微信JSAPI支付(JAVA版)

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

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

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

2).OAuth2.0网页授权:
OAuth2.0网页授权

3).JS接口安全授权
JS接口安全授权

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

首先来看微信开发文档的支付逻辑吧!
如图所示:
JSAPI支付
要获得用户的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支付,如图:
商品支付
当点击微信支付之后,就可以调用‘统一下单的接口’->获取返回的数据->调用JSPAI进行支付
我的思路是这样的:
首先利用ajax调用微信的‘统一下单接口’,然后获取一些支付需要的信息(可以查看微信支付文档),ajax获取到回调的信息之后,利用JSAPI发起微信支付。
1).微信统一下单接口获取支付订单数据:
/*
* 1.根据订单号查询订单信息
* 2.填写微信接口需要的订单信息
* 3.订单信息加密
* 4.封装成XML、调用微信接口
* 5.获取返回的值和需要的值封装成json返回到客户端
*/
订单信息就不用说了,接下来我用map格式封装微信统一下单接口需要的格式

SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();
        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对应键的说明可以查看此表:
对应参数
2).支付订单数据result封装成json格式用于ajax回调数据

//获取到返回值,解析成map格式
            map = XMLMethods.doXMLParse(result);
            //把返回的值变成json格式
            SortedMap<Object,Object> params = new TreeMap<Object,Object>();
            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文件:<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>),而调用这个文件也需要授权的哦,我们在上面第一步就已经授权了,就是在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).支付成功,微信端回调函数
请看下图正确处理的逻辑
回调处理的逻辑
简单的一个回调代码如下:

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<Object, Object> 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了^_^。
里面的工具类可以在这里下载哦,大家可以参考一下。
博客可能存在很多错误,大家请多多包含,有错的地方可以留言告知,大家一起进步咯。嘻嘻!

### 微信JSAPI支付集成概述 微信JSAPI支付是一种允许商家通过其公众号向用户收取费用的方式。为了成功实现这一功能,开发者需完成一系列准备工作并遵循特定流程[^1]。 #### 准备工作 在开始编码之前,确保已经完成了必要的前置条件: - 已注册成为微信公众平台的服务号,并开通了微信支付权限; - 获取商户ID (MCH_ID),AppID 和 AppSecret; - 完成证书下载与配置; 这些步骤对于后续开发至关重要,因为它们提供了身份验证所需的信息以及安全通信的基础。 #### Maven依赖安装 为了让Java应用程序能够调用微信支付接口,在项目的`pom.xml`文件中加入如下依赖项来引入官方提供的SDK库[^2]: ```xml <dependency> <groupId>com.github.wechatpay-apiv3</groupId> <artifactId>wechatpay-java</artifactId> <version>0.2.10</version> </dependency> ``` 这一步骤简化了HTTP请求构建过程中的签名计算和其他复杂操作。 #### 实现逻辑概览 整个交易流程大致分为以下几个部分: 1. **前端页面加载**:当用户访问含有付款按钮的网页时,服务器端会生成预付订单信息并通过统一下单API提交至微信后台获取prepay_id。 2. **客户端发起支付**:利用JavaScript SDK方法wx.chooseWXPay()携带上一步得到的结果唤起原生支付界面让用户确认金额并输入密码完成扣款动作。 3. **服务端回调通知处理**:一旦支付状态发生变化(无论成败),微信将会异步发送消息告知应用方以便更新数据库记录或执行其他业务逻辑。 以下是具体的代码片段用于展示如何创建一个简单的控制器类来进行上述交互: ```java import com.github.wechatpay.apiv3.WechatPayClient; // ... 导入更多包 ... @RestController @RequestMapping("/payment") public class PaymentController { private final WechatPayClient client; @Autowired public PaymentController(WechatPayClient client){ this.client = client; } /** * 创建预付订单并向微信申请prepay_id. */ @PostMapping("/createOrder") ResponseEntity<String> createOrder(@RequestBody OrderRequest request) throws Exception { UnifiedOrderResponse response = client.unifiedorder( new UnifiedOrderRequest() .setBody(request.getBody()) .setOutTradeNo(UUID.randomUUID().toString()) // 商户侧唯一订单编号 .setTotalFee((long)(request.getTotalAmount()*100)) // 单位转换为分 .setSpbillCreateIp(request.getRemoteAddr()) .setNotifyUrl("https://yourdomain.com/payment/notify") // 支付结果接收URL .setOpenid(request.getOpenid())); // 用户标识 Map<String, String> payParams = PayUtil.jsApiParameters(response); return ResponseEntity.ok(new ObjectMapper().writeValueAsString(payParams)); } } ``` 这段代码展示了如何使用`WechatPayClient`实例化对象并与之互动以发出统一订单请求,同时返回给前端所需的参数集合供下一步调用所必需。 #### 数据安全性考量 在整个过程中特别需要注意的是敏感数据的安全传输问题。建议采用HTTPS协议保障网络层面上的数据保密性和完整性;另外还要妥善保管私钥材料防止泄露风险发生。此外,针对某些特殊场景下的加解密需求可借助于第三方工具如[ijPay](https://github.com/javen205/ijPay)[^3] 来减轻负担提高效率。
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值