当前位置:   article > 正文

微信支付V3版本weixin-java-pay集成调用(APP调用)(含二次加签)

weixin-java-pay

准备工作(准备如下信息)

#微信公众号或者小程序等的appid
appId: xxxxxxxxxxxxx
#微信支付商户号
mchId: xxxxxxxxxxxxx
# 证书
apiclient_key.pem: xxxxxxxxx
# 证书
apiclient_cert.pem: xxxxxxxxx
# apiV3key
apiV3key: xxxxxxxxxxxxxxxxxx
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

代码集成

pom坐标

 <!-- 微信支付 -->
        <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-pay</artifactId>
            <version>4.3.9.B</version>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

配置文件编写

wx:
  pay:
    #微信公众号或者小程序等的appid
    appId: xxxxxxxxxxxxxxxxxxxxx
    #微信支付商户号
    mchId: xxxxxxxxxxxxxxxxxxx
    # 证书相对路径 (以classpath:开头)
    privateKeyPath: classpath:/dev/apiclient_key.pem
    # 证书相对路径 (以classpath:开头)商户私钥
    privateCertPath: classpath:/dev/apiclient_cert.pem
    #支付回调通知地址
    returnUrl: http://xxxxxxxxxx/wxPay/callBack
    #    退款回调地址
    refundUrl: http://xxxxxxxxxx/wxPay/refund
    # apiV3key
    apiV3key: xxxxxxxxxxxxxxxxxxxxxxxx
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

配置类(微信配置实体)

@Data
@Configuration
public class WxPayProperties {
    /**
     * 设置微信公众号或者小程序等的appid
     */
    @Value("${wx.pay.appId}")
    private String appId;
    /**
     * 微信支付商户号
     */
    @Value("${wx.pay.mchId}")
    private String mchId;

    /**
     * 证书相对路径
     */
    @Value("${wx.pay.privateKeyPath}")
    private String privateKeyPath;

    /**
     * 证书相对路径
     */
    @Value("${wx.pay.privateCertPath}")
    private String privateCertPath;

    /**
     * 下单回调地址
     */
    @Value("${wx.pay.returnUrl}")
    private String returnUrl;

    /**
     * 退款回调地址
     */
    @Value("${wx.pay.refundUrl}")
    private String refundUrl;


    /**
     * apiV3key
     */
    @Value("${wx.pay.apiV3key}")
    private String apiV3key;


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

配置类(微信PayService-Bean注入)

@Configuration
@ConditionalOnClass(WxPayService.class)
public class WxPayConfiguration {
    @Autowired
    private  WxPayProperties properties;

    @Autowired
    public WxPayConfiguration(WxPayProperties properties) {
        this.properties = properties;
    }

    @Bean
    @ConditionalOnMissingBean
    public WxPayService wxService() {
        WxPayService wxPayService = new WxPayServiceImpl();
        wxPayService.setConfig(wxPayConfig());
        return wxPayService;
    }

    @Bean
    public WxPayConfig wxPayConfig() {
        WxPayConfig payConfig = new WxPayConfig();
        payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId()));
        payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));
        payConfig.setPrivateKeyPath(this.properties.getPrivateKeyPath());
        payConfig.setPrivateCertPath(this.properties.getPrivateCertPath());
        payConfig.setApiV3Key(this.properties.getApiV3key());
        // 可以指定是否使用沙箱环境
        payConfig.setUseSandboxEnv(false);
        return payConfig;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

微信支付工具类编写

@Component
@Slf4j
public class WxPayUtil {
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private WxPayProperties wxPayProperties;

    /**
     * 统一支付下单接口
     *
     * @param outTradeNo     商户订单号
     * @param totalFee       下单金额(单位:分)
     * @param productContent 商品描述
     */
    public Map<String, String> createOrder(String outTradeNo, Integer totalFee, String productContent) {
        WxPayUnifiedOrderV3Request wxPayUnifiedOrderV3Request = new WxPayUnifiedOrderV3Request();
        wxPayUnifiedOrderV3Request.setDescription(productContent);
        WxPayUnifiedOrderV3Request.Amount amount = new WxPayUnifiedOrderV3Request.Amount();
        amount.setTotal(totalFee);
        wxPayUnifiedOrderV3Request.setAmount(amount);
        wxPayUnifiedOrderV3Request.setOutTradeNo(outTradeNo);
        wxPayUnifiedOrderV3Request.setNotifyUrl(wxPayProperties.getReturnUrl());
        try {
            WxPayUnifiedOrderV3Result.AppResult appResult = wxPayService.createOrderV3(TradeTypeEnum.APP, wxPayUnifiedOrderV3Request);
            return this.startWXPay(appResult);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 商户订单号查询订单  微信官方文档: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_2.shtml
     *
     * @param outTradeNo     商户订单号
     * @return  WxPayOrderQueryV3Result 返回对象
     */
    public WxPayOrderQueryV3Result selectOrder(String outTradeNo) {
        WxPayOrderQueryV3Request wxPayOrderQueryV3Request = new WxPayOrderQueryV3Request();
        wxPayOrderQueryV3Request.setOutTradeNo(outTradeNo);
        try {
            return wxPayService.queryOrderV3(wxPayOrderQueryV3Request);
        } catch (WxPayException e) {
           throw new RuntimeException(e.getMessage());
        }
    }


    /**
     * 退款调用
     *
     * @param outTradeNo     商户订单号
     * @param outRefundNo    商户退款单号
     * @param reason    退款原因
     * @param refund    退款金额(单位:分)
     * @param total    原订单金额(单位:分)
     * @return WxPayRefundV3Result 返回值参考: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_9.shtml
     */
    public WxPayRefundV3Result refundOrder(String outTradeNo, String outRefundNo, String reason,Integer refund,Integer total) {
        WxPayRefundV3Request wxPayRefundV3Request = new WxPayRefundV3Request();
        wxPayRefundV3Request.setOutTradeNo(outTradeNo);
        wxPayRefundV3Request.setOutRefundNo(outRefundNo);
        wxPayRefundV3Request.setReason(reason);
        wxPayRefundV3Request.setNotifyUrl(wxPayProperties.getRefundUrl());
        WxPayRefundV3Request.Amount amount = new WxPayRefundV3Request.Amount();
        amount.setRefund(refund);
        amount.setTotal(total);
        amount.setCurrency("CNY");
        wxPayRefundV3Request.setAmount(amount);
        try {
            return  wxPayService.refundV3(wxPayRefundV3Request);
        } catch (WxPayException e) {
            throw new RuntimeException(e.getMessage());
        }
    }


    /**
     * 封装二次加签数据
     *
     * @param appResult 预下单数据
     * @return Map 返回值
     */
    public Map<String, String> startWXPay(WxPayUnifiedOrderV3Result.AppResult appResult) {
        Map<String, String> map = new HashMap<>();
        //时间戳
        long timestamp = System.currentTimeMillis() / 1000;
        String token = getSign(appResult.getNoncestr(), appResult.getAppid(), appResult.getPrepayId(), timestamp);
        map.put("appid", appResult.getAppid());
        map.put("partnerid", appResult.getPartnerId());
        map.put("prepayid", appResult.getPrepayId());
        map.put("package", appResult.getPackageValue());
        map.put("noncestr", appResult.getNoncestr());
        map.put("timestamp", String.valueOf(timestamp));
        map.put("sign", token);
        return map;
    }

    /**
     * 获取签名
     *
     * @param nonceStr  随机数
     * @param appId     微信公众号或者小程序等的appid
     * @param prepay_id 预支付交易会话ID
     * @param timestamp 时间戳 10位
     * @return String 新签名
     */
    String getSign(String nonceStr, String appId, String prepay_id, long timestamp) {

        //从下往上依次生成
        String message = buildMessage(appId, timestamp, nonceStr, prepay_id);
        //签名
        try {
            return sign(message.getBytes("utf-8"));
        } catch (IOException e) {
            throw new RuntimeException("签名异常,请检查参数或商户私钥");
        }
    }

    String sign(byte[] message) {
        try {
            //签名方式
            Signature sign = Signature.getInstance("SHA256withRSA");
            //私钥,通过MyPrivateKey来获取,这是个静态类可以接调用方法 ,需要的是_key.pem文件的绝对路径配上文件名
            sign.initSign(wxPayService.getConfig().getPrivateKey());
            sign.update(message);
            return Base64.getEncoder().encodeToString(sign.sign());
        } catch (Exception e) {
            throw new RuntimeException("签名异常,请检查参数或商户私钥");
        }
    }

    /**
     * 按照前端签名文档规范进行排序,\n是换行
     *
     * @param nonceStr  随机数
     * @param appId     微信公众号或者小程序等的appid
     * @param prepay_id 预支付交易会话ID
     * @param timestamp 时间戳 10位
     * @return String 新签名
     */
    String buildMessage(String appId, long timestamp, String nonceStr, String prepay_id) {
        return appId + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + prepay_id + "\n";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/874187?site
推荐阅读
相关标签
  

闽ICP备14008679号