最近对项目中的微信支付功能做了升级,之前使用的是V2版本。V2版本目前还可以使用,但已暂停更新。V3版本的集成,官方文档还是比较清晰的,但各类的配置,一个不小心就掉坑里半天爬不出来。趁着思路清晰,特此记录一下。
V2版本参数格式是xml格式,不太好维护,V3版本已改成json格式。
V2版本的签名是拼在参数里面的,V3版本校验都放在配置类里面了,更加方便灵活。
官方文档:
https://pay.weixin.qq.com/wiki/doc/apiv3/index.shtml
微信提供两种集成方式:wechatpay-java(推荐);wechatpay-apache-httpclient,以推荐的方式为例:
<dependency> <groupId>com.github.wechatpay-apiv3</groupId> <artifactId>wechatpay-java</artifactId> <version>0.2.5</version></dependency>
使用自动更新平台证书的配置类 RSAAutoCertificateConfig。注:每个商户号只能创建一个 RSAAutoCertificateConfig。
代码实现,将配置交由Spring统一管理,单例模式保证初始化一次。
@Configurationpublic class WXPayConfig { private Config config; @PostConstruct public void init(){ config = new RSAAutoCertificateConfig.Builder() .merchantId(WXPayConstants.MCHID) .privateKey(WXPayConstants.PRIVATE_KEY) .merchantSerialNumber(WXPayConstants.MERCHANT_SERIAL_NUMBER) .apiV3Key(WXPayConstants.API_V3_KEY) .build(); } @Bean("h5Service") public H5Service getH5Service(){ // H5支付 return new H5Service.Builder().config(config).build(); } @Bean("jsService") public JsapiServiceExtension getJsService(){ // 微信js支付 return new JsapiServiceExtension.Builder() .config(config) .signType("RSA") // 不填则默认为RSA .build(); } @Bean("appService") public AppServiceExtension getAppService() { // App支付 return new AppServiceExtension.Builder().config(config).build(); } @Bean("NotificationParser") public NotificationParser getNotificationParser(){ // 支付回调的解析器 return new NotificationParser((NotificationConfig)config); }}
/** * 获取微信支付参数(APP) */public WechatPayDTO getWechatAppPayParam(BigDecimal money, String orderNumber, String notifyUrl) throws Exception { // 下单 com.wechat.pay.java.service.payments.app.model.PrepayRequest request = new com.wechat.pay.java.service.payments.app.model.PrepayRequest(); com.wechat.pay.java.service.payments.app.model.Amount amount = new com.wechat.pay.java.service.payments.app.model.Amount(); amount.setTotal(Integer.parseInt(totalFee(money))); amount.setCurrency("CNY"); request.setAmount(amount); request.setAppid(WXPayConstants.APPID); request.setMchid(WXPayConstants.MCHID); request.setDescription(""); request.setNotifyUrl(notifyUrl); request.setOutTradeNo(orderNumber); com.wechat.pay.java.service.payments.app.model.PrepayWithRequestPaymentResponse response = appService.prepayWithRequestPayment(request); return WechatPayDTO.builder() .appid(response.getAppid()) .partnerid(response.getPartnerId()) .prepayid(response.getPrepayId()) .packageVal(response.getPackageVal()) .timestamp(response.getTimestamp()) .noncestr(response.getNonceStr()) .sign(response.getSign()) .build();}
/** * 获取微信支付参数(公众号 小程序) */public WechatPayDTO getWechatJSAPIPayParam(String openid, BigDecimal money, String orderNumber, String notifyUrl) throws Exception { // 下单 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(); amount.setTotal(Integer.parseInt(totalFee(money))); amount.setCurrency("CNY"); request.setAmount(amount); request.setAppid(WXPayConstants.PUBLIC_APPID); request.setMchid(WXPayConstants.MCHID); request.setDescription(""); request.setNotifyUrl(notifyUrl); request.setOutTradeNo(orderNumber); Payer payer = new Payer(); payer.setOpenid(openid); request.setPayer(payer); PrepayWithRequestPaymentResponse response = jsService.prepayWithRequestPayment(request); logger.info("JS支付参数:{}", response.toString()); return WechatPayDTO.builder() .appid(response.getAppId()) .packageVal(response.getPackageVal()) .timestamp(response.getTimeStamp()) .noncestr(response.getNonceStr()) .signType(response.getSignType()) .paySign(response.getPaySign()) .build();}
/** * 获取微信H5支付连接 */public String getWechatH5PayUrl(BigDecimal money, String orderNumber, String notifyUrl) { // 下单 PrepayRequest request = new PrepayRequest(); Amount amount = new Amount(); amount.setTotal(Integer.parseInt(totalFee(money))); amount.setCurrency("CNY"); request.setAmount(amount); SceneInfo sceneInfo = new SceneInfo(); sceneInfo.setPayerClientIp(""); request.setSceneInfo(sceneInfo); request.setAppid(WXPayConstants.PUBLIC_APPID); request.setMchid(WXPayConstants.MCHID); request.setDescription(""); request.setNotifyUrl(notifyUrl); request.setOutTradeNo(orderNumber); // 调用接口 PrepayResponse response = h5Service.prepay(request); return response.getH5Url();}
获取 HTTP 请求头中的以下值,构建 RequestParam 。
获取 HTTP 请求体 body。切记不要用 JSON 对象序列化后的字符串,避免验签的 body 和原文不一致。
根据解密后的通知数据数据结构,构造解密对象类 DecryptObject 。支付结果通知解密对象类为 Transaction,退款结果通知解密对象类为 RefundNotification。
初始化 RSAAutoCertificateConfig(已在前文统一初始化)。
初始化 NotificationParser(已在前文统一初始化)。
使用请求参数 requestParam 和 DecryptObject.class ,调用 parser.parse 验签并解密报文。
RequestParam requestParam = new RequestParam.Builder() .serialNumber(request.getHeader("Wechatpay-Serial")) .nonce(request.getHeader("Wechatpay-Nonce")) .signature(request.getHeader("Wechatpay-Signature")) .timestamp(request.getHeader("Wechatpay-Timestamp")) .signType(request.getHeader("Wechatpay-Signature-Type")) .body(body) .build();Transaction transaction = notificationParser.parse(requestParam, Transaction.class);if (Objects.equals(transaction.getTradeState(), Transaction.TradeStateEnum.SUCCESS)){ //处理业务逻辑 //通知微信支付成功 wechatPayUtil.paySuccessful(response);}
本文链接:http://www.28at.com/showinfo-26-28348-0.html微信支付V3版本集成详解【避坑指南】
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com