【微信支付】jsApi支付 V3版本(附代码)

1、接入前的准备

官方文档地址
jsapi下单官方文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml

jsapi调起支付官方文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml

jsapi支付通知回调文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtml

接入前的准备:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_1.shtml

公众号绑定商户号(略)

登录商户号配置v3秘钥
在这里插入图片描述

登录商户号配置商户证书
流程比较多,可以看官方提供的步骤操作,操作完后本地会生成三个证书文件
在这里插入图片描述

登录商户号设置支付授权目录
在这里插入图片描述

登录公众号后台设置授权域名
在这里插入图片描述

2、引入jar

我这里用的是gradle

implementation 'com.github.wechatpay-apiv3:wechatpay-apache-httpclient:0.4.2'
implementation group: 'com.github.binarywang', name: 'weixin-java-common', version: '3.3.0'

3、创建三个工具方法

构造jsApi下单请求参数


/**
    * 构造微信JsApi付款的json
    * @param appid
    * @param mchid
    * @param description
    * @param out_trade_no
    * @param notify_url
    * @param amount
    * @return
    */
   public static JSONObject buildWxJsApiPayJson(String appid , String mchid , String description , String out_trade_no , String notify_url , String amount, String openId){
 
       //订单金额json
       JSONObject amountJson = new JSONObject();
       amountJson.put("total",Integer.valueOf(amount));
       amountJson.put("currency","CNY");
 
 
       //支付者json
       JSONObject payerJson = new JSONObject();
       payerJson.put("openid",openId);
 
       //基础信息json
       JSONObject json = new JSONObject();
       json.put("appid",appid);
       json.put("mchid",mchid);
       json.put("description",description);
       json.put("out_trade_no",out_trade_no);
       json.put("notify_url",notify_url);
       json.put("amount",amountJson);
       json.put("payer",payerJson);
       return json;
   }

创建下单httpClient方法:

/**
*wxMchid商户号
*wxCertno证书编号
*wxCertPath证书地址
*wxPaternerKey   v3秘钥
*url jsapi下单地址
*body 构造好的消息体
*/
public static JSONObject doPostWexinV3(String wxMchid,String wxCertno,String wxCertPath,String wxPaternerKey,String url, String body) {
 
        // 自动更新证书功能
        AutoUpdateCertificatesVerifier verifier = null;
        try {
            // 名词解释:CERTNO:证书序列号;CERTPATH:证书在你服务器的地址(apiclient_key.pem)
            verifier = new AutoUpdateCertificatesVerifier(
                    new WechatPay2Credentials(wxMchid, new PrivateKeySigner(wxCertno,
                            PemUtil.loadPrivateKey(new FileInputStream(wxCertPath)))),
                    wxPaternerKey.getBytes("utf-8"));
        } catch (FileNotFoundException e) {
            System.err.println("证书未找到!=====================");
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            System.err.println("文件流错误!=====================");
            e.printStackTrace();
        }
 
        WechatPayHttpClientBuilder builder = null;
        try {
            builder = WechatPayHttpClientBuilder.create()
                    .withMerchant(wxMchid,wxCertno, PemUtil.loadPrivateKey(new FileInputStream(wxCertPath)))
                    .withValidator(new WechatPay2Validator(verifier));
        } catch (FileNotFoundException e) {
            System.err.println("证书未找到!=====================");
            e.printStackTrace();
        }
 
        HttpClient httpClient = builder.build();
        HttpPost httpPost  = new HttpPost(url);
        httpPost.addHeader("Content-Type","application/json;chartset=utf-8");
        httpPost.addHeader("Accept", "application/json");
        try{
            if(body==null){
                throw  new IllegalArgumentException("data参数不能为空");
            }
            StringEntity stringEntity = new StringEntity(body,"utf-8");
            httpPost.setEntity(stringEntity);
            // 直接执行execute方法,官方会自动处理签名和验签,并进行证书自动更新
            HttpResponse httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
 
            if(httpResponse.getStatusLine().getStatusCode() == 200){
                String jsonResult = EntityUtils.toString(httpEntity);
                return JSONObject.parseObject(jsonResult);
            }else{
                System.err.println("微信支付错误信息"+EntityUtils.toString(httpEntity));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

获取签名方法

/**
*wxCertPath证书地址
*prepay_id jsapi下单接口返回的参数
*/
public static JSONObject getTokenWeixin (String appId,String wxCertPath, String prepay_id) throws IOException, SignatureException, NoSuchAlgorithmException, InvalidKeyException, java.security.InvalidKeyException {
        // 获取随机字符串
        String nonceStr = getNonceStr();
        // 获取微信小程序支付package
        String packagestr = "prepay_id=" + prepay_id;
        long timestamp = System.currentTimeMillis() / 1000;
        //签名,使用字段appId、timeStamp、nonceStr、package计算得出的签名值
        String message = buildMessageTwo(appId,timestamp,nonceStr,packagestr);
        //获取对应的签名
        String signature = sign(wxCertPath,message.getBytes("utf-8"));
        // 组装返回
        JSONObject json = new JSONObject();
        json.put("timeStamp", String.valueOf(timestamp));
        json.put("nonceStr", nonceStr);
        json.put("package", packagestr);
        json.put("signType", "RSA");
        json.put("paySign", signature);
        json.put("appId", appId);
 
        return json;
    }
 
 
    public static String getNonceStr(){
        return UUID.randomUUID().toString()
                .replaceAll("-", "")
                .substring(0, 32);
    }
    private static String buildMessageTwo(String appId, long timestamp, String nonceStr, String packag) {
        return appId + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + packag + "\n";
    }
    private static String sign(String wxCertPath,byte[] message) throws NoSuchAlgorithmException, SignatureException, IOException, InvalidKeyException, java.security.InvalidKeyException {
        Signature sign = Signature.getInstance("SHA256withRSA"); //SHA256withRSA
        sign.initSign(PemUtil.loadPrivateKey(new FileInputStream(wxCertPath))); // 微信证书私钥
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }

4、获取微信加密签名控制层接口

给当前url鉴权,否则前端无法唤起支付窗口

    /**
     * 获取微信加密签名
     * @return
     */
    @PostMapping("getSignPackage")
    public ResponseResult getSignPackage(String url) {
        ResponseResult result = new ResponseResult<>();
        WxJsapiSignature jsapiSignature;
        if (StringUtils.isEmpty(url)) {
            return result.error(500,"缺少参数!");
        }
        try{
            jsapiSignature = createJsapiSignature(url);
        }catch (Exception e){
            logger.error("getSignPackage_error:"+e.getMessage());
             return result.error(500,"请求异常!");
        }

        return result.success(jsapiSignature);
    }
   /**
     * 微信加密签名参数拼装
     * @param url
     * @return
     * @throws Exception
     */
    public WxJsapiSignature createJsapiSignature(String url) throws Exception {
        long timestamp = System.currentTimeMillis() / 1000L;
        String randomStr = RandomUtils.getRandomStr();
        String jsapiTicket =getAccessToken();
        String signature = SHA1.genWithAmple(new String[]{"jsapi_ticket=" + jsapiTicket, "noncestr=" + randomStr, "timestamp=" + timestamp, "url=" + url});
        WxJsapiSignature jsapiSignature = new WxJsapiSignature();
        jsapiSignature.setAppId(wxAppid);
        jsapiSignature.setTimestamp(timestamp);
        jsapiSignature.setNonceStr(randomStr);
        jsapiSignature.setUrl(url);
        jsapiSignature.setSignature(signature);
        return jsapiSignature;
    }

5、创建下单控制层接口

//拼接微信支付参数
JSONObject requestJson = buildWxJsApiPayJson(wxAppid,wxMchid,rechargeType.getMealName(),orderNo,notifyUrl,amount,openid);
//发送post请求"统一下单接口"返回预支付id:prepay_id
//下单接口:https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
JSONObject stringObjectJson = doPostWexinV3(wxMchid,wxCertno,wxCertPath,wxPaternerKey,wxJsApiurl, requestJson.toJSONString());
JSONObject resJson = getTokenWeixin(wxAppid,wxCertPath, String.valueOf(stringObjectJson.get("prepay_id")));

return result.success(resJson);

6、创建支付回调控制层接口

/**
     * 微信回调接口
     * @param body
     * @param request
     * @return
     */
    @RequestMapping("wxJsApiCallback")
    public Map wxJsApiCallback(@RequestBody Map body, HttpServletRequest request) {
        Map<String, Object> result = new HashMap();
        //1:获取微信支付回调的获取签名信息
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        String nonce = request.getHeader("Wechatpay-Nonce");
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            // 2: 开始解析报文体
            String data = objectMapper.writeValueAsString(body);
            String message = timestamp + "\n" + nonce + "\n" + data + "\n";
            //3:获取应答签名
            String sign = request.getHeader("Wechatpay-Signature");
            //4:获取平台对应的证书
            String serialNo = request.getHeader("Wechatpay-Serial");
            Map<String, String> resource = (Map) body.get("resource");
            // 5:回调报文解密
            AesUtil aesUtil = new AesUtil(wxPaternerKey.getBytes());
            //解密后json字符串
            String decryptToString = aesUtil.decryptToString(
                    resource.get("associated_data").getBytes(),
                    resource.get("nonce").getBytes(),
                    resource.get("ciphertext"));
            //6:获取微信支付返回的信息
            com.alibaba.fastjson.JSONObject jsonData = com.alibaba.fastjson.JSONObject.parseObject(decryptToString);
            logger.info("wxJsApiCallback responseJson:" + jsonData.toJSONString());
            //7: 支付状态的判断 如果是success就代表支付成功
            if ("SUCCESS".equals(jsonData.get("trade_state"))) {
                // 8:获取支付的交易单号,流水号,和附属参数
                String out_trade_no = jsonData.get("out_trade_no").toString();
                String transaction_id = jsonData.get("transaction_id").toString();
                com.alibaba.fastjson.JSONObject amount = jsonData.getJSONObject("amount");// 订单金额信息
                int payMoney = amount.getIntValue("payer_total"); //实际支付金额
                // 成功处理
            }else{
                // 失败处理

            }
            result.put("code", "SUCCESS");
            result.put("message", "成功");
        } catch (Exception e) {
            result.put("code", "fail");
            result.put("message", "系统错误");
            e.printStackTrace();
        }
        return result;
    }
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值