1. 引入依赖

     <dependency>
            <groupId>com.github.wechatpay-apiv3</groupId>
            <artifactId>wechatpay-java</artifactId>
            <version>0.2.14</version>
        </dependency>

2. 新建微信配置类,具体数据更换为你自己的,私钥文件我是直接以字符串方式放在nacos的,所以config用的是.privateKey(privateKeyString),如果你要去指定路径读取文件需要用.privateKeyfrompath(String path)

JsapiService发起支付,NotificationParser解密,RefundService退款,你必须要先初始化,不然用不了
@Configuration
public class WechatPayConfig {
    /** 商户号 */
    @Value("${weixin.merchantId}")
    public  String merchantId;
    /** 商户API私钥路径 */
    @Value("${weixin.privateKeyString}")
    public  String privateKeyString;
    /** 商户证书序列号 */
    @Value("${weixin.merchantSerialNumber}")
    public  String merchantSerialNumber;
    /** 商户APIV3密钥 */
    @Value("${weixin.apiV3Key}")
    public  String apiV3Key;
    @Value("${weixin.appId}")
    public  String appId;


    @Value("${weixin.notifyUrl}")
    public  String notifyUrl;
    @Bean
    public JsapiService jsapiService(Config config){
        JsapiService service = new JsapiService.Builder().config(config).build();
        return service;
    }

    /**
     * 初始化退款service
     * **/
    @Bean
    public RefundService refundService(Config config){
        RefundService service = new RefundService.Builder().config(config).build();
        return service;
    }


    @Bean
    public Config config()
    {
        Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(merchantId)
                        .privateKey(privateKeyString)
                        .merchantSerialNumber(merchantSerialNumber)
                        .apiV3Key(apiV3Key)
                        .build();
        return config;
    }

    @Bean
    public NotificationParser notificationParser(Config config) {
        NotificationParser parser = new NotificationParser((NotificationConfig) config);
        return parser;
    }

    /**
     * 作用:使用字段appId、timeStamp、nonceStr、package计算得出的签名值
     * 场景:根据微信统一下单接口返回的 prepay_id 生成调启支付所需的签名值
     * @param appId
     * @param timestamp
     * @param nonceStr
     * @param pack package
     * @return
     * @throws Exception
     */
    public String getSign(String appId, long timestamp, String nonceStr, String pack) throws Exception{
        String message = buildMessage(appId, timestamp, nonceStr, pack);
        String paySign= sign(message.getBytes("utf-8"));
        return paySign;
    }

    private String buildMessage(String appId, long timestamp, String nonceStr, String pack) {
        return appId + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + pack + "\n";
    }
    private String sign(byte[] message) throws Exception{
        Signature sign = Signature.getInstance("SHA256withRSA");
        //这里需要一个PrivateKey类型的参数,就是商户的私钥。
        //获取商户私钥
        PrivateKey privateKey = PemUtil.loadPrivateKeyFromString(privateKeyString);
        sign.initSign(privateKey);
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }

}

3. 获取用户openid

调用微信预支付需要用户openid,最开始需要前端去获取一个code

然后后端拿到code后调用接口

        String result = HttpUtil.get("https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appId + "&secret=" + appSecret + "&code=" + weixinPayDto.getCode() + "&grant_type=authorization_code");
//        System.out.println("获取用户openid返回结果: " + result);
        JSONObject jsonObject = JSONObject.parseObject(result);
        String openid = jsonObject.getString("openid");

4. 发起调用,没有直接贴controller,openid放在weixinPayDto的userId里面的,返回给前端之后就可以拉起微信支付了

@Override
    public Result getWeixinPrepay(WeixinPayDto weixinPayDto) {
        PrepayRequest request = new PrepayRequest();
        //设置金额
        Amount amount = new Amount();
        amount.setTotal(Integer.parseInt(weixinPayDto.getTotalAmount()));
        request.setAmount(amount);
        //设置必要信息
        request.setAppid(wechatPayConfig.appId);
        request.setMchid(wechatPayConfig.merchantId);
        request.setDescription("测试商品标题");
        request.setNotifyUrl(wechatPayConfig.notifyUrl);
        request.setOutTradeNo(weixinPayDto.getOutTradeNo());
        //设置发起调用的用户
        Payer payer = new Payer();
        payer.setOpenid(weixinPayDto.getUserId());
        request.setPayer(payer);
        try {
            PrepayResponse response = jsapiService.prepay(request);
            //新增微信订单
            Boolean aBoolean = insertOrder(weixinPayDto);
            if (aBoolean) {
                // 需要的全部请求参数
                String prepayId = response.getPrepayId();//下单返回的prepayId
                long timestamp = System.currentTimeMillis();//时间戳
                String nonceStr = System.currentTimeMillis() + "";//随机字符串
                String pack = StringUtils.join("prepay_id=", prepayId);//订单详情扩展字符串
                String paySign = null;
                //获取签名
                paySign = wechatPayConfig.getSign(wechatPayConfig.appId, timestamp, nonceStr, pack);//签名
                //以指定格式返回前端
                JSONObject data = new JSONObject();
                data.put("appId", wechatPayConfig.appId);//appid
                data.put("timeStamp", String.valueOf(timestamp));
                data.put("nonceStr", nonceStr);
                data.put("prepayId", prepayId);
                data.put("package", pack);
                data.put("signType", "RSA");//签名方式
                data.put("paySign", paySign);
                return Result.ok(data, 200, "获取微信预支付交易会话id成功");
            }
            return Result.error(500, "支付订单金额错误,请尝试重新下单");
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error(500, "获取微信预支付交易会话id失败:" + e);
        }
    }

5. 用户支付后的回调,支付回调地址在上一步发起支付时已经配置了,接下来是收到微信回调解密了,需要给微信返回是否成功,不然会重试

    @PostMapping("/weixinPayNotify")
    public void pay_notify(@RequestBody String body,HttpServletRequest request, HttpServletResponse response) throws Exception {
        weixinPayService.weixinPayNotify(body,request,response);
    }


 


@Override
    public void weixinPayNotify(String body, HttpServletRequest request, HttpServletResponse response) throws Exception {
        //获取报文
        //随机串
        String nonceStr = request.getHeader("Wechatpay-Nonce");
        //微信传递过来的签名
        String signature = request.getHeader("Wechatpay-Signature");
        //证书序列号(微信平台)
        String serialNo = request.getHeader("Wechatpay-Serial");
        //时间戳
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        InputStream is = null;
        try {
            is = request.getInputStream();
            // 构造 RequestParam
            com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder()
                    .serialNumber(serialNo)
                    .nonce(nonceStr)
                    .signature(signature)
                    .timestamp(timestamp)
                    .body(body)
                    .build();
            // 如果已经初始化了 RSAAutoCertificateConfig,可以直接使用  config
            // 初始化 NotificationParser
            // 验签、解密并转换成 Transaction
            Transaction transaction = notificationParser.parse(requestParam, Transaction.class);
            //记录日志信息
            Transaction.TradeStateEnum state = transaction.getTradeState();
            String orderNo = transaction.getOutTradeNo();
            System.out.println("订单号:" + orderNo);
            if (state == Transaction.TradeStateEnum.SUCCESS) {
                System.out.println("支付成功");
                //TODO------
                //根据自己的需求处理相应的业务逻辑,异步
                JSONObject jsonObject = JSONObject.parseObject(transaction.toString());
                System.out.println("微信支付回调信息:" + jsonObject);
                JSONObject resultJson = new JSONObject();
                resultJson.put("out_trade_no", jsonObject.getString("out_trade_no"));
                resultJson.put("trade_state", jsonObject.getString("trade_state"));
                //业务处理
                BywOrder bywOrder = new BywOrder();
                bywOrder.setOrderId(jsonObject.getString("out_trade_no"));
                bywOrder.setPaymentStatus(jsonObject.getString("trade_state"));
                int i = bywOrderMapper.updateBywOrder(bywOrder);
                if (i > 0) {
                    rabbitTemplate.convertAndSend("payExchange", "alipay", resultJson.toJSONString());
                }
                //通知微信回调成功
                response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");
            } else {
                System.out.println("微信回调失败,JsapiPayController.payNotify.transaction:" + transaction.toString());
                //通知微信回调失败
                response.getWriter().write("<xml><return_code><![CDATA[FAIL]]></return_code></xml>");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            is.close();
        }
    }

这样就可以直接调用了,后续会出jsapi退款相关教程,支付宝支付窗支付相关教程,大家可以持续关注,获取code文档,下单文档、官方demo都在里面了

技术文档:wechatpay-apiv3/wechatpay-java: 微信支付 APIv3 的官方 Java Library

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

微信网页开发 / 网页授权

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