springboot接入微信支付v3

本文详细介绍了如何在Java应用中集成微信支付APIv3,包括依赖管理、证书配置、支付接口(如nativePay和小程序支付)的实现以及支付回调的处理,重点展示了如何初始化配置和进行签名验证。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、引入包
<dependency>
            <groupId>com.github.wechatpay-apiv3</groupId>
            <artifactId>wechatpay-java</artifactId>
            <version>0.2.12</version>
</dependency>
2、导入证书,配置商家号等信息

3、初始化微信支付配置,这里会自动加载微信支付用到的类,并且完成签名认证等操作。

@Bean
    public Config config() throws IOException {
        //nginx转发
        requestUrl = properties.getRequestUrl();
        String path = CLASS_PATH + certPemPath;
        Resource resourceCert = resourceLoader.getResource(path);
        String privatePath = CLASS_PATH + privateKeyPath;
        Resource resourcePrivate = resourceLoader.getResource(privatePath);
        String privateKey = inputStreamToString(resourcePrivate.getInputStream());
        X509Certificate certificate = getCertificate(resourceCert.getInputStream());

        String merchantSerialNumber = certificate.getSerialNumber().toString(16).toUpperCase();
        RSAAutoCertificateConfig config = new RSAAutoCertificateConfig.Builder()
                .merchantId(merchantId)
                .privateKey(privateKey)
                .merchantSerialNumber(merchantSerialNumber)
                .apiV3Key(apiV3key)
                .build();
        return config;
    }

/**
     * 微信支付对象
     * @param config Config
     * @return JsapiService
     */
    @Bean
    public JsapiService jsapiService(Config config){
        log.info("==========加载微信支付对象");
        JsapiService service = new JsapiService.Builder().config(config).hostName().build();
        return service;
    }

 /**
     * 获取证书 将文件流转成证书文件
     *
     * @param inputStream 证书文件
     * @return {@link X509Certificate} 获取证书
     */
    public static X509Certificate getCertificate(InputStream inputStream) {
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X509");
            X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
            cert.checkValidity();
            return cert;
        } catch (CertificateExpiredException e) {
            throw new RuntimeException("证书已过期", e);
        } catch (CertificateNotYetValidException e) {
            throw new RuntimeException("证书尚未生效", e);
        } catch (CertificateException e) {
            throw new RuntimeException("无效的证书", e);
        }
    }
4、nativePay,返回二维码支付连接,前端转成二维码图片
public ResponseEntity<ResultMsg> nativePay(PayOrder order) {
        log.info("nativePay");
        
        /*根据规则生成订单号*/
        String outTradeNo = "DD"+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMddHHmmss"))+String.format("%04d", new Random().nextInt(10000));
        order.setOutTradeNo(outTradeNo);
        order.setTotalAmount(accRespGuar.getPayable());
        order.setStatus(String.valueOf(Transaction.TradeStateEnum.NOTPAY));
        orderService.save(order);
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        BigDecimal payMoney = order.getTotalAmount();
        BigDecimal amountTotal = payMoney.multiply(new BigDecimal("100").setScale(0, RoundingMode.DOWN));
        amount.setTotal(amountTotal.intValue());
        request.setAmount(amount);
        request.setTimeExpire(getExpiredTimeStr());
        request.setAppid(appId);
        request.setMchid(merchantId);
        request.setAttach(order.getOrderId());
        request.setDescription(order.getPayContent());
        request.setNotifyUrl(properties.getPayNotifyUrl());
        //这里生成流水号,后续用这个流水号与微信交互,查询订单状态
        request.setOutTradeNo(order.getOutTradeNo());
        PrepayResponse response;
        try {
            response = nativePayService.prepay(request);
        } catch (HttpException e) {
            log.error("微信下单发送HTTP请求失败,错误信息:{}", e.getHttpRequest());
            throw new MsgException("微信下单发送HTTP请求失败,"+e.getMessage(),ServiceEnum.acgp );
        } catch (ServiceException e) {
            // 服务返回状态小于200或大于等于300,例如500
            log.error("微信下单服务状态错误,错误信息:{}", e.getErrorMessage());
            throw new MsgException("微信下单服务状态错误,"+e.getMessage(), ServiceEnum.acgp);
        } catch (MalformedMessageException e) {
            // 服务返回成功,返回体类型不合法,或者解析返回体失败
            log.error("服务返回成功,返回体类型不合法,或者解析返回体失败,错误信息:{}", e.getMessage());
            throw new MsgException("服务返回成功,返回体类型不合法,或者解析返回体失败"+ e.getMessage(),ServiceEnum.acgp );
        }
        log.info("nativePay end");
        order.setCodeUrl(response.getCodeUrl());
        return ReturnUtils.NOSuccess(order);
    }
