1. 程式人生 > >微信公眾號之微信支付(V3版)jsp頁面jsapi統一下單調啟支付(java版)

微信公眾號之微信支付(V3版)jsp頁面jsapi統一下單調啟支付(java版)

web專案

按順序一步一步來

準備: 申請了微信支付介面的微信公眾號一枚 , 備案的域名網站一枚, (如果有沒有的這兩個東西會耽誤你很久,因為微信支付必須是線上,無法本地除錯,)

 這裡說一下 如果有經濟條件的最好申請一臺win系統的伺服器作為測試伺服器這樣會使你省去很多的麻煩,裝上開發軟體直接線上除錯很爽.

首先截了幾張需要設定的圖,瞭解一下,開發中自己需要的引數常量

圖一

圖二

圖3

圖4

圖5

這些設定的地方分別在微信公眾號平臺和微信商戶平臺,自從2017年8月改版之後微信支付單獨拎出來了,有的配置很隱蔽不是很好找還有那個官方給的微信支付的demo

這是微信目前的demo地址

微信支付demo下載   https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1  

demo是maven專案自行配置之後閱讀README.md 檔案 按這裡的提示修改自己的配置 個人感覺相比較v2版的微信支付V3的demo確實簡化了不少

配置MyConfig    .   微信的demo有點小問題需要自己搞搞,

別忘記下載 (圖4) 的證書檔案,  cert.zip ,安裝過程看壓縮檔案裡的教程密碼就是公眾號的商戶號

這裡是部分的常量


  微信分配的公眾賬號ID  APPID="wxb88888888888be";
    /*
     * 微信支付商戶號
     */
    public static final String MCH_ID="14888888888";//必填
    /**
     * 裝置號
     */
    public static final String DEVICE_INFO="WEB";//非必填
    /**
     * 微信伺服器回撥通知url
     */
    public static String NOTIFY_URL="http://localhost:80/paySuccess.do";
    /**
     * app_select
     */
    public static final String APPSELECT="e17706b888888888888888c10";
    /**
     * token
     */
    public static final String TOKEN="MYTOKEN";
    /**
     * EncodingAESKey
     */
    public static final String EncodingAESKey="gXL1RGlDN2KfeCL8888888888888EfB6Tyt3y";
    /**
     * API祕鑰
     */
    public static final String APPKEY="JXyrBTnsS8888888888HbaVGhdcXso";
 
    

demo配置好之後幾乎該有的都有了, 像之前md5加密函式,隨機字串,時間戳等等 微信demo工具類裡WXPayUtil.java都提供了

之後就是頁面訪問調啟jsapi支付,


編寫後臺函式呼叫統一下單介面

這個後臺方法注意了,支付授權目錄就是這裡

例: http://www.baidu.com/apy/   (授權目錄)

這樣 這幾個fang都可以使用

http://www.baidu.com/pay/doShopScore.do

http://www.baidu.com/pay/doShopScore.do2

http://www.baidu.com/pay/doShopScore.do3

需要注意的一個地方, try {}塊裡的程式碼

Map<String, String> mp = wxpay.unifiedOrder(data);

微信處理完之後返回的集合 的使用,

看到返回的值什麼都有了就直接拿到jsapi裡用,就一直簽名驗證失敗,後來發現 Sign 不是paySign (其實我到現在也不知道你們這個簽名是不是一樣的含義)  ,艹,誰知道還分這玩意兒 ,說真的微信裡引數名起名起的一塌糊塗,亂七八糟,

最後反正只從mp裡取了一個引數package用了重新生成了簽名,居然可以了,乖乖

這個微信真是的,本來引數就不清楚了開發的時候都得懵, 到底是想幹嘛,如果是想讓自己生成簽名(paySign)幹嘛返回簽名(Sign)

/**
	 * 使用者  購買成為 VIP 產生 (積分) 進入付款頁面 (介面)
	 */
	@ResponseBody
	@RequestMapping(value = "/pay/doShopScore.do", method = RequestMethod.POST)
	public Map<String,Object> doShopScore(HttpServletRequest request, HttpServletResponse response,Model model) throws Exception {
		String custId = Global.ZW_WECHAT_COMPANY_ID;//
		Map<String,Object> resultMap = new HashMap<String, Object>();
		String openid = (String) this.getSession().getAttribute("customerOpenId");
		String body = "科技-物品";//作為訂單商品名稱使用
		String total_fee = "0";//總金額數(分)
		//獲取物品id
		String dbGoodsPriceId = request.getParameter("dbGoodsPriceId");//0 300,1 3000
		String referrerOpenid = request.getParameter("referrerOpenId");//推薦人的openid 注意大小寫
		String referrerPhone = request.getParameter("referrerPhone");//推薦人的註冊電話
		DbGoodsPrice dbGoodsPrice = null;
		if(StringUtils.isNotBlank(dbGoodsPriceId)){
			dbGoodsPrice = dbGoodsPriceService.get(new DbGoodsPrice(dbGoodsPriceId));
			body = dbGoodsPrice.getDbGoods().getGoodsName();
			total_fee = String.valueOf(dbGoodsPrice.getGoodsPrice());
		}
		
        String appid = ConstantUtil.APPID;
        String mch_id = ConstantUtil.MCH_ID;
        String device_info = ConstantUtil.DEVICE_INFO;
        String nonce_str = WXPayUtil.generateNonceStr();
    
        String out_trade_no = DateUtils.fmtTime14Date(new Date());//商戶訂單號
        String fee_type = "CNY";//人民幣
        
        String spbill_create_ip = request.getRemoteAddr();//終端ip
        Date currDate = new Date();//當前日期
        String time_stamp = DateUtilsEx.formatToString(currDate,DateUtilsEx.DATE_FORMAT_SEC_U);//交易起始時間
        String time_expire = com.jeeplus.common.utils.DateUtils.getCurrTimePushMinute4DateStr(currDate,Integer.valueOf(SetUpUtils.getConfigParam("sys_order_pay_validity_date",custId)));//交易結束時間   當前時間 + 30分鐘 
        String notify_url = ConstantUtil.NOTIFY_URL;
        String trade_type = ConstantUtil.TRADE_TYPE;//JSAPI
        
        //預支付訂單生成===================start===========================
        DbOrder dbOrder = new DbOrder();
        dbOrder.setOrderCode(SetUpUtils.BaseSeq(custId,1));//訂單序號
        dbOrder.setOrderType(DictUtils.getDictValue("訂單","zw_order_type","0"));//訂單型別0 股份型別
        dbOrder.setOutTradeNo(out_trade_no);
        dbOrder.setGoodName(body);
        
        dbOrder.setGoodPrice(Integer.valueOf(total_fee));
        dbOrder.setGoodsPriceId(dbGoodsPrice.getId());
        dbOrder.setGoodsNum(1);//
        dbOrder.setIntegralToCash(0);
        dbOrder.setTotalPrice(Integer.valueOf(total_fee));
        dbOrder.setFeeType(DictUtils.getDictValue("人民幣","zw_currency","0"));
        dbOrder.setPayType(DictUtils.getDictValue("微信支付","zw_pay_type","0"));//支付型別
        dbOrder.setPayState(DictUtils.getDictValue("未支付","zw_pay_state","0"));//訂單狀態
        dbOrder.setCustomerOpenid(openid);
        User user = (User) this.getSession().getAttribute("customer");
        dbOrder.setOrderPayValidityDate(com.jeeplus.common.utils.DateUtils.getCurrTimePushMinute4Date(currDate,Integer.valueOf(SetUpUtils.getConfigParam("sys_order_pay_validity_date",custId))));//訂單支付有效期
        dbOrder.setCreateBy(user);
        dbOrder.setCreateDate(new Date());//訂單建立時間
        dbOrder.setReferrerPhone(referrerPhone);//推薦人電話
        dbOrder.setReferrerOpenid(referrerOpenid);//推薦人openid
        dbOrder.setUpdateBy(user);
        dbOrder.setUpdateDate(new Date());
        
        dbOrder.setNonceStr(nonce_str);
        dbOrder.setTimeStamp(time_stamp);
        dbOrder.setTimeExpire(time_expire);
        dbOrder.setSpbillCreateIp(spbill_create_ip);
        
        if(!dbOrder.getIsNewRecord()){//編輯表單儲存
			DbOrder t = dbOrderService.get(dbOrder.getId());//從資料庫取出記錄的值
			MyBeanUtils.copyBeanNotNull2Bean(dbOrder, t);//將編輯表單中的非NULL值覆蓋資料庫記錄中的值
			dbOrderService.save(t);//儲存
		}else{//新增表單儲存
			dbOrderService.save(dbOrder);//儲存
		}
        //訂單log  未支付
        //訂單id//單據狀態 //狀態說明 //操作者id
  		DbOrderLog dbOrderLog = setDbRepairLogParam(dbOrder.getId(),0,DictUtils.getDictLabel("0","zw_pay_state","未支付"), user.getId());
  		dbOrderLogService.save(dbOrderLog);//儲存
        
        this.getSession().setAttribute("orderId",dbOrder.getId());//訂單id
        //預支付訂單生成===================end===========================
        
        //設定支付引數==============================================
        MyConfig config = new MyConfig();
        WXPay wxpay = new WXPay(config, notify_url);
        Map<String, String> data = new HashMap<String, String>();
        
        data.put("appid",appid);
        data.put("mch_id",mch_id);
        data.put("device_info",device_info);
        data.put("body",body);
        data.put("nonce_str",nonce_str);
        data.put("openid",openid);
        
        data.put("fee_type", fee_type);
        data.put("trade_type",trade_type);//jsAPI 支付
        data.put("total_fee", total_fee);
        data.put("time_start",String.valueOf(time_stamp));//起始時間
        data.put("time_expire",String.valueOf(time_expire));//結束時間
        
        data.put("out_trade_no",out_trade_no);
        data.put("spbill_create_ip",spbill_create_ip);
        data.put("notify_url",notify_url);
         
        try {
        	Map<String, String> mp = wxpay.unifiedOrder(data);
        	
            /*model.addAttribute("appid",appid);
            model.addAttribute("time_stamp",time_stamp);
            model.addAttribute("openid",openid);
            model.addAttribute("nonce_str",mp.get("nonce_str"));
            model.addAttribute("package", "prepay_id="+mp.get("prepay_id").toString().trim());*/
            
            Map<String, String> data2 = new HashMap<String, String>();
            data2.put("appId", appid); // 必須
            data2.put("timeStamp",String.valueOf(time_stamp));
            data2.put("nonceStr", mp.get("nonce_str"));
            data2.put("signType", "MD5");
            data2.put("package", "prepay_id=" + mp.get("prepay_id").toString().trim());//注意prepay_id的值是一個鍵值對
            //model.addAttribute("paySign",WXPayUtil.generateSignature(data2,ConstantUtil.APPKEY));
            
            
            resultMap.put("appid",appid);
            resultMap.put("time_stamp",time_stamp);
            resultMap.put("openid",openid);
            resultMap.put("nonce_str",mp.get("nonce_str"));
            resultMap.put("packageStr", "prepay_id="+mp.get("prepay_id").toString().trim());
            resultMap.put("paySign",WXPayUtil.generateSignature(data2,ConstantUtil.APPKEY));
            
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
       
	    return resultMap;
	}
	

jsp頁面

$.ajax({
		url:ctx+"/wechat/pay/doShopScore.do",
		type:"POST",
		data:{"dbGoodsPriceId":dbGoodsPriceId},
		success:function(resultMap){
		submit_flag=true;
		if(resultMap != null && resultMap !=''){
						var appid = resultMap.appid;
						var time_stamp = resultMap.time_stamp;
						var nonce_str = resultMap.nonce_str;
						var packageStr = resultMap.packageStr;
						var paySign = resultMap.paySign;
								//設定引數
								WeixinJSBridge.invoke('getBrandWCPayRequest', {
							        "appId":appid,     //公眾號名稱,由商戶傳入     
								"timeStamp":time_stamp+"",         //時間戳,自1970年以來的秒數     
							        "nonceStr":nonce_str, //隨機串     
							        "package":packageStr,     
							        "signType":"MD5",//微信簽名方式:     
							        "paySign":paySign
								    },
								    function(res){     
								        if(res.err_msg == "get_brand_wcpay_request:ok" ) {    
								             //alert("支付成功");  
								             // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在使用者支付成功後返回    ok,但並不保證它絕對可靠。     
								             location.replace(ctx+"/wechat/pay/toSuccessVip.do");//跳到訂單成功頁
								         }else if (res.err_msg == "get_brand_wcpay_request:cancel")  {  
								             //alert("支付過程中使用者取消");  
								             //使用者取消訂單支付返回訂單列表
								             window.location.href=ctx+"/wechat/pay/notPay.do";  
								         }else{  
								            //支付失敗  
								            alert(res.err_msg);
								         }   
								        
								    }
								); 
							}
						},
						error:function(e){
							submit_flag=true;
						}
					});


支付成功還要有個成功之後的回撥函式,不給返回success 程式碼 還一直不停的回撥,注意了


/**
* 微信支付成功後回撥方法
* @param request
* @param response
* @return
* @throws Exception
*/
@ResponseBody  
@RequestMapping(value = "/pay/paySuccess.do")  
    public String notify(HttpServletRequest request, HttpServletResponse response) throws Exception {  
        String result;//返回給微信的處理結果  
        String inputLine;  
        String notityXml = "";  
        request.setCharacterEncoding("UTF-8");  
        //response.setCharacterEncoding("UTF-8");  
        //response.setContentType("text/html;charset=UTF-8");  
        //response.setHeader("Access-Control-Allow-Origin", "*");  
        //微信給返回的東西  
        try {  
            while ((inputLine = request.getReader().readLine()) != null) {  
                notityXml += inputLine;  
            }  
            request.getReader().close();  
        } catch (Exception e) {  
            e.printStackTrace();  
            result = setXml("fail","xml獲取失敗");  
        }  
        if (StringUtils.isEmpty(notityXml)) {  
            result = setXml("fail","xml為空");  
        }  
        
        System.out.println(notityXml);
        Map map = WXPayUtil.xmlToMap(notityXml);  
        // 解析各種資料  
        String appid = (String) map.get("appid");//應用ID  
        String attach = (String) map.get("attach");//商家資料包  
        String bank_type = (String) map.get("bank_type");//付款銀行  
        String cash_fee = (String) map.get("cash_fee");//現金支付金額  
        String fee_type = (String) map.get("fee_type");//貨幣種類  
        String is_subscribe = (String) map.get("is_subscribe");//是否關注公眾賬號  
        String mch_id = (String) map.get("mch_id");//商戶號  
        String nonce_str = (String) map.get("nonce_str");//隨機字串  
        String openid = (String) map.get("openid");//使用者標識  
        String out_trade_no = (String) map.get("out_trade_no");// 獲取商戶訂單號  
        String result_code = (String) map.get("result_code");// 業務結果  
        String return_code = (String) map.get("return_code");// SUCCESS/FAIL  
        String sign = (String) map.get("sign");// 獲取簽名  
        String time_end = (String) map.get("time_end");//支付完成時間  
        String total_fee = (String) map.get("total_fee");// 獲取訂單金額  
        String trade_type = (String) map.get("trade_type");//交易型別  
        String transaction_id = (String) map.get("transaction_id");//微信支付訂單號  
          
        User user = systemService.getUserByOpenId(openid);
        SortedMap<String, String> parameters = new TreeMap<String, String>();  
        // 資料加密  
        parameters.put("appid", appid);//應用ID  
        parameters.put("attach", attach);//商家資料包  
        parameters.put("bank_type", bank_type);//付款銀行  
        parameters.put("cash_fee", cash_fee);//現金支付金額  
        parameters.put("fee_type", fee_type);//貨幣種類  
        parameters.put("is_subscribe", is_subscribe);//是否關注公眾賬號  
        parameters.put("mch_id", mch_id);//商戶號  
        parameters.put("nonce_str", nonce_str);//隨機字串  
        parameters.put("openid", openid);//使用者標識  
        parameters.put("out_trade_no", out_trade_no);// 商戶訂單號  
        parameters.put("result_code", result_code);// 業務結果  
        parameters.put("return_code", return_code);// SUCCESS/FAIL  
        parameters.put("time_end", time_end);// 支付完成時間  
        parameters.put("total_fee", total_fee);// 獲取訂單金額  
        parameters.put("trade_type", trade_type);//交易型別  
        parameters.put("transaction_id", trade_type);//微信支付訂單號  
        
          
        /*System.out.println("**************************************************************************************************");  
        System.out.println(appid+"-------------------應用ID");  
        System.out.println(attach+"-------------------商家資料包");  
        System.out.println(bank_type+"-------------------付款銀行");  
        System.out.println(cash_fee+"-------------------現金支付金額");  
        System.out.println(fee_type+"-------------------貨幣種類");  
        System.out.println(is_subscribe+"-------------------是否關注公眾賬號");  
        System.out.println(mch_id+"-------------------商戶號");  
        System.out.println(nonce_str+"-------------------隨機字串");  
        System.out.println(openid+"-------------------使用者標識");  
        System.out.println(out_trade_no+"-------------------獲取商戶訂單號");  
        System.out.println(result_code+"-------------------業務結果");  
        System.out.println(return_code+"------------------- SUCCESS/FAIL");  
        System.out.println(sign+"-------------------獲取簽名-微信回撥的簽名");  
        System.out.println(time_end+"-------------------支付完成時間");  
        System.out.println(total_fee+"-------------------獲取訂單金額");  
        System.out.println(trade_type+"-------------------交易型別");  
        System.out.println(transaction_id+"-------------------微信支付訂單號");  
        System.out.println("**************************************************************************************************");  
          */
  
        if (result_code.equals("SUCCESS")) {
            result = setXml("SUCCESS", "OK");  
        }else{
        result = setXml("fail", "微信返回的交易狀態不正確(result_code=" + result_code + ")");  
        System.err.println("微信返回的交易狀態不正確(result_code=" +result_code+ ")");  
        }
        // 如果微信返回的結果是success,則修改訂單狀態  
        if (return_code.equals("SUCCESS")) {
        result = setXml("SUCCESS", "OK");  
       
//這裡是我的業務........................................
          
        }else{
        result = setXml("fail", return_code);
        }
        System.out.println("回撥成功----返回給微信的xml:" + result);  
        return result;  
    }  
  
    //通過xml 發給微信訊息  
    public static String setXml(String return_code, String return_msg) {  
        SortedMap<String, String> parameters = new TreeMap<String, String>();  
        parameters.put("return_code", return_code);  
        parameters.put("return_msg", return_msg);  
        return "<xml><return_code><![CDATA[" + return_code + "]]>" +   
                "</return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>";  
    }  

配置域名千萬檢查清楚不能寫錯,雖然簡單但是很致命,因為那是你很少再會去檢查的地方  祝你好運