微信小程序-支付

業務需求

實現小程序支付功能

注意事項(訂單號重複問題)

1.平臺訂單號

2.微信支付訂單號

分開設計,訂單失敗成功以微信訂單號爲準 更新(回調時驗證)相關產品訂單支付狀態;

環境

1.後端java

2.jdk1.7

前端代碼(小程序)

var app = getApp()
Page({
  payAction: function () {
    var openid = 'oAJ1N5Vg-UcltfCj6uGXXXXX';//自己openID
    wx.request({
      url: 'http://XXXXX/aglie/tenAppletPay/v1/orderPay',//調用接口生成 統一下單的參數
      data: {
        openId: openid,//openid  
        orderId:'20180717154514968',
        type:'1'
        //body: "尊貴VIP", //商品信息  
        //totalfee: 100 //金額 
        
      },
      method: 'POST', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
      header: {
        'content-type': 'application/x-www-form-urlencoded'
      }, // 設置請求的 header
      success: function (res) {
        console.log("status=" + res.data.status)
        console.log("message=" + res.data.message)
          var obj = res.data //得到參數
          console.log('微信支付接口信息')
          console.log('簽名:' + res.data.paySign)
          console.log('隨機串:' + res.data.nonceStr)
          console.log('時間戳:' + res.data.timeStamp)
          console.log('package:' + res.data.package)
        wx.requestPayment({
          timeStamp: obj.timeStamp,
          nonceStr: obj.nonceStr,
          package: obj.package,
          signType: 'MD5',
          paySign: obj.paySign,
          success: function (res) {
            console.log('支付成功打印信息' )
            console.log('timeStam=' + obj.timeStamp)
            console.log('nonceStr=' + obj.nonceStr)
            console.log('package=' + obj.package)
            console.log('paySign=' + obj.paySign)
            console.log('成功')
          }, fail: function (e) {
            console.log(e)
            console.log('失敗')
          }
        })
      },
    })
  }
})

後端代碼(java)

1. 參數配置

	// AppID(小程序ID) 小程序唯一標識 (在微信小程序管理後臺獲取)
	private static final String APPID = "wx8a52b60XXXXXXX";
	// 小程序的 AppSecret(小程序密鑰) (在微信小程序管理後臺獲取)
	private static final String APPSECRET = "d3455f3cfb9685c602b60XXXXXXX";
	// 授權(必填) 填寫爲 authorization_code (小程序)
	private static final String GRANT_TYPE = "authorization_code";
	
	//微信支付的商戶id
	public static final String MCHID = "12760XXXXXXX";
	// 商戶支付密鑰Key。審覈通過後,在微信發送的郵件中查看
	public static final String KEY = "2b60XXXXXXX12345";
    //簽名方式,固定值
    public static final String SIGNTYPE = "MD5";
    //交易類型,小程序支付的固定值爲JSAPI
    public static final String TRADETYPE = "JSAPI";
    //微信統一下單接口地址
    public static final String PAY_URL = 	"https://api.mch.weixin.qq.com/pay/unifiedorder";
	//支付成功後的服務器回調url,Controller裏的回調函數地址
	public static final String NOTIFY_URL = "http://XXXX/aglie/tenAppletPay/v1/notify";

2.統一下單支付

 /**
	     * 
	     * @Title: orderPay   
	     * @Description: TODO(統一下單)   
	     * @param: @param request
	     * @param: @param response
	     * @param: @param orderId
	     * @param: @param openId
	     * @param: @param type 業務類型 {1:諮詢(收費&免費) 4.電商 
	     * @param: @return
	     * @param: @throws Exception      
	     * @return: Map<String,Object>      
	     * @throws
	     */
		@ResponseBody
		@RequestMapping(value = "/v1/orderPay" , method = RequestMethod.POST)
		public Map<String, Object> orderPay(HttpServletRequest request,HttpServletResponse response
				,@RequestParam(required=true) String orderId
				,@RequestParam(required=true) String openId
				,@RequestParam(required=true) String type) throws Exception{
			 logger.info("微信統一下單  接口調用");
		     Map<String, Object> map = Maps.newHashMap();
				//code獲取參數
		     if (StringUtils.isBlank(orderId)) {
		    	 map.put("status", "fail");
		    	 map.put("message", "orderId is not null.");
		    	 return map;
		     }
		     //這裏根據orderId獲取下單信息 (openId、
		     logger.info("【orderPay】-接收商品orderId號碼="+orderId + " 業務類型type ="+ type); 
		     //局部變量
		     String body="尊貴VIP";//訂單 商品信息
		     int totalfee=0; //訂單 商品金額 微信是按分處理的
		     String wx_out_trade_no=""; //微信支付訂單號,只能使用一次,非產品訂單號,業務不同前綴不同(規則 諮詢(ZX...) 電商(DS...)

	     	switch (type) {
			case "1":
				System.out.println("========諮詢微信統一下單處理 開始=========");
				//微信支付訂單號生成
				 Date  data = new Date();  
				 wx_out_trade_no="ZX" + DateUtil.dateFormatSSS.format(data)+UtilDate.getThree();

		    	//更新微信支付單號(根據自己業務場景處理) 
		    	try {
		    		 logger.info("2-- 微信統一下單 訂單號更新訂單庫中"); 
		        	 update_orderIdWx_date(type,orderId,wx_out_trade_no);
				} catch (Exception e) {
					logger.info("ERROR-更新微信支付訂單號:orderId號碼="+orderId + " 業務類型type ="+ type +" orderIdWx="+wx_out_trade_no); 
				}
				//根據訂單號獲取訂單詳情(根據自己業務場景處理)
		    	 logger.info("3-- 微信統一下單 根據orderId 查詢訂單庫商品信息"); 
				 MyhQuestion myhQuestionInfo =myhQuestionService.findByOrderId(orderId);
				 if(myhQuestionInfo!=null){
					body="諮詢服務";
			        //Double不丟失精度,要用BigDecimal處理
			        BigDecimal v1 = myhQuestionInfo.getFinalPrice();
			        BigDecimal v2 = new BigDecimal("100");
			        Double b = v1.multiply(v2).doubleValue();
			        int fee1 = b.intValue();
					totalfee=fee1;
				 }else {
					 logger.info("ERROR-查詢訂單信息:orderId號碼="+orderId + " 業務類型type ="+ type); 
				}
				 System.out.println("========諮詢微信統一下單處理  結束=========");
				break;

			default:
				break;
			}
		     try {
		    	//獲取客戶端請求code
				String        appid = AppletConfig.getAppid();    //微信小程序--》“開發者ID”
				String       mch_id = AppletConfig.getMchid();    //商戶號,將該值賦值給partner
				String          key = AppletConfig.getKey();    //微信支付商戶平臺登錄)
			    String       openid = openId;    //openid
			    String           ip = WXUtil.getIpAddr(request);    //ip地址
			    String    body_info = body; //描述
				int       total_fee = totalfee;     //支付金額
			    String   notify_url = AppletConfig.getNotifyUrl();   //回調鏈接
				//orderId庫裏訂單ID  與  微信out_trade_no不同;避免支付失敗,微信平臺訂單號出現重複,這裏必須重新生成
				String out_trade_no = wx_out_trade_no; //只能使用一次,所以不能使用orderId
			    Map<Object, Object> map_pay=Applet.weixinPlay(mch_id, appid, key, openid, total_fee, out_trade_no, notify_url, body_info, ip);
			    if ("SUCCESS".equals(map_pay.get("return_code"))) {      
			     map.put("paySign", map_pay.get("paySign"));
		    	 map.put("timeStamp", map_pay.get("timeStamp"));
		    	 map.put("nonceStr", map_pay.get("nonceStr"));
		    	 map.put("package", map_pay.get("package"));
				 map.put("status", "success");
		    	 map.put("message", "生成訂單");
		    	 map.put("return_code", "SUCCESS");
			    }else {
			     logger.info("return_code="+map.get("return_code")); 
		    	 map.put("status", "fail");
		    	 map.put("message", "生成訂單失敗");
		    	 map.put("return_code", "Fail");
		    	 map.put("return_msg", map_pay.get("return_msg"));
				}
		    	 return map;
				
			} catch (Exception e) {
				 logger.debug("Error-e:",e);
			     logger.info("生成統一下單失敗:openId="+openId); 
				 map.put("status", "fail");
		    	 map.put("message", "請求失敗");
		    	 return map;
			}
		     
		}

3.回調更新狀態

		/**
		 * 回調函數
		 * @param request
		 * @param response
		 * @throws Exception
		 */
		@ResponseBody
		@RequestMapping(value = "v1/notify" , method = RequestMethod.POST)
		public  void notify(HttpServletRequest request,HttpServletResponse response) throws Exception{
			logger.info("支付成功的回調函數(notify)接口調用");
			weixinpay_notify(request,response);
		}

4.其它方法

weixinPlay()生成微信訂單

/**
		 * 生成微信訂單
		 * 
		 * @param openid
		 * @param period_number
		 * @param merchant_id
		 * @param num
		 * @return
		 */
		public static SortedMap<Object, Object> weixinPlay(String mch_id,String appid,String key,String openid,int total_fee,String out_trade_no,String notify_url,String body,String ip) throws UnsupportedEncodingException, DocumentException {
			logger.info("生成微信訂單(weixinPlay)接口調用");
			SortedMap<Object, Object> paymentPo = new TreeMap<Object, Object>();
			paymentPo.put("appid",appid);
			paymentPo.put("mch_id",  mch_id);
			paymentPo.put("nonce_str", WXUtil.generate());
			paymentPo.put("body",body);
			paymentPo.put("out_trade_no",out_trade_no);
			paymentPo.put("total_fee",String.valueOf(total_fee));
			paymentPo.put("spbill_create_ip", ip);//這裏填你的ip地址
			paymentPo.put("notify_url", notify_url);
			paymentPo.put("trade_type", AppletConfig.getTradetype()); //JSAPI
			paymentPo.put("openid", openid);
			//第一次簽名
			String sign = WXUtil.createSign_ChooseWXPay("UTF-8", paymentPo, key);
			paymentPo.put("sign", sign);
			String param = WXUtil.getRequestXml(paymentPo);;
		
			String request = WXUtil.httpRequest(AppletConfig.PAY_URL, "POST", param);
			Map<String, String> map = new HashMap<String, String>();         // 將解析結果存儲在HashMap中
			InputStream in = new ByteArrayInputStream(request.getBytes());
			SAXReader reader = new SAXReader();                              // 讀取輸入流
			Document document = reader.read(in);
		
			Element root = document.getRootElement();                        // 得到xml根元素
			@SuppressWarnings("unchecked")                                   // 得到根元素的所有子節點
			List<Element> elementList = root.elements();
			for (Element element : elementList) {
				map.put(element.getName(), element.getText());
			}
			SortedMap<Object, Object> result = new TreeMap<Object, Object>();
				
			if (map.get("return_code").equals("SUCCESS")) {                  // 業務結果
				String nonceStr  =WXUtil.generate();
				Long   timeStamp = System.currentTimeMillis() / 1000;
				SortedMap<Object, Object> params = new TreeMap<Object, Object>();
				
				params.put("appId", appid);
				params.put("nonceStr", nonceStr);
				params.put("package", "prepay_id=" + map.get("prepay_id")); 
				params.put("signType", AppletConfig.getSigntype()); //MD5
				params.put("timeStamp", timeStamp); 
				//二次簽名  這個簽名用於小程序端調用wx.requesetPayment方法
				String paySign = WXUtil.createSign_ChooseWXPay("UTF-8", params, key);
				
				result.put("paySign", paySign);
				result.put("timeStamp", timeStamp + "");
				result.put("nonceStr", nonceStr);
				result.put("package", "prepay_id=" + map.get("prepay_id"));
				result.put("return_code", "SUCCESS");
			}else {
				result.put("return_code", "Fail");
				result.put("return_msg", map.get("return_msg"));
			}
			return result;
		}

weixinpay_notify() 回調方

/**
		 * 支付成功的回調函數
		 * @param request
		 * @param response
		 * @throws Exception
		 */
	    public  void weixinpay_notify(HttpServletRequest request,HttpServletResponse response) throws Exception{  
	    	System.out.println("=========支付成功,回調函數(weixinpay_notify)接口調用   開始=========");
			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();  
	        //sb爲微信返回的xml
	        String notityXml = sb.toString();
	        Map<String, String> m = new HashMap<String, String>();  
	        m = WXUtil.doXMLParse(sb.toString());  
	        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("接收到的報文2- packageParams:" + packageParams);
	        String key = AppletConfig.getKey(); //祕鑰 
            String resXml = ""; 
             //驗證簽名
	        if(WXUtil.isTenpaySign("UTF-8", packageParams,key)) {   
	            //logger.info("接收到的報文3- packageParams:" + packageParams);
	            System.out.println("-------1- 簽名驗證成功--------");
	            //驗證報文
	            if("SUCCESS".equals((String)packageParams.get("return_code"))){  
//	            	 //logger.info("SUCCESS=packageParams:return_code" );
	            	 System.out.println("-------2- 報文驗證成功--------");
	            	//得到返回的參數
	            	String openid = (String)packageParams.get("openid");  
	                String transaction_id = (String)packageParams.get("transaction_id");  
	                String out_trade_no = (String)packageParams.get("out_trade_no");  
	                String total_fee = (String)packageParams.get("total_fee");  
	                Float fee= Float.parseFloat(total_fee)/100;
	                /**此處添加自己的業務邏輯代碼start**/
	                System.out.println("******處理業務邏輯  開始******");
                        
                      這裏處理業務
			        
	                System.out.println("******處理業務邏輯  結束******");
	                /**此處添加自己的業務邏輯代碼end**/
	                
	                //通知微信服務器已經支付成功
	                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"  
	                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";  
	                System.out.println("-------3- 通知微信已支付成功--------");
	                BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());  
	                out.write(resXml.getBytes());  
	                out.flush();  
	                out.close();
	            } else {  
	              System.out.println("----回調失敗,報文爲空----");
		            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
		                    + "<return_msg><![CDATA[報文爲空]]></return_msg>" + "</xml> ";
	            }  
	        } else{  
	        	System.out.println("----回調失敗,簽名失敗----");
	            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
	                    + "<return_msg><![CDATA[簽名失敗]]></return_msg>" + "</xml> ";
	        } 
	        System.out.println("=========支付成功,回調函數(weixinpay_notify)接口調用   結束=========");
	    }

相關工具類(簽名、祕鑰生成等)這裏就不寫了

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章