微信公衆號第三方網站在微信瀏覽器中支付搞了三天,真的是太多坑,作個記錄備用

1.支付頁面代碼,我是用把OPENID存入SESSION中的方式,因此有個wxOauth2Urljavascript

<input type="hidden" id="wxOpenId" value="${wxOpenId}"> 
<input type="hidden" id="wxOauth2Url" value="${wxOauth2Url}">
<a class="item" id="weixin"> <img src="/static/app/member/images/pay_w.png" class="pay_img" alt="" />

2.支付頁面JS調用html

var wxH5 = isweixin();
if (wxH5) {
    //alert("當前爲微信訪問");
    var appId = "";
    var timeStamp = "";
    var nonceStr = "";
    var prepay = "";
    var signType = "";
    var paySign = "";
    var wxOpenId = $("#wxOpenId").val();
    var wxOauth2Url = $("#wxOauth2Url").val();

    //如何沒有獲取到OPENID
    if (wxOpenId == '') {
        window.location.href = wxOauth2Url; //若沒有OPENID 調用CODE獲取OPENID
        //wxOauth2Url中有個參數state,我把這個參數設定爲訂單ID以便獲取到OPENID後返回到訂單支付頁
        //alert("開始獲取用戶OPENID");
    } else {
        //alert("開始提交wxh5pay.do");
        $.ajax({
            url: '/appApi/pay/wxh5pay.do',
            type: 'POST',
            data: {
                state: state
            },
            cache: false,
            async: false,
            dataType: 'JSON',
            timeout: 5000,
            error: function(textStatus) {
                alert('系統錯誤~');
            },
            success: function(data) {
                if (data != null) {
                    alert(data.wxh5Data.prepay);
                    appId = data.wxh5Data.appId;
                    timeStamp = data.wxh5Data.timeStamp;
                    nonceStr = data.wxh5Data.nonceStr;
                    prepay = data.wxh5Data.prepay;
                    signType = data.wxh5Data.signType;
                    paySign = data.wxh5Data.paySign;
                }
            }
        });

        // 喚起微信支付
        if (appId != '') {
            pay();
        }

        // 喚起微信支付
        function pay() {

            //alert("pay JS 啓動");
            if (typeof WeixinJSBridge == "undefined") {
                if (document.addEventListener) {
                    document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
                } else if (document.attachEvent) {
                    document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
                    document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
                }
            } else {
                onBridgeReady();
            }

        }

        // 開始支付
        function onBridgeReady() {
            //alert("onBridgeReady JS 啓動");
            WeixinJSBridge.invoke('getBrandWCPayRequest', {
                "appId": appId,
                // 公衆號名稱,由商戶傳入
                "timeStamp": timeStamp + "",
                // 時間戳,自1970年以來的秒數
                "nonceStr": nonceStr,
                // 隨機串
                "package": "prepay_id=" + prepay,
                "signType": signType,
                // 微信簽名方式:
                "paySign": paySign

                // 微信簽名
            },

            function(res) {
                if (res.err_msg == "get_brand_wcpay_request:ok") {
                    alert("支付成功"); // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功後返回
                    // ok,但並不保證它絕對可靠。
                    // 回到用戶訂單列表
                    window.location.href = "/m/member/dingdan_list.html";
                } else if (res.err_msg == "get_brand_wcpay_request:cancel") {
                    alert("支付過程當中用戶取消");
                } else {
                    // 支付失敗
                    alert(res.err_msg)
                }
            });
        }

    }

}

/* 判斷是否是微信瀏覽器 */
function isweixin() {
    var ua = navigator.userAgent.toLowerCase();
    if (ua.match(/MicroMessenger/i) == "micromessenger") {
        return true;
    } else {
        return false;
    }
}

3.訂單支付頁控制器,這裏體驗可能不要很好,沒有獲取到OPENID時可能要點2次,後期獲取SESSION能夠考慮在其餘地方作。前端

// 判斷是否爲微信瀏覽器
Boolean validation = false;
String ua = request.getHeader("user-agent").toLowerCase();
if (ua.indexOf("micromessenger") > 0) {// 是微信瀏覽器
     validation = true;
      // 讀取用戶的OPENID到SESSION中
       String wxOpenId = (String) userHelper.getOpenId();
       request.setAttribute("wxOpenId", wxOpenId);
         if (wxOpenId == null) {
	 String redirect_uri = WxPayUtil.urlEnodeUTF8(WxPayConfig.REDIRECT_URI);
	// 從新寫稿到SESSION中
	String wxOauth2Url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + WxPayConfig.APPID + "&redirect_uri=" + redirect_uri + "&response_type=code&scope=snsapi_base&state="+number+"#wechat_redirect";
    //redirect_uri 此參數要結合公衆號平臺設置,number這裏是訂單號
request.setAttribute("wxOauth2Url", wxOauth2Url);
	System.out.println("wxOauth2Url:"+wxOauth2Url);
	}
}
request.setAttribute("validation", validation);

4.調用wxOauth2Url 獲取CODE的返回接收URL,在這裏作了寫入OPENID到SEEION和從新返回到支付頁面。java

package com.szqws.nanhaibiz.controller.app;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.szqws.nanhaibiz.bean.base.UserHelper;
import com.szqws.nanhaibiz.constants.WxPayConfig;
import com.szqws.nanhaibiz.controller.system.BaseController;
import com.szqws.nanhaibiz.util.system.WxPayUtil;

@Controller
@RequestMapping(value = "/mp")
public class AppWXCodeController extends BaseController {

	private static final Logger logger = LoggerFactory.getLogger(AppWXCodeController.class);

	@Resource
	UserHelper userHelper;

	/**
	 * 獲取OPENID 且寫入SESSION
	 * 
	 * @param code
	 * @return
	 */

	@RequestMapping(value = "/get_code.do", method = { RequestMethod.GET })
	public String WXPayCode(String code, String state) {
		try {
			String openid = WxPayUtil.getOpenId(WxPayConfig.APPID, WxPayConfig.APPSECRET, code);
			userHelper.putOpenId(openid);
			System.out.println("openid:" + openid);
		} catch (Exception e) {
			logger.debug("獲取OPENID--異常", e);
		}

		return "redirect:/m/member/pay/detail_" + state + ".html";
	}

}

5.完成統一下訂單API,node

// 統一下單支付(Wap支付)
	public static String appPayH5(WxPaySendData data, String key) {
		String returnXml = null;
		try {

	// 生成sign簽名
	SortedMap<String, Object> parameters = new TreeMap<String, Object>();
	parameters.put("appid", data.getAppid());
	parameters.put("attach", data.getAttach());
	parameters.put("body", data.getBody());
	parameters.put("mch_id", data.getMch_id());
	parameters.put("nonce_str", data.getNonce_str());
	parameters.put("notify_url", data.getNotify_url());
	parameters.put("out_trade_no", data.getOut_trade_no());
	parameters.put("fee_type", data.getFee_type());
	parameters.put("total_fee", data.getTotal_fee());
	parameters.put("trade_type", data.getTrade_type());
	parameters.put("spbill_create_ip", data.getSpbill_create_ip());
	parameters.put("device_info", data.getDevice_info());
	parameters.put("openid", data.getOpenid()); //這裏是個坑必定要OPENID,掃描支付是不要的
	data.setSign(createSign(parameters, key));

	XStream xs = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_")));
	xs.alias("xml", WxPaySendData.class);
	String xml = xs.toXML(data);

	logger.info("統一下單xml爲:\n" + xml);
	returnXml = HttpClientHelper.sendPostRequestXml("https://api.mch.weixin.qq.com/pay/unifiedorder", xml);
	logger.info("返回結果:" + returnXml);

		} catch (Exception e) {
			logger.debug("微信支付--統一下單--異常:{}", e);
		}
		return returnXml;
	}

正確返回數據應該如圖web

6.WXH5Pay APIajax

/**
	 * 支付執行
	 * 
	 * @param state
	 * @return
	 */
	@RequestMapping(value = "/wxh5pay.do", method = { RequestMethod.GET, RequestMethod.POST })
	@ResponseBody
	public Object WXH5pay(String state) {
		String msg = "";
		try {
			// 分離出訂單號
			JSONObject json = JSON.parseObject(state);
			String rechargeId = json.getString("order_number");
			double payPrice = 0.00;
			String number = null;

			// 獲取用戶和訂單
			User iUser = (User) userHelper.get();
			if (iUser == null) {
				logger.debug("未登錄用戶!");
				return null;
			}

			Order recharge = orderService.getByNumber(rechargeId);
			if (recharge == null) {
				return null;
			} else {
		payPrice = recharge.getAmount();
		// payPrice = 0.01;
		number = MyUIDD.getAtomicCounter();
		// 更改訂單狀態
		Order tmpOrder = new Order();
		tmpOrder.setStatus("NOTPAY");
		tmpOrder.setId(recharge.getId());
		tmpOrder.setNumber(number);
		orderService.update(tmpOrder);
		
		// 第一步提交微信統一下單接口
		// 1.準備數據
		WxPaySendData data = new WxPaySendData();
		String nonceStr = new WxPayUtil().getNonceStr();
		data.setAppid(WxPayConfig.APPID);
		data.setAttach("訂單支付");
		data.setBody("訂單金額" + payPrice + "元");
		data.setMch_id(WxPayConfig.MCHID);
		data.setNonce_str(nonceStr);
		data.setNotify_url(WxPayConfig.NOTIFY_URL);
		data.setOut_trade_no(number);
		data.setTotal_fee((int) (payPrice * 100));
		data.setFee_type("CNY");
		data.setSpbill_create_ip("113.110.254.178");
		data.setTrade_type("JSAPI");
		data.setDevice_info("WXH5");
		data.setOpenid((String)userHelper.getOpenId());
		
		// 2.提交請求
		msg = new WxPayUtil().appPayH5(data, WxPayConfig.KEY);
		
		// 3.分析返回數據
		WxPayReturnData reData = new WxPayReturnData();
		XStream xs1 = new XStream(new DomDriver());
		xs1.alias("xml", WxPayReturnData.class);
		reData = (WxPayReturnData) xs1.fromXML(msg);
		
		// 第二步 準備JSP數據
		String timestamp = String.valueOf(new Date().getTime() / 1000);
		Map<String, Object> wxh5Data = new HashMap<String, Object>();
		wxh5Data.put("appId", WxPayConfig.APPID);
		wxh5Data.put("timeStamp", timestamp);
		wxh5Data.put("signType", "MD5");
		wxh5Data.put("nonceStr", nonceStr);
		wxh5Data.put("package", "prepay_id="+reData.getPrepay_id()); //這個prepay_id必須是統一下單返回的又是一大坑,不少人可能用訂單號來生成。
		
		// 參數開始生成簽名
		SortedMap<String, Object> parameters = new TreeMap<String, Object>();
		parameters.put("appId", WxPayConfig.APPID);
		parameters.put("timeStamp", timestamp);
		parameters.put("signType", "MD5");
		parameters.put("nonceStr", nonceStr);
		parameters.put("package", "prepay_id="+reData.getPrepay_id());
		String paySign = WxPayUtil.createSign(parameters, WxPayConfig.KEY);
		// 簽名結束
		wxh5Data.put("paySign", paySign);
		wxh5Data.put("prepay", reData.getPrepay_id()); 
		
		// 返回數據
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("wxh5Data", wxh5Data);
		map.put("reData", reData);
		map.put("state", state);
		map.put("orderId", number);
		return map;
			}
		} catch (Exception e) {
			logger.debug("付款操做異常:AppPayAPI.WXH5pay()", e);
			return null;
		}

	}

 

注意點:spring

// 獲取code重定向路徑
public static final String REDIRECT_URI = "http://www.XXXX.com/mp/get_code.do";json

此項值須要在公衆號平臺客戶設置 網頁http://www.XXXX.com/mp/api

這裏有個問題 MP_verify_moWSco2lnJUaf56s.txt把這個文件放在mp目錄下後,SpringMVC URL就不生效了,只能這裏提交後把MP目錄名稱改掉。

相關文章
相關標籤/搜索