• 玩转小程序支付之支付结果通知


    上一篇讲了小程序支付的过程,接下来就是支付结果通知

    官方文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_7

    注意: 

    支付通知的url 是通过【统一下单API】中提交的参数notify_url设置,如果链接无法访问,商户将无法接收到微信通知。

    通知url必须为直接可访问的url,不能携带参数。示例:notify_url:“https://pay.weixin.qq.com/wxpay/pay.action”

    在前面的支付的参数中设置了支付结果的URL——baseUrl+"/notify"

    所以支付通知会发到我自己服务器下的这个路径下,会接收到类似如下的xml字符串(如果正常的话,即result_code 和return_code都为SUCCESS)

    解析这个xml,可以得到transaction_id,out_trade_no等关键信息。

    为了保证返回信息是否正确,我们可以去验证其正确性。

    方法是对参数进行加密获取的签名,然后比对返回的签名和我们生成的签名是否一致,若不一致就表明返回的支付通知被修改,不过一般不会出现这种情况。

    注意:

     可能是微信方面觉得一次不一定能通知到,所以支付通知可能会发多次,所以我们在收到正确的通知之后,需要给小程序官方返回一段xml,表示收到,之后就不会再收到啦。

     

    整个支付通知的处理的代码如下

    /**
    	 * 支付完成通知
    	 * @param request
    	 * @param response
    	 * @return
    	 * @throws Exception
    	 */
    	@RequestMapping(value = "/notify",method = RequestMethod.POST)
        public String notify(HttpServletRequest request, HttpServletResponse response) throws Exception {
    		BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream)request.getInputStream()));
            String line = null;
            StringBuilder sb = new StringBuilder();
            while((line = br.readLine())!=null){
            	sb.append(line);
            }
            //解析并给微信发回收到通知确认
            Map map =  PayUtils.doXMLParse(sb.toString());
            String returnCode = map.get("return_code").toString();
            if(returnCode.equals("SUCCESS")){
            	String resultCode = map.get("result_code").toString();
            	if(resultCode.equals("SUCCESS")){
            		SortedMap<String, String> packageParams = new TreeMap<String, String>();
            		packageParams.put("appid", map.get("appid").toString());
            		packageParams.put("attach", map.get("attach").toString());
            		packageParams.put("bank_type", map.get("bank_type").toString());
            		packageParams.put("cash_fee", map.get("cash_fee").toString());
            		packageParams.put("fee_type", map.get("fee_type").toString());
            		packageParams.put("is_subscribe", map.get("is_subscribe").toString());
            		packageParams.put("mch_id", map.get("mch_id").toString());
            		packageParams.put("nonce_str", map.get("nonce_str").toString());
            		packageParams.put("openid", map.get("openid").toString());
            		packageParams.put("out_trade_no", map.get("out_trade_no").toString());
            		packageParams.put("result_code", map.get("result_code").toString());
            		packageParams.put("return_code", map.get("return_code").toString()); 
            		packageParams.put("time_end", map.get("time_end").toString());
            		packageParams.put("total_fee", map.get("total_fee").toString());
            		packageParams.put("trade_type", map.get("trade_type").toString());
            		packageParams.put("transaction_id", map.get("transaction_id").toString());
            		String sign = PayUtils.createSign(packageParams,key);
            		String originSign = map.get("sign").toString();
            		if(sign.equals(originSign)){
            			//签名一致,保存支付流水
            			String xml="<xml>"
                    			  +"<return_code>SUCCESS</return_code>"
                    			  +"<return_msg>OK</return_msg>"
                    			  +"</xml>";
            			ProfPayLog payLog = new ProfPayLog();
            			payLog.setCreatedAt(new Date());
            			payLog.setSource(Source.WeiXin);
            			DecimalFormat df = new DecimalFormat("######0.00"); 
            			payLog.setTotalFee(String.valueOf(df.format((Double.valueOf(map.get("total_fee").toString())/100))));
            			payLog.setTradeNo(map.get("out_trade_no").toString());
            			payLog.setTransactionId(map.get("transaction_id").toString());
            			String attach = map.get("attach").toString();//userId+"#wx#"+activityId
            			payLog.setUserId(attach.split("#wx#")[0]);
            			payLog.setType(ProfPayLog.Type.Pay);
            			WxappUser user = wxappUserService.find(Long.valueOf(attach.split("#wx#")[0]));
            			WxappActivity activity = wxappActivityService.find(Long.valueOf(attach.split("#wx#")[1]));
            			WxappActivityApply activityApply = wxappActivityApplyService.findActivityApplyByUserAndActivity(user, activity);
            			if(activityApply.getPayLogId() != null){
            				System.out.println("=========已经完成了存储支付流水=========");
            				return xml;
            			}else{
            				System.out.println("=========完成第一次保存支付流水=========");
            				payLog = wxappPayService.save(payLog);
            				//在活动申请表中关联上支付流水的id
                			activityApply.setPayLogId(String.valueOf(payLog.getId()));
                			wxappActivityApplyService.save(activityApply);
                        	return xml;
            			}
            		}else{
            			String xml="<xml>"
            	      			  +"<return_code>FAIL</return_code>"
            	      			  +"<return_msg>签名不一致</return_msg>"
            	      			  +"</xml>";
            	      	return xml;
            		}
            	}else{
            		String xml="<xml>"
                			  +"<return_code>FAIL</return_code>"
                			  +"<return_msg>支付通知失败</return_msg>"
                			  +"</xml>";
                			return xml;
            	}
            } else {
            	String xml="<xml>"
          			  +"<return_code>FAIL</return_code>"
          			  +"<return_msg>支付通知失败</return_msg>"
          			  +"</xml>";
          			return xml;
            }
        }
    

      

  • 相关阅读:
    [Cogs727] [网络流24题#2] 太空飞行计划 [网络流,最小割]
    [Cogs14] [网络流24题#1] 飞行员分配方案 [网络流,最大流,二分图匹配]
    [Poj2112][USACO2003 US OPEN] Optimal Milking [网络流,最大流][Dinic+当前弧优化]
    基本高精度模板
    Dinic模板
    [poj1698]Alice's Chance[网络流]
    [cf 599D] Spongebob and Squares
    [cf 599C] Day at the Beach
    [BZOJ1004]Cards
    [BZOJ1007]水平可见直线
  • 原文地址:https://www.cnblogs.com/tonyccc/p/7069961.html
Copyright © 2020-2023  润新知