5、小程序支付
public ResponseEntity<ResultMsg> wxAppPay(PayOrder order, SecurityToken token) throws Exception {
        log.info("wxAppPay");
        
        /*根据规则生成订单号*/
        String outTradeNo = "DD"+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMddHHmmss"))+String.format("%04d", new Random().nextInt(10000));
        order.setOutTradeNo(outTradeNo);
        order.setTotalAmount(accRespGuar.getPayable());
        order.setStatus(String.valueOf(Transaction.TradeStateEnum.NOTPAY));
        orderService.save(order);
        com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest request = new com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest();
        com.wechat.pay.java.service.payments.jsapi.model.Amount amount = new com.wechat.pay.java.service.payments.jsapi.model.Amount();
        BigDecimal payMoney = order.getTotalAmount();
        BigDecimal amountTotal = payMoney.multiply(new BigDecimal("100").setScale(0, RoundingMode.DOWN));
        amount.setTotal(amountTotal.intValue());
        request.setAmount(amount);
        request.setTimeExpire(getExpiredTimeStr());
        request.setAppid(appId);
        request.setMchid(merchantId);
        request.setAttach(order.getOrderId());
        request.setDescription(order.getPayContent());
        request.setNotifyUrl(properties.getPayNotifyUrl());
        //这里生成流水号,后续用这个流水号与微信交互,查询订单状态
        request.setOutTradeNo(order.getOutTradeNo());
        Payer payer = new Payer();
        payer.setOpenid(token.getOpenid());
        request.setPayer(payer);
        com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse  response;
        try {
            response = jsapiService.prepay(request);
        } catch (HttpException e) {
            log.error("微信下单发送HTTP请求失败,错误信息:{}", e.getHttpRequest());
            throw new MsgException("微信下单发送HTTP请求失败,"+e.getMessage(),ServiceEnum.acgp );
        } catch (ServiceException e) {
            // 服务返回状态小于200或大于等于300,例如500
            log.error("微信下单服务状态错误,错误信息:{}", e.getErrorMessage());
            throw new MsgException("微信下单服务状态错误,"+e.getMessage(), ServiceEnum.acgp);
        } catch (MalformedMessageException e) {
            // 服务返回成功,返回体类型不合法,或者解析返回体失败
            log.error("服务返回成功,返回体类型不合法,或者解析返回体失败,错误信息:{}", e.getMessage());
            throw new MsgException("服务返回成功,返回体类型不合法,或者解析返回体失败"+ e.getMessage(),ServiceEnum.acgp );
        }
        log.info("wxAppPay end");
        // 需要的全部请求参数
        String prepayId = response.getPrepayId();//下单返回的prepayId
        long timestamp = Instant.now().getEpochSecond();
        String nonceStr = NonceUtil.createNonce(32);;//随机字符串
        String packageVal = "prepay_id=" + prepayId;
        String message =
                appId + "\n" + timestamp + "\n" + nonceStr + "\n" + packageVal + "\n";
        log.debug("Message for RequestPayment signatures is[{}]", message);
        String sign = signer.sign(message).getSign();
        order.setPrepayId(packageVal);
        order.setSignType("RSA");
        order.setPaySign(sign);
        order.setNonceStr(nonceStr);
        order.setTimeStamp(String.valueOf(timestamp));
        return ReturnUtils.NOSuccess(order);
    }
6、支付回调,本地调试可以使用内网穿透工具
public Object payCallBack(HttpServletRequest request) throws IOException {
        Map<String,String> resultMap = new HashMap<>();
        String wechatPaySerial = request.getHeader("Wechatpay-Serial");
        String wechatpayNonce = request.getHeader("Wechatpay-Nonce");
        String wechatSignature = request.getHeader("WechatPay-Signature");
        String wechatTimestamp = request.getHeader("Wechatpay-Timestamp");
        StringBuilder requestBody = new StringBuilder();
        BufferedReader reader = request.getReader();
        String line;
        while ((line = reader.readLine()) != null) {
            requestBody.append(line);
        }
        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(wechatPaySerial)
                .nonce(wechatpayNonce)
                .signature(wechatSignature)
                .timestamp(wechatTimestamp)
                .body(requestBody.toString())
                .build();
        try {
            // 以支付通知回调为例,验签、解密并转换成 Transaction
            Transaction transaction = notificationParser.parse(requestParam, Transaction.class);
                /*更新订单状态*/
            orderService.update(new UpdateWrapper<PayOrder>().set("status",transaction.getTradeState()).eq("out_trade_no",transaction.getOutTradeNo()));
            PayPaymentRecord paymentRecord = new PayPaymentRecord();
            String paymentNo = "ZF"+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMddHHmmss"))+String.format("%04d", new Random().nextInt(10000));
            PayOrder payOrder = orderService.getOne(new LambdaQueryWrapper<PayOrder>().eq(PayOrder::getOutTradeNo, transaction.getOutTradeNo()));
            paymentRecord.setOrderId(payOrder.getOrderId());
            paymentRecord.setPaymentStatus(Transaction.TradeStateEnum.SUCCESS.toString());
            paymentRecord.setPayerTotal(new BigDecimal(transaction.getAmount().getPayerTotal()).divide(BigDecimalUtils.NUM_100));
            paymentRecord.setPaymentTime(transaction.getSuccessTime());
            paymentRecord.setPaymentNo(paymentNo);
            paymentRecordService.save(paymentRecord);
            /*处理业务*/
           

        } catch (ValidationException e) {
            // 签名验证失败,返回 401 UNAUTHORIZED 状态码
            log.error("签名验证失败 sign verification failed", e);
            resultMap.put("code","ERROR");
            resultMap.put("message",e.getMessage());
            return resultMap;
        }

       /* // 如果处理失败,应返回 4xx/5xx 的状态码,例如 500 INTERNAL_SERVER_ERROR
        if (*//* process error *//*) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR);
        }*/
        resultMap.put("code","SUCCESS");
        resultMap.put("message","");
        return resultMap;
    }
7、官方api地址

JSAPI下单 - JSAPI支付 | 微信支付商户文档中心

GitHub - wechatpay-apiv3/wechatpay-java: 微信支付 APIv3 的官方 Java Library

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值