springlcoud微信小程序支付

微信小程序jsapi v3支付流程和如何实现代码 需要的配置参数有哪些

参数:

wx-pay:
  v3:
    #微信关联的小程序的appid
    appId: xxxxx
    #微信支付商户号
    mchId: xxxxxx
    #微信支付证书序列号
    serialnumber: xxxxxx
    #微信支付apiv3的密钥
    apiKey3: xxxxx
    #微信支付证书
    certKeyPath: /cert/xxxxx.pem
    #微信支付回调商户线上地址api
    notifyUrl: https://xxxxx/pay/callback 
    #微信支付关闭订单api
    closeOrderUrl: https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}/close
    #微信支付小程序预下单api
    jsApiUrl: https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
    #微信支付订单查询api
    queryOrder: https://api.mch.weixin.qq.com/v3/pay/transactions/id/

初始化服务

@Service
@Transactional
public class SysPayServiceImpl implements SysPayService {
    private static final Logger log = LoggerFactory.getLogger(SysPayServiceImpl.class);
    @Autowired
    private WxPayConfig wxPayConfig;
    //微信专业httpClient
    private static CloseableHttpClient httpClient;
    //生成签名用
    private static Sign sign;
    //证书管理器
    private static CertificatesManager certificatesManager;
    @Autowired
    private SysOrderDao sysOrderDao;

    //初始化微信支付的参数
    @PostConstruct
    public void init() throws Exception {
        //获取商户私钥
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(getFileInputStream(wxPayConfig.getCertKeyPath()));
        // 获取证书管理器实例
        certificatesManager = CertificatesManager.getInstance();
        sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, merchantPrivateKey.getEncoded(), null);
        // 向证书管理器增加需要自动更新平台证书的商户信息
        certificatesManager.putMerchant(wxPayConfig.getMchId(), new WechatPay2Credentials(wxPayConfig.getMchId(),
                new PrivateKeySigner(wxPayConfig.getSerialnumber(), merchantPrivateKey)), wxPayConfig.getApiKey3().getBytes(StandardCharsets.UTF_8));
        // 从证书管理器中获取verifier
        Verifier verifier = certificatesManager.getVerifier(wxPayConfig.getMchId());
        //用于构造HttpClient
        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                .withMerchant(wxPayConfig.getMchId(), wxPayConfig.getSerialnumber(), merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier));
        httpClient = builder.build();
    }
     /**
     * 使用getResourceAsStream直接从resources根路径下获取文件流
     * @param path
     */
    private InputStream getFileInputStream(String path) {
        InputStream in = this.getClass().getResourceAsStream(path);
        return in;
    }
}

预生成订单

//预订单生成返回给小程序请求参数
    @Override
    public AjaxResult prePay(WxPayDto dto) {

        log.info("微信小程序支付JSAPI预下单开始------");
        AjaxResult ajaxResult = AjaxResult.success();
        JSONObject obj = new JSONObject();
        //应用ID
        obj.put("appid", wxPayConfig.getAppId());
        //直连商户号
        obj.put("mchid", wxPayConfig.getMchId());
        //商品描述
        obj.put("description", dto.getDescription());
        //商户订单号
        obj.put("out_trade_no", dto.getOrderCode());
        //通知地址
        obj.put("notify_url", wxPayConfig.getNotifyUrl());

        //附加数据 查询API和支付通知中原样返回,可作为自定义参数使用,实际情况下只有支付完成状态才会返回该字段。
        Map<String, String> attach = new HashMap<>();
        attach.put("orderCode", dto.getOrderCode());
        obj.put("attach", JSON.toJSONString(attach));

        //订单金额
        JSONObject amount = new JSONObject();
        amount.put("total", dto.getPrice());
        obj.put("amount", amount);

        //支付者
        JSONObject payer = new JSONObject();
        payer.put("openid", dto.getOpenId());
        obj.put("payer", payer);

        log.info("微信小程序支付JSAPI预下单请求参数:{}" + obj.toJSONString());

        HttpPost httpPost = new HttpPost(wxPayConfig.getJsApiUrl());
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Content-type", "application/json; charset=utf-8");
        httpPost.setEntity(new StringEntity(obj.toJSONString(), "UTF-8"));

        String bodyAsString ;
        try {
            if(httpClient == null){
                log.info("微信小程序支付JSAPI预下单请求失败");
                return AjaxResult.error("预下单失败,请重试,无法连接微信支付服务器!" );
            }
            //执行请求
            CloseableHttpResponse response = httpClient.execute(httpPost);
            bodyAsString = EntityUtils.toString(response.getEntity());
        } catch (IOException e) {
            log.info("微信小程序支付JSAPI预下单请求失败{}", e.getMessage());
            return AjaxResult.error("预下单失败,请重试!" + e.getMessage());
        }
        String prePayId = JSONObject.parseObject(bodyAsString).getString("prepay_id");
        if (prePayId == null){
            String message = JSONObject.parseObject(bodyAsString).getString("message");
            log.info("微信小程序支付JSAPI预下单请求失败{}", message);
            return AjaxResult.error("预下单失败,请重试!" + message);
        }
        //准备小程序端的请求参数
        ajaxResult.put("appId", wxPayConfig.getAppId());
        String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
        ajaxResult.put("timeStamp", timeStamp);
        String nonceStr = IdUtil.fastSimpleUUID();
        ajaxResult.put("nonceStr", nonceStr);
        String packageStr = "prepay_id=" + prePayId;
        ajaxResult.put("package", packageStr);
        ajaxResult.put("signType", "RSA");
        String signString =  wxPayConfig.getAppId() + "\n" + timeStamp + "\n" + nonceStr + "\n" + packageStr + "\n";
        ajaxResult.put("paySign", Base64.encode(sign.sign(signString.getBytes())));
        return ajaxResult;
    }

回调

//微信支付回调通知
    @Override
    public void callback(HttpServletRequest servletRequest, HttpServletResponse response) {
        log.info("----------->微信支付回调开始");
        Map<String, String> map = new HashMap<>(12);
        String timeStamp = servletRequest.getHeader("Wechatpay-Timestamp");
        String nonce = servletRequest.getHeader("Wechatpay-Nonce");
        String signature = servletRequest.getHeader("Wechatpay-Signature");
        String certSn = servletRequest.getHeader("Wechatpay-Serial");

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(servletRequest.getInputStream()))) {
            StringBuilder stringBuilder = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                stringBuilder.append(line);
            }
            String obj = stringBuilder.toString();
            log.info("微信支付回调请求参数:{},{},{},{},{}", obj, timeStamp, nonce, signature, certSn);

            Verifier verifier = certificatesManager.getVerifier(wxPayConfig.getMchId());
            String sn = verifier.getValidCertificate().getSerialNumber().toString(16).toUpperCase(Locale.ROOT);
            NotificationRequest request = new NotificationRequest.Builder().withSerialNumber(sn)
                    .withNonce(nonce)
                    .withTimestamp(timeStamp)
                    .withSignature(signature)
                    .withBody(obj)
                    .build();
            NotificationHandler handler = new NotificationHandler(verifier, wxPayConfig.getApiKey3().getBytes(StandardCharsets.UTF_8));
            // 验签和解析请求体
            Notification notification = handler.parse(request);
            JSONObject res = JSON.parseObject(notification.getDecryptData());
            log.info("微信支付回调响应参数:{}", res.toJSONString());

            //做一些操作
            if (res != null) {
                //如果支付成功
                String tradeState = res.getString("trade_state");
                if("SUCCESS".equals(tradeState)){
                    //拿到商户订单号
                    String outTradeNo = res.getString("out_trade_no");
                    JSONObject amountJson = res.getJSONObject("amount");
                    Integer payerTotal = amountJson.getInteger("payer_total");
                    SysOrder sysOrder = sysOrderDao.queryByOrderCode(outTradeNo);
                    if(sysOrder != null){
                        if(sysOrder.getPayStatus() == 1){
                            //如果支付状态为1 说明订单已经支付成功了,直接响应微信服务器返回成功
                            response.setStatus(200);
                            map.put("code", "SUCCESS");
                            map.put("message", "SUCCESS");
                            response.setHeader("Content-type", ContentType.JSON.toString());
                            response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
                            response.flushBuffer();
                        }
                        //验证用户支付的金额和订单金额是否一致
                        if(payerTotal.equals(sysOrder.getOrderPrice())){
                            //修改订单状态
                            String successTime = res.getString("success_time");
                            sysOrder.setPayStatus(1);
                            sysOrderDao.update(sysOrder);
                            //响应微信服务器
                            response.setStatus(200);
                            map.put("code", "SUCCESS");
                            map.put("message", "SUCCESS");
                            response.setHeader("Content-type", ContentType.JSON.toString());
                            response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
                            response.flushBuffer();
                        }
                    }
                }
            }
            response.setStatus(500);
            map.put("code", "ERROR");
            map.put("message", "签名错误");
            response.setHeader("Content-type", ContentType.JSON.toString());
            response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
            response.flushBuffer();
        } catch (Exception e) {
            log.error("微信支付回调失败", e);
        }
    }

如果有用,请给个采纳,谢谢