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

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

#微信公众号或者小程序等的appid
appId: xxxxxxxxxxxxx
#微信支付商户号
mchId: xxxxxxxxxxxxx
# 证书
apiclient_key.pem: xxxxxxxxx
# 证书
apiclient_cert.pem: xxxxxxxxx
# apiV3key
apiV3key: xxxxxxxxxxxxxxxxxx

代码集成

pom坐标

 <!-- 微信支付 -->
        <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-pay</artifactId>
            <version>4.3.9.B</version>
        </dependency>

配置文件编写

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

配置类(微信配置实体)

@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;


}

配置类(微信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;
    }
}

微信支付工具类编写

@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";
    }
}
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值