微信JSAPI支付(JAVA版)

最近公司需要在现有的项目都加入微信支付。做了一个星期的微支付,就当分享一下自己所学到的一些知识吧。

JSAPI支付适用于手机版项目,当然也不是绝对的。流程大致:
1. 注册微信公众号(注册的时候注意选择公众号类型)
2. 公众号认证和微信支付认证(一般人工校验需要一天的时间)
3. 在微信公众号里授权微信支付url、OAuth2.0网页授权和JS接口安全授权(挺繁琐的= =)
4. 开发自己的支付代码
5. 测试、完成

步骤1和步骤2就不说了,这个已经和代码无关了。
接下来用图片说明步骤3:
1).授权微信支付URL:
微信JSAPI支付(JAVA版)_第1张图片

2).OAuth2.0网页授权:
微信JSAPI支付(JAVA版)_第2张图片

3).JS接口安全授权
微信JSAPI支付(JAVA版)_第3张图片

步骤4(代码):
楼主也是参考”情本寂寞”这位大哥博客的,有兴趣的大家也可以看看哦^_^

首先来看微信开发文档的支付逻辑吧!
如图所示:
微信JSAPI支付(JAVA版)_第4张图片
要获得用户的code这个参数,获取这个参数就需要调用微信的授权接口(https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect),当然咯这个接口就是跟我们上面设置的OAuth2.0网页授权有关,如果没有设置就获取不了openid的哦!APPID换成自己的公众号appid、REDIRECT_URI换成需要回调的链接咯、SCOPE如果不需要记录用户的信息只是想获取code的话就用snsapi_base就可以了。

//获取openid的方法
public String wxgetOpenid(){
        String code = request.getParameter("code");
        //ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code" 获取openid的微信接口
        String urlstr = Constant.ACCESS_TOKEN.replace("APPID", Constant.APPID).replace("SECRET", Constant.APPSECRET).replace("CODE", code);

        URL url;
            url = new URL(urlstr);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.connect();
            // 取得输入流,并使用Reader读取
            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(),"utf-8"));
            String lines;
            StringBuilder sb = new StringBuilder();
            //接受返回的数据
            while ((lines = reader.readLine()) != null) {
                sb.append(lines);
            }
            reader.close();
            // 断开连接
            connection.disconnect();
            //json对象需要json.org的jar包
            JSONObject json;
            //可以直接解析需要导入org.json.jar这个包哦
            json = new JSONObject(sb.toString());
            //目前只需要用到openid
            openId = json.getString("openid");
            //楼主保存openid的方法是用到session来保存的,不知道有没有更好的idea呢,可以分享出来哦
            request.getSession().setAttribute("openid", openId);
        return SUCCESS;
    }

好咯,获取到openid之后就可以买东西,下订单,微信支付就可以等待快递收货了。哈哈
接下来讲在微信内置的浏览器里面调用微信支付JSAPI了
当用户买完商品之后进入选择页面点击支付发起JSPAI支付,如图:
微信JSAPI支付(JAVA版)_第5张图片
当点击微信支付之后,就可以调用‘统一下单的接口’->获取返回的数据->调用JSPAI进行支付
我的思路是这样的:
首先利用ajax调用微信的‘统一下单接口’,然后获取一些支付需要的信息(可以查看微信支付文档),ajax获取到回调的信息之后,利用JSAPI发起微信支付。
1).微信统一下单接口获取支付订单数据:
/*
* 1.根据订单号查询订单信息
* 2.填写微信接口需要的订单信息
* 3.订单信息加密
* 4.封装成XML、调用微信接口
* 5.获取返回的值和需要的值封装成json返回到客户端
*/
订单信息就不用说了,接下来我用map格式封装微信统一下单接口需要的格式

SortedMap parameters = new TreeMap();
        parameters.put("appid", Constant.APPID);
        parameters.put("mch_id", Constant.MCH_ID);
        parameters.put("device_info", "WEB");
        parameters.put("nonce_str", WXUtils.CreateNoncestr(32));
        parameters.put("attach", "新疆5票务网购票");
        parameters.put("body", "电子票券");
        parameters.put("out_trade_no", orderId);
        System.out.println(price);
//      parameters.put("total_fee", price);
        //测试填写1,微信默认为整形数字符串11分钱、101毛钱如此类推
        parameters.put("total_fee", "1");
        parameters.put("spbill_create_ip",WXUtils.getIpAddr(request));
        parameters.put("notify_url", Constant.NOTIFY_URL);
        parameters.put("trade_type", "JSAPI");
        //oppenid是在session里面获得的,所以才有了上面的授权页面了
        parameters.put("openid", openId);
        String sign = WXUtils.createSign("UTF-8", parameters);
        //把以上的信息进行键值对加密‘MD5’
        parameters.put("sign", sign);
        //把map里面的map对应的键值对变成MXL格式的字符串
        String requestXML = XMLMethods.getRequestXml(parameters);
        //调用微信接口下单,返回
        String result =WXUtils.httpsRequest(Constant.UNIFIED_ORDER_URL, "POST", requestXML);

map对应键的说明可以查看此表:
微信JSAPI支付(JAVA版)_第6张图片
2).支付订单数据result封装成json格式用于ajax回调数据

//获取到返回值,解析成map格式
            map = XMLMethods.doXMLParse(result);
            //把返回的值变成json格式
            SortedMap params = new TreeMap();
            params.put("appId", Constant.APPID);
            params.put("timeStamp", Long.toString(new Date().getTime()));
            params.put("nonceStr", WXUtils.CreateNoncestr(32));
            params.put("package", "prepay_id="+map.get("prepay_id"));
            params.put("signType", Constant.SIGN_TYPE);
            //注意paySign签名
            String paySign =  WXUtils.createSign("UTF-8", params);

            //封装参数,前端调用微信支付
            JSONObject json =new JSONObject();
            json.put("appId", Constant.APPID);
            json.put("timeStamp", params.get("timeStamp").toString());
            json.put("nonceStr", params.get("nonceStr").toString());
            json.put("package", "prepay_id="+map.get("prepay_id"));
            json.put("signType", Constant.SIGN_TYPE);
            json.put("paySign", paySign);   //paySign的生成规则和Sign的生成规则一致
            json.put("sendUrl", Constant.SUCCESS_URL);   //付款成功后,点击完成跳转的页面
            String userAgent = request.getHeader("user-agent");   //判断当前微信的版本
            char agent = userAgent.charAt(userAgent.indexOf("MicroMessenger")+15);
            json.put("agent", new String(new char[]{agent}));   //微信版本号,用于前面提到的判断用户手机微信的版本是否是5.0以上版本。
            data = json.toString();   //这个data格式是要在前端调用的哦!大家可以注意一下

3).前端调用JSAPI进行支付
当获取到data数据之后就可以调用微信支付了(注意咯,调用微信支付的方法需要在当前页引入一个JS文件:),而调用这个文件也需要授权的哦,我们在上面第一步就已经授权了,就是在JS接口安全域名那里,大家还记得么?^_^。

WeixinJSBridge.invoke('getBrandWCPayRequest',{  
                        "appId" : obj.appId,                //公众号API 
                        "timeStamp":obj.timeStamp,          //时间戳,自 1970 年以来的秒数  
                        "nonceStr" : obj.nonceStr,          //随机串  
                        "package" : obj.package,       //商品包信息
                        "signType" : obj.signType,          //微信签名方式
                        "paySign" : obj.paySign             //微信签名  
                    },function(res){
                        //当成功支付点击完成之后 
                        if(res.err_msg == "get_brand_wcpay_request:ok" ) {
                            //支付成功,处理成功的逻辑  
                            location = obj.sendUrl;  
                        }else{
                            //否则支付失败,处理失败的逻辑
                            alert("支付已取消");
                        }  
                    });

4).支付成功,微信端回调函数
请看下图正确处理的逻辑
微信JSAPI支付(JAVA版)_第7张图片
简单的一个回调代码如下:

InputStream inStream = request.getInputStream();
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            outSteam.close();
            inStream.close();
            String result  = new String(outSteam.toByteArray(),"utf-8");   //获取微信调用我们notify_url的返回信息
            Map map = XMLMethods.doXMLParse(result);
            //支付成功
            for(Object keyValue : map.keySet()){
                System.out.println(keyValue+"="+map.get(keyValue));
            }
            //微信端已支付,处理订单业务
            if (map.get("result_code").toString().equalsIgnoreCase("SUCCESS")){
                //处理自己的业务逻辑
                //发送信息给微信知道当前处理完业务逻辑、返回成功标识
                response.getWriter().write(WXUtils.setXML("SUCCESS", ""));   //告诉微信服务器,我收到信息了,不要在通知我了
            }

总结:
其实不管是微信支付,支付宝支付等大致的思想都是差不多的。变得只是处理的数据细节需要变化(注意数据的并发行为)只要在逻辑上多留个心眼,保证支付的安全性这基本就OK了^_^。
里面的工具类可以在这里下载哦,大家可以参考一下。
博客可能存在很多错误,大家请多多包含,有错的地方可以留言告知,大家一起进步咯。嘻嘻!

你可能感兴趣的:(微信)