微信 pc 公衆號(微信內瀏覽器)支付 實現 (h5調用 微信 還沒實現 )

微信:linweikun8023 歡迎諮詢 記得備註

package cn.com.yyg.front.utils;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.qq.connect.utils.json.JSONObject;

public class WeixinAccessToken {
	private static Logger logger = LoggerFactory.getLogger(WeixinAccessToken.class);
	public static String getAccessToken() {
		String access_token = ""; // 有效期爲7200秒
		String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + WeixinUtils.app_ID + "&secret=" + WeixinUtils.app_Secret;
		try {
			URL urlGet = new URL(url);
			HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
			http.setRequestMethod("GET"); // 必須是get方式請求
			http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			http.setDoOutput(true);
			http.setDoInput(true);
			System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 鏈接超時30秒
			System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 讀取超時30秒
			http.connect();
			InputStream is = http.getInputStream();
			int size = is.available();
			byte[] jsonBytes = new byte[size];
			is.read(jsonBytes);
			String message = new String(jsonBytes, "UTF-8");
			JSONObject demoJson = new JSONObject(message);
			access_token = demoJson.getString("access_token");
			logger.info("access_token"+access_token);
			System.out.println("access_token"+access_token);
			is.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return access_token;
	}

}




package cn.com.yyg.front.utils;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;

public class WeixinSign {
	public static void main(String[] args) {
		String jsapi_ticket = "jsapi_ticket";

		// 注意 URL 必定要動態獲取,不能 hardcode
		String url = "http://example.com";
		Map<String, String> ret = sign(jsapi_ticket, url);
		for (Map.Entry entry : ret.entrySet()) {
			System.out.println(entry.getKey() + ", " + entry.getValue());

		}
	};

	public static Map<String, String> sign(String jsapi_ticket, String url) {
		Map<String, String> ret = new HashMap<String, String>();
		String nonce_str = create_nonce_str();
		String timestamp = create_timestamp();
		String string1;
		String signature = "";

		// 注意這裏參數名必須所有小寫,且必須有序
		string1 = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonce_str + "&timestamp=" + timestamp + "&url=" + url;
		// System.out.println(string1);

		try {
			MessageDigest crypt = MessageDigest.getInstance("SHA-1");
			crypt.reset();
			crypt.update(string1.getBytes("UTF-8"));
			signature = byteToHex(crypt.digest());
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		ret.put("url", url);
		ret.put("jsapi_ticket", jsapi_ticket);
		ret.put("nonceStr", nonce_str);
		ret.put("timestamp", timestamp);
		ret.put("signature", signature);

		return ret;
	}

	private static String byteToHex(final byte[] hash) {
		Formatter formatter = new Formatter();
		for (byte b : hash) {
			formatter.format("%02x", b);
		}
		String result = formatter.toString();
		formatter.close();
		return result;
	}

	public static String create_nonce_str() {
		return UUID.randomUUID().toString();
	}

	public static String create_32nonce_str() {
		return StringUtils.substring(UUID.randomUUID().toString(), 1, 32);
	}

	public static String create_timestamp() {
		return Long.toString(System.currentTimeMillis() / 1000);
	}
}



package cn.com.yyg.front.utils;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.com.yyg.front.web.wap.controller.WapWxPayController;

import com.qq.connect.utils.json.JSONObject;

public class WeixinTicket {
	private static Logger logger = LoggerFactory.getLogger(WeixinTicket.class);
	public static String getTicket() {
		String ticket = null;
		String access_token = WeixinUtils.getAccessToken(); // 有效期爲7200秒
		String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + access_token + "&type=jsapi";
		try {
			URL urlGet = new URL(url);
			HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
			http.setRequestMethod("GET"); // 必須是get方式請求
			http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			http.setDoOutput(true);
			http.setDoInput(true);
			System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 鏈接超時30秒
			System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 讀取超時30秒
			http.connect();
			InputStream is = http.getInputStream();
			int size = is.available();
			byte[] jsonBytes = new byte[size];
			is.read(jsonBytes);
			String message = new String(jsonBytes, "UTF-8");
			JSONObject demoJson = new JSONObject(message);
			ticket = demoJson.getString("ticket");
			logger.info("ticket="+ticket);
			System.out.println("ticket="+ticket);
			is.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return ticket;
	}
}




package cn.com.yyg.front.utils;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ui.ModelMap;

import cn.com.easy.utils.HttpUtils;
import cn.com.yyg.front.dto.WeixinDto;

import com.github.sd4324530.fastweixin.exception.WeixinException;
import com.qq.connect.utils.json.JSONException;
import com.qq.connect.utils.json.JSONObject;

public class WeixinUtils {

	// https://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html
	private static Logger logger = LoggerFactory.getLogger(WeixinUtils.class);
	public static String app_ID = "";
	public static String app_Secret = "";
	public static String domailString = "http://5555";

	/**
	 * 獲取code 訪問到主頁 判斷獲取到code 再去獲取用戶accessToken
	 * 
	 * @author linwk 2016年10月13日
	 */
	public static String getCode() {
		String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + app_ID + "&redirect_uri=" + domailString
				+ "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
		return "redirect:" + url;
	}

	/**
	 * 獲取用戶openId 用戶accessToken
	 * 
	 * @return
	 * @author linwk 2016年10月13日
	 * @throws Exception
	 */
	public static String getOpenIdAndAccessToken(String code) throws Exception {
		try {
			logger.info("code=" + code);
			String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + app_ID + "&secret=" + app_Secret + "&code=" + code + "&grant_type=authorization_code";
			String accrssString = HttpUtils.doGet(url);
			logger.info("access_token=" + accrssString);
			return accrssString;
		} catch (WeixinException e) {
			logger.info("code=" + code);
			String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + app_ID + "&secret=" + app_Secret + "&code=" + code + "&grant_type=authorization_code";
			String accrssString = HttpUtils.doGet(url);
			logger.info("access_token=" + accrssString);
			return accrssString;
		}
	}

	/**
	 * 獲取用戶openId 用戶accessToken
	 * 
	 * @return
	 * @author linwk 2016年10月13日
	 * @throws Exception
	 */
	public static String getUserInfo(String openid, String access_token) throws Exception {
		try {
			logger.info("openid=" + openid + "*************************** access_token=" + access_token);
			String url = "https://api.weixin.qq.com/sns/userinfo?access_token=" + access_token + "&openid=" + openid + "&lang=zh_CN";
			String UserInfo = HttpUtils.doGet(url);
			logger.info("UserInfo=" + UserInfo);
			return UserInfo;
		} catch (WeixinException e) {
			logger.info("openid=" + openid + "*************************** access_token=" + access_token);
			String url = "https://api.weixin.qq.com/sns/userinfo?access_token=" + access_token + "&openid=" + openid + "&lang=zh_CN";
			String UserInfo = HttpUtils.doGet(url);
			logger.info("UserInfo=" + UserInfo);
			return UserInfo;
		}
	}

	/**
	 * 微信登陸驗證
	 * 
	 * @param request
	 * @param response
	 * @author linwk 2016年6月15日
	 * @throws Exception
	 */
	public static WeixinDto doPost(HttpServletRequest request, HttpServletResponse response, String code) throws Exception {
		try {
			response.setContentType("text/html; charset=utf-8");
			// 獲取用戶openId 用戶accessToken
			String accrssString = getOpenIdAndAccessToken(code);
			if (StringUtils.isNoneBlank(accrssString)) {
				logger.info("獲取***************************openid*************************************信息成功");
				JSONObject demoJson = new JSONObject(accrssString);
				String openid = getJsonName(demoJson, "openid");
				String access_token = getJsonName(demoJson, "access_token");
				String UserInfo = getUserInfo(openid, access_token);
				if (StringUtils.isNoneBlank(UserInfo)) {
					logger.info("獲取***************************openid*************************************信息成功");
					JSONObject UserInfoJson = new JSONObject(UserInfo);
					String nickname = getJsonName(UserInfoJson, "nickname");
					String sex = getJsonName(UserInfoJson, "sex");
					String headimgurl = getJsonName(UserInfoJson, "headimgurl");
					WeixinDto weixin = new WeixinDto(openid, nickname, sex, headimgurl);
					return weixin;
				}
			}
		} catch (WeixinException e) {
		}
		return null;

	}

	private static String getJsonName(JSONObject demoJson, String tString) throws JSONException {
		return demoJson.getString(tString);
	}

	/**
	 * 微信瀏覽器判讀
	 * 
	 * @param req
	 * @author linwk 2016年10月17日
	 * @param modelMap
	 */
	public static void extracted(HttpServletRequest request) {
		String ua = ((HttpServletRequest) request).getHeader("user-agent").toLowerCase();
		if (ua.indexOf("micromessenger") > 0) {// 是微信瀏覽器
			// [微信登陸腳本]
			request.getSession().setAttribute("isWeixinBrowerisWeixinBrower", true);
			request.getSession().setAttribute("isWeixinBrower", true);
			request.getSession().setAttribute("appId", WeixinUtils.app_ID);
			String jsapi_ticket = WeixinUtils.getTicket();
			// 注意 URL 必定要動態獲取,不能 hardcode
			String url = RequestUtils.getUrl(request);
			Map<String, String> ret = WeixinSign.sign(jsapi_ticket, url);
			for (@SuppressWarnings("rawtypes")
			Map.Entry entry : ret.entrySet()) {
				request.getSession().setAttribute(entry.getKey().toString(), entry.getValue());
			}
		}
	}

	/**
	 * get accessToken
	 * 
	 * @return
	 * @author linwk 2016年10月13日
	 */
	public static String getAccessToken() {
		if (StringUtils.isBlank(System.getProperty("accessToken"))) {
			System.setProperty("accessToken", WeixinAccessToken.getAccessToken());
		}
		return System.getProperty("accessToken");
	}

	/**
	 * set accessToken
	 * 
	 * @param accessToken
	 * @author linwk 2016年10月13日
	 */
	public static void setAccessToken(String accessToken) {
		System.setProperty("accessToken", accessToken);
	}

	/**
	 * get ticket
	 * 
	 * @return
	 * @author linwk 2016年10月13日
	 */
	public static String getTicket() {
		if (StringUtils.isBlank(System.getProperty("ticket"))) {
			System.setProperty("ticket", WeixinTicket.getTicket());
		}
		return System.getProperty("ticket");
	}

	/**
	 * set ticket
	 * 
	 * @param ticket
	 * @author linwk 2016年10月13日
	 */
	public static void setTicket(String ticket) {
		System.setProperty("ticket", ticket);
	}
}




package cn.com.yyg.pay.util;

import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.commons.codec.digest.DigestUtils;

import cn.com.yyg.front.utils.WeixinSign;
import cn.com.yyg.front.utils.WeixinUtils;
import cn.com.yyg.pay.wxpay.sdk.HttpUtil;
import cn.com.yyg.pay.wxpay.sdk.MD5Util;
import cn.com.yyg.pay.wxpay.sdk.XMLUtil;

/**
 * 微信支付
 * 
 * @author lvzf 2016年9月28日
 * 
 */
public class WxPayUtil {
	static String UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";

	/**
	 * 生成h5支付鏈接
	 * 
	 * @param appId
	 * @param appKey
	 * @param merId
	 * @param orderId
	 * @param amount
	 * @param notifyUrl
	 * @param ip
	 * @return
	 * @throws Exception
	 * @author linwk 2016年10月10日
	 * @param openId
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static Map getWeixinPayMap(String appId, String appKey, String merId, String orderId, String amount, String notifyUrl, String ip, String openId, String timeStamp)
			throws Exception {
		// String appsecret = PayConfigUtil.APP_SECRET; // appsecret
		String currTime = getCurrTime();
		String strTime = currTime.substring(8, currTime.length());
		String strRandom = buildRandom(4) + "";
		String nonce_str = strTime + strRandom;
		// 價格 注意:價格的單位是分
		amount = String.valueOf((long) (Double.parseDouble(amount) * 100));
		String body = "商品名稱"; // 商品名稱
		String trade_type = "JSAPI";
		SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
		packageParams.put("appid", appId);
		packageParams.put("mch_id", merId);
		packageParams.put("nonce_str", nonce_str);
		packageParams.put("body", body);
		packageParams.put("device_info", "WEB");
		if (openId != null) {
			packageParams.put("openid", openId);
		}
		packageParams.put("product_id", orderId);
		// 訂單號
		packageParams.put("out_trade_no", orderId);
		packageParams.put("total_fee", amount);
		// 獲取發起電腦 ip
		packageParams.put("spbill_create_ip", ip);
		// 回調接口
		packageParams.put("notify_url", notifyUrl);
		packageParams.put("trade_type", trade_type);
		String sign = createSign("UTF-8", packageParams, appKey);
		packageParams.put("sign", sign);
		String requestXML = getRequestXml(packageParams);
		System.out.println("請求:" + requestXML);
		String resXml = HttpUtil.postData(UFDODER_URL, requestXML);
		System.out.println("響應:" + resXml);
		Map map = XMLUtil.doXMLParse(resXml);

		SortedMap<Object, Object> packagePayParams = new TreeMap<Object, Object>();
		packagePayParams.put("appId", appId);
		packagePayParams.put("timeStamp", timeStamp);
		packagePayParams.put("nonceStr", (String) map.get("nonce_str"));
		packagePayParams.put("package", "prepay_id=" + (String) map.get("prepay_id"));
		packagePayParams.put("signType", "MD5");
		// 再次簽名
		String paySign = createSign("UTF-8", packagePayParams, appKey);
		map.put("paySign", paySign);
		//map.put("nonceStr", (String) map.get("nonce_str"));
		return map;
	}

	/**
	 * 生成支付二維碼
	 * 
	 * @param appId
	 * @param appKey
	 * @param merId
	 *            商戶號
	 * @param orderId
	 *            訂單號
	 * @param amount
	 *            金額(元)
	 * @param notifyUrl
	 * @param ip
	 * @return
	 * @throws Exception
	 * @author lvzf 2016年9月26日
	 */
	public static String createQrcode(String appId, String appKey, String merId, String orderId, String amount, String notifyUrl, String ip) throws Exception {
		// String appsecret = PayConfigUtil.APP_SECRET; // appsecret

		String currTime = getCurrTime();
		String strTime = currTime.substring(8, currTime.length());
		String strRandom = buildRandom(4) + "";
		String nonce_str = strTime + strRandom;
		// 價格 注意:價格的單位是分
		amount = String.valueOf((long) (Double.parseDouble(amount) * 100));
		String body = "掃描付款"; // 商品名稱

		String trade_type = "NATIVE";

		SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
		packageParams.put("appid", appId);
		packageParams.put("mch_id", merId);
		packageParams.put("nonce_str", nonce_str);
		packageParams.put("body", body);
		packageParams.put("device_info", "web");
		packageParams.put("product_id", orderId);

		// 訂單號
		packageParams.put("out_trade_no", orderId);
		packageParams.put("total_fee", amount);
		// 獲取發起電腦 ip
		packageParams.put("spbill_create_ip", ip);
		// 回調接口
		packageParams.put("notify_url", notifyUrl);
		packageParams.put("trade_type", trade_type);

		String sign = createSign("UTF-8", packageParams, appKey);
		packageParams.put("sign", sign);

		String requestXML = getRequestXml(packageParams);
		System.out.println("請求:" + requestXML);

		String resXml = HttpUtil.postData(UFDODER_URL, requestXML);
		System.out.println("響應:" + resXml);
		@SuppressWarnings("rawtypes")
		Map map = XMLUtil.doXMLParse(resXml);
		@SuppressWarnings("unused")
		String return_code = (String) map.get("return_code");
		String prepay_id = (String) map.get("prepay_id");
		@SuppressWarnings("unused")
		String urlCode = (String) map.get("code_url");
		sign = (String) map.get("sign");
		return urlCode;

	}

	/**
	 * 是否簽名正確,規則是:按參數名稱a-z排序,遇到空值的參數不參加簽名。
	 * 
	 * @return boolean
	 */
	@SuppressWarnings("rawtypes")
	public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {
		StringBuffer sb = new StringBuffer();
		Set es = packageParams.entrySet();
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			if (!"sign".equals(k) && null != v && !"".equals(v)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + API_KEY);

		// 算出摘要
		String mysign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase();
		String tenpaySign = ((String) packageParams.get("sign")).toLowerCase();

		// System.out.println(tenpaySign + "    " + mysign);
		return tenpaySign.equals(mysign);
	}

	/**
	 * 
	 * @param map
	 * @return
	 * @author linwk 2016年10月18日
	 */
	private static String getSign(Map<String, String> map) {
		StringBuffer sb = new StringBuffer();
		@SuppressWarnings("rawtypes")
		Set es = map.entrySet();// 全部參與傳參的參數按照accsii排序(升序)
		@SuppressWarnings("rawtypes")
		Iterator it = es.iterator();
		while (it.hasNext()) {
			@SuppressWarnings("rawtypes")
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			Object v = entry.getValue();
			if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		// 你在公衆號內設置的密鑰
		sb.append("key=" + WeixinUtils.app_Secret);
		// MD5加密方法,文章後面會提供工具類下載
		String sign = DigestUtils.md5Hex(getContentBytes(sb.toString(), "UTF-8")).toUpperCase();
		return sign;
	}

	/**
	 * @author
	 * @date 2016-4-22
	 * @Description:sign簽名
	 * @param characterEncoding
	 *            編碼格式
	 * @param parameters
	 *            請求參數
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {
		StringBuffer sb = new StringBuffer();
		Set es = packageParams.entrySet();
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + API_KEY);
		// String sign = MD5Util.MD5Encode(sb.toString(),
		// characterEncoding).toUpperCase();
		String sign = DigestUtils.md5Hex(getContentBytes(sb.toString(), characterEncoding)).toUpperCase();
		return sign;
	}

	private static byte[] getContentBytes(String content, String charset) {
		if (charset == null || "".equals(charset)) {
			return content.getBytes();
		}
		try {
			return content.getBytes(charset);
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException("MD5簽名過程當中出現錯誤,指定的編碼集不對,您目前指定的編碼集是:" + charset);
		}
	}

	/**
	 * @author
	 * @date 2016-4-22
	 * @Description:將請求參數轉換爲xml格式的string
	 * @param parameters
	 *            請求參數
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public static String getRequestXml(SortedMap<Object, Object> parameters) {
		StringBuffer sb = new StringBuffer();
		sb.append("<xml>");
		Set es = parameters.entrySet();
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			// if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) ||
			// "sign".equalsIgnoreCase(k)) {
			if ("attach".equalsIgnoreCase(k)) {
				sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
			} else {
				sb.append("<" + k + ">" + v + "</" + k + ">");
			}
		}
		sb.append("</xml>");
		return sb.toString();
	}

	/**
	 * 取出一個指定長度大小的隨機正整數.
	 * 
	 * @param length
	 *            int 設定所取出隨機數的長度。length小於11
	 * @return int 返回生成的隨機數。
	 */
	public static int buildRandom(int length) {
		int num = 1;
		double random = Math.random();
		if (random < 0.1) {
			random = random + 0.1;
		}
		for (int i = 0; i < length; i++) {
			num = num * 10;
		}
		return (int) ((random * num));
	}

	/**
	 * 獲取當前時間 yyyyMMddHHmmss
	 * 
	 * @return String
	 */
	public static String getCurrTime() {
		Date now = new Date();
		SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");
		String s = outFormat.format(now);
		return s;
	}

	public static void main(String[] args) {
		String merId = "1388261002";
		String appId = "wxe913ec262d781dca";
		String appKey = "c80f86302e55cdbcb6fae727991ff4c6";
		String orderId = "" + System.currentTimeMillis();
		String amount = "0.02";
		String openId = "oPgBSwL8NcYm5XdZH3rBSxClYUzY";
		try {
			// String url = WxPayUtil.createQrcode(appId, appKey, merId,
			// orderId, amount, "http://www.qibao99.com/wxPay/smBack/",
			// "123.12.12.123");
			// System.out.println("url=" + url);
			// QRCodeImgUtils.createImg(url, 300, 300, "D:/newPic.jpg");
			@SuppressWarnings("unchecked")
			Map<String, String> map = WxPayUtil.getWeixinPayMap(appId, appKey, merId, orderId, amount, "http://www.qibao99.com/wxPay/smBack/", "123.12.12.123", openId,
					WeixinSign.create_timestamp());
			for (@SuppressWarnings("rawtypes")
			Map.Entry entry : map.entrySet()) {
				System.out.println("key:" + entry.getKey().toString() + ",value:" + entry.getValue());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}




package cn.com.yyg.front.web.wap.controller;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

import cn.com.easy.exception.BusinessException;
import cn.com.easy.utils.FastJSONUtils;
import cn.com.easy.utils.IPUtils;
import cn.com.yyg.base.entity.PayRecordEntity;
import cn.com.yyg.base.entity.UserEntity;
import cn.com.yyg.front.dao.UserDao;
import cn.com.yyg.front.service.PayService;
import cn.com.yyg.front.service.YgBuyService;
import cn.com.yyg.front.utils.RequestUtils;
import cn.com.yyg.front.utils.WeixinSign;
import cn.com.yyg.pay.util.WxPayUtil;
import cn.com.yyg.pay.wxpay.sdk.XMLUtil;

/**
 * 微信掃描支付
 * 
 * @author lvzf 2016年8月30日
 * 
 */
@Controller
@RequestMapping("/wap/wxPay")
public class WapWxPayController {

	private Logger logger = LoggerFactory.getLogger(WapWxPayController.class);
	@Autowired
	private UserDao userDao;
	@Autowired
	private YgBuyService ygBuyService;
	@Autowired
	private PayService payService;
	// 商戶號
	String merId = "";
	// 應用id
	String appId = "";
	// 應用祕鑰
	String appKey = "";

	/**
	 * 微信支付頁面
	 * 
	 * @param modelMap
	 * @param req
	 * @param res
	 * @param payNo
	 * @return
	 * @author linwk 2016年10月17日
	 */
	@RequestMapping
	public String pay(ModelMap modelMap, HttpServletRequest req, HttpServletResponse res, String payNo) {
		// 參數設置
		try {
			req.getSession().setAttribute("isWeixinBrowerisWeixinBrower", false);
			req.getSession().setAttribute("isWeixinBrower", false);

			PayRecordEntity pay = payService.getPayByPayNo(payNo);
			if (pay == null || pay.getPayStatus() != PayRecordEntity.PAY_STATUS_INIT) {
				throw new BusinessException("該訂單已經支付或取消");
			}
			String payAmount = pay.getAmount().toString();
			if (NumberUtils.isNumber(payAmount) == false) {
				throw new BusinessException("請輸入數字");
			}
			if (Double.parseDouble(payAmount) < 0.01) {
				throw new BusinessException("金額大於0.01元");
			}
			String orderId = payNo;

			String serverPort = "";
			if (req.getServerPort() != 80) {
				serverPort = ":" + req.getServerPort();
			}
			String contextPath = req.getContextPath();
			if (contextPath == "/") {
				contextPath = "";
			}
			String path = req.getScheme() + "://" + req.getServerName() + serverPort + contextPath;
			String backUrl = path + "wap/wxPay/backResponse/";
			String ip = IPUtils.getRealIP(req);

			// 用戶openId
			UserEntity user = userDao.findOne(RequestUtils.getCurrentUser(req).getId());
			if (user.getWeixinOpenId() == null) {
				// 能夠不須要
				throw new BusinessException("請使用微信帳號登陸");
			}
			String timeStamp = WeixinSign.create_timestamp();
			modelMap.addAttribute("appId", appId);
			modelMap.addAttribute("timeStamp", timeStamp);
			@SuppressWarnings("unchecked")
			Map<String, String> map = WxPayUtil.getWeixinPayMap(appId, appKey, merId, orderId, payAmount, backUrl, ip, user.getWeixinOpenId(),timeStamp);
			for (@SuppressWarnings("rawtypes")
			Map.Entry entry : map.entrySet()) {
				modelMap.addAttribute(entry.getKey().toString(), entry.getValue());
				logger.info(entry.getKey().toString(), entry.getValue());
			}
			if (StringUtils.contains((String) map.get("return_code"), "FAIL")) {
				throw new BusinessException((String) map.get("return_msg"));
			}

			return "/wap/buy/weixinpay_result";
		} catch (BusinessException ex) {
			modelMap.addAttribute("message", ex.getMessage());
		} catch (Exception ex) {
			modelMap.addAttribute("message", "系統錯誤");
		}
		return "/wap/buy/pay_error";
	}

	/**
	 * 支付結果
	 * 
	 * @param modelMap
	 * @param req
	 * @param res
	 * @return
	 * @author lvzf 2016年10月8日
	 */
	@RequestMapping("/qrcodePaySuccess")
	public String qrcodePaySuccess(ModelMap modelMap, HttpServletRequest req, HttpServletResponse res, String payNo) {
		PayRecordEntity pay = payService.getPayByPayNo(payNo);
		if (pay != null && pay.getPayStatus() == PayRecordEntity.PAY_STATUS_SUCCESS) {
			return "/wap/buy/pay_result";
		}
		return "/wap/buy/pay_error";
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@RequestMapping("/backResponse")
	public void weixin_notify(HttpServletRequest request, HttpServletResponse response) throws Exception {

		// 讀取參數
		InputStream inputStream;
		StringBuffer sb = new StringBuffer();
		inputStream = request.getInputStream();
		String s;
		BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
		while ((s = in.readLine()) != null) {
			sb.append(s);
		}
		in.close();
		inputStream.close();

		// 解析xml成map
		Map<String, String> m = new HashMap<String, String>();
		m = XMLUtil.doXMLParse(sb.toString());

		// 過濾空 設置 TreeMap
		SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
		Iterator it = m.keySet().iterator();
		while (it.hasNext()) {
			String parameter = (String) it.next();
			String parameterValue = m.get(parameter);

			String v = "";
			if (null != parameterValue) {
				v = parameterValue.trim();
			}
			packageParams.put(parameter, v);
		}

		logger.info(FastJSONUtils.toJsonString(packageParams));

		// 判斷簽名是否正確
		if (WxPayUtil.isTenpaySign("UTF-8", packageParams, appKey)) {
			// ------------------------------
			// 處理業務開始
			// ------------------------------
			String resXml = "";
			if ("SUCCESS".equals((String) packageParams.get("result_code"))) {
				// 這裏是支付成功
				// ////////執行本身的業務邏輯////////////////
				String mch_id = (String) packageParams.get("mch_id");
				String openid = (String) packageParams.get("openid");
				String is_subscribe = (String) packageParams.get("is_subscribe");
				String out_trade_no = (String) packageParams.get("out_trade_no");
				String trade_no = request.getParameter("trade_no");
				String trade_status = request.getParameter("result_code");

				String total_fee = (String) packageParams.get("total_fee");

				logger.info("mch_id:" + mch_id);
				logger.info("openid:" + openid);
				logger.info("is_subscribe:" + is_subscribe);
				logger.info("out_trade_no:" + out_trade_no);
				logger.info("total_fee:" + total_fee);

				// ////////執行本身的業務邏輯////////////////

				logger.info("支付成功");
				// 通知微信.異步確認成功.必寫.否則會一直通知後臺.八次以後就認爲交易失敗了.
				resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
				PayRecordEntity pay = payService.getPayByPayNo(out_trade_no);
				if (pay != null && pay.getPayStatus() != PayRecordEntity.PAY_STATUS_SUCCESS) {
					pay.setPayStatus(PayRecordEntity.PAY_STATUS_SUCCESS);// 付款
					// pay.setThirdPayTime(DateUtil.getStringToDate(notify_time,
					// DateUtil.YMDhhmmss));
					pay.setThirdPayTime(new Date());
					pay.setThirdTradeNo(trade_no);
					pay.setThirdTradeStatus(trade_status);
					// 生成中獎號碼
					UserEntity user = userDao.findOne(pay.getUserId());
					ygBuyService.createWinNo(user, pay);
				}
			} else {
				logger.info("支付失敗,錯誤信息:" + packageParams.get("err_code"));
				resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[報文爲空]]></return_msg>" + "</xml> ";
			}
			// ------------------------------
			// 處理業務完畢
			// ------------------------------
			BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
			out.write(resXml.getBytes());
			out.flush();
			out.close();
		} else {
			logger.info("通知簽名驗證失敗");
		}

	}
}