微信公众号支付开发全过程

微信公众号支付开发全过程

需求:把游戏里的商城转移到微信公众号上

微信公众号支付开发的准备过程:

需要注册一个公众号,然后开通微信支付功能(需要5个工作日左右),然后就可以得到APPID,APP_SECRET,商户号,商户key等参数。

开始开发:

1. 调用统一下单接口,获取预支付ID

/**
 * 用户提交支付,获取微信支付订单接口
 */
@RequestMapping(value="/pay")
public ModelAndView pay(HttpServletRequest request,HttpServletResponse response){
    ModelAndView mv = new ModelAndView();
    String GZHID = "wxfd7c065eee11112222";// 微信公众号id
    String GZHSecret = "b5b3a627f5d1f8888888888888";// 微信公众号密钥id
    String SHHID = "111111111";// 财付通商户号
    String SHHKEY = "mmmmmmmmmmmmmmm";// 商户号对应的密钥

    /*------1.获取参数信息------- */
    //商户订单号
    String out_trade_no= request.getParameter("state"); 
    //价格
    String money = request.getParameter("money");
    //金额转化为分为单位
    String finalmoney = WeChat.getMoney(money);
    //获取用户的code
    String code = request.getParameter("code");

    /*------2.根据code获取微信用户的openId和access_token------- */
    //注: 如果后台程序之前已经得到了用户的openId 可以不需要这一步,直接从存放openId的位置或session中获取就可以。
    //toPay.jsp页面中提交的url路径也就不需要再经过微信重定向。写成:http://localhost:8080/项目名/wechat/pay?money=${sumPrice}&state=${orderId}
    String openid=null;
    try {
        List<Object> list = accessToken(code);
        openid=list.get(1).toString();
    } catch (IOException e) {
        logger.error("根据code获取微信用户的openId出现错误", e);
        mv.setViewName("error");
        return mv;
    }

    /*------3.生成预支付订单需要的的package数据------- */
    //随机数 
    String nonce_str= MD5.getMessageDigest(String.valueOf(new Random().nextInt(10000)).getBytes());
    //订单生成的机器 IP
    String spbill_create_ip = request.getRemoteAddr();
    //交易类型 :jsapi代表微信公众号支付
    String trade_type = "JSAPI";
    //这里notify_url是 微信处理完支付后的回调的应用系统接口url。
    String notify_url ="http://69a6a38e.ngrok.natapp.cn/heyi-console/wechat/weixinNotify";

    SortedMap<String, String> packageParams = new TreeMap<String, String>();
    packageParams.put("appid",  GZHID);  
    packageParams.put("mch_id",  SHHID);  
    packageParams.put("nonce_str", nonce_str);  
    packageParams.put("body", "费用");  
    packageParams.put("out_trade_no", out_trade_no);  
    packageParams.put("total_fee", finalmoney);  
    packageParams.put("spbill_create_ip", spbill_create_ip);  
    packageParams.put("notify_url", notify_url);  
    packageParams.put("trade_type", trade_type); 
    packageParams.put("openid", openid); 

    /*------4.根据package数据生成预支付订单号的签名sign------- */
    RequestHandler reqHandler = new RequestHandler(request, response);
    reqHandler.init( GZHID,  GZHSecret,  SHHKEY);
    String sign = reqHandler.createSign(packageParams);

    /*------5.生成需要提交给统一支付接口https://api.mch.weixin.qq.com/pay/unifiedorder 的xml数据-------*/
    String xml="<xml>"+
            "<appid>"+ GZHID+"</appid>"+
            "<mch_id>"+ SHHID+"</mch_id>"+
            "<nonce_str>"+nonce_str+"</nonce_str>"+
            "<sign>"+sign+"</sign>"+
            "<body><![CDATA["+"费用"+"]]></body>"+
            "<out_trade_no>"+out_trade_no+"</out_trade_no>"+
            "<total_fee>"+finalmoney+"</total_fee>"+
            "<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"+
            "<notify_url>"+notify_url+"</notify_url>"+
            "<trade_type>"+trade_type+"</trade_type>"+
            "<openid>"+openid+"</openid>"+
            "</xml>";

    /*------6.调用统一支付接口https://api.mch.weixin.qq.com/pay/unifiedorder 生产预支付订单----------*/
    String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    String prepay_id="";
    try {
        prepay_id = GetWxOrderno.getPayNo(createOrderURL, xml);
        if(prepay_id.equals("")){
            mv.addObject("ErrorMsg", "支付错误");
            mv.setViewName("error");
            return mv;
        }
    } catch (Exception e) {
        logger.error("统一支付接口获取预支付订单出错", e);
        mv.setViewName("error");
        return mv;
    }
    /*将prepay_id存到库中*/
    PageData p = new PageData();
    p.put("shopId", out_trade_no);
    p.put("prePayId", prepay_id);
    activityService.updatePrePayId(p);


    /*------7.将预支付订单的id和其他信息生成签名并一起返回到jsp页面 ------- */
    nonce_str= MD5.getMessageDigest(String.valueOf(new Random().nextInt(10000)).getBytes());
    SortedMap<String, String> finalpackage = new TreeMap<String, String>();
    String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
    String packages = "prepay_id="+prepay_id;
    finalpackage.put("appId",  GZHID);  
    finalpackage.put("timeStamp", timestamp);  
    finalpackage.put("nonceStr", nonce_str);  
    finalpackage.put("package", packages);  
    finalpackage.put("signType", "MD5");
    String finalsign = reqHandler.createSign(finalpackage);

    mv.addObject("appid",  GZHID);
    mv.addObject("timeStamp", timestamp);
    mv.addObject("nonceStr", nonce_str);
    mv.addObject("packageValue", packages);
    mv.addObject("paySign", finalsign);
    mv.addObject("success","ok");
    mv.setViewName("wechat/pay");
   return mv;
}

2. H5调起微信支付的内置JS

<script type="text/javascript">
			function onBridgeReady(){
				WeixinJSBridge.invoke(
					       'getBrandWCPayRequest', 
					       {
					           "appId" : "<%=paramsMap.get("appId") %>",     //公众号名称,由商户传入     
					           "timeStamp":"<%=paramsMap.get("timeStamp") %>",         //时间戳,自1970年以来的秒数     
					           "nonceStr" : "<%=paramsMap.get("nonceStr")%>", //随机串     
					           "package" : "<%=paramsMap.get("package")%>",     
					           "signType" : "<%=paramsMap.get("signType")%>",         //微信签名方式:     
					           "paySign" : "<%=paramsMap.get("paySign")%>" //微信签名 
					       },
					       function(res){    
					           // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回    ok,但并不保证它绝对可靠。 
					           if(res.err_msg == "get_brand_wcpay_request:ok" ) {//成功
					        	   $("#tip_icon").addClass("weui_icon_success");
					        		$("#tip").text("购买成功");
					        		$("#amount").text("恭喜你,获得"+"<%=goodContent%>");
					           }else if(res.err_msg == "get_brand_wcpay_request:cancel" ) {//取消
					        	   $("#tip_icon").addClass("weui_icon_warn");
					        	   $("#tip").text("用户取消支付");
					           }else if(res.err_msg == "get_brand_wcpay_request:fail" ) {//失败
					        	   $("#tip_icon").addClass("weui_icon_warn");
					        	   $("#tip").text("支付失败");
					           }else{
					        	   $("#tip").text(res.err_msg);
					           }
					   	    	$(".confirm_container").show();
								$("#chargeBtn").show();
					       }
					   ); 

			}

			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();
			}
 	    </script>

3.支付成功之后跳转回自己的系统的某个页面

遇到的问题:

1.在微信商户平台里面需要设置api秘钥(paternerKey),所谓paternerKey意思就是伙伴的秘钥,也就是合作商的秘钥。

需要自定义一个字符串,然后用MD5加密成32位的字符串,然后设置。

2.统一下单接口的容易出错的参数:

1)trade_type==交易类型==取值如下:JSAPI,NATIVE,APP。我们这里使用的JSAPI。标题已经说了,是微信公众号支付。他们的区别,请参考https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_2。

ps:JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付,统一下单接口trade_type的传参可参考这里。MICROPAY--刷卡支付,刷卡支付有单独的支付接口,不调用统一下单接口。

2)notify_url==通知地址==接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。

3)sign==签名==官方给的签名算法。https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3。获取预支付ID时,如果返回值是【签名错误】。那真是的你的签名错了,请仔细核对生成sign的参数名称、参数值和调用统一下单接口的参数名称和参数值

3.要想支付成功,需要在商户号设置支付授权目录。路径应为支付页面的上一级路径。

======================================大功告成=============================================

 

 

展开阅读全文

没有更多推荐了,返回首页