JVAV-SDK方式实现微信小程序支付接入
微信接入文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_1.shtml
一、获取小程序与支付的接入前准备
1.获取小程序appid
微信小程序后台获取地址 (qq.com)
2.获取微信支付商户号、证书、密钥
这里获取因为某些原因就不展示截屏了,下面这个微信文档的接入准备将的很详细
获取证书文档
我用的是APIV3支付密钥,看自己业务
二、后台接入配置
1.yml配置
wx:
#微信公众号或者小程序等的appid
appId: xxxxxxxxxxxxxxxxxx
#应用密钥
appSecret: xxxxxxxxxxxxxxxxxx
#微信支付商户号
merchantId: xxxxxxxxxxxxxxxxxx
#微信支付商户密钥
mchKey: xxxxxxxxxxxxxxxxxx
#商户证书目录
keyPath: xxxxxxxxxxxxxxxxxx
#商户API私钥路径 部署到centos后 /etc/wx-pay/apiclient_cert.pem
privateKeyPath: C:\Users\admin\Desktop\wx\apiclient_cert.pem
#商户API密钥证书路径 部署到centos后 /etc/wx-pay/apiclient_key.pem
wechatPayCertificatePath: C:\Users\admin\Desktop\wx\apiclient_key.pem
#商户证书序列号
merchantSerialNumber: xxxxxxxxxxxxxxxxxx
#商户APIV3密钥
apiV3Key: xxxxxxxxxxxxxxxxxx
2.实体注入配置
@Data
@Primary //覆盖 当有多个这个的WxPayProperties实现类 注入这个
@Configuration()
@PropertySource("classpath:application.yml") //读取配置文件
@ConfigurationProperties(prefix = "wx")
public class WXProperties {
/** appId : 微信公众号或者小程序等的appid */
private String appId;
/** appSecret : 应用密钥 */
private String appSecret;
/** mchId : 微信支付商户号 */
private String merchantId;
/** mchKey : 微信支付商户密钥 */
private String mchKey;
/** mchKey : 商户证书目录 */
private String keyPath ;
/**商户API私钥路径*/
private String privateKeyPath ;
/**商户API密钥证书路径*/
private String wechatPayCertificatePath ;
/** 商户证书序列号*/
private String merchantSerialNumber ;
/**商户APIV3密钥*/
private String apiV3Key ;
}
3.pom依赖
官网GitHub地址,里面的文档可以仔细阅读一下,很有帮助
使用 SDK 不需要计算请求签名和验证应答签名。详细代码可从 QuickStart 获得。
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
<version>0.2.9</version>
</dependency>
4.微信支付配置
(1)RSAConfig配置
public static String merchantId = "";
public static String privateKeyPath = "";
public static String merchantSerialNumber = "";
public static String wechatPayCertificatePath = "";
public static void main(String[] args) {
// 初始化商户配置
RSAConfig config =
new RSAConfig.Builder()
.merchantId(merchantId)
// 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
.privateKeyFromPath(privateKeyPath)
.merchantSerialNumber(merchantSerialNumber)
.wechatPayCertificatesFromPath(wechatPayCertificatePath)
.build();
}
(2)RSAAutoCertificateConfig配置(我自己用的配置)
@Resource
private WXProperties wxProperties;
private RSAAutoCertificateConfig rsaAutoCertificateConfig=null;
public static void main(String[] args) {
// 初始化商户配置
RSAAutoCertificateConfig config =
new RSAAutoCertificateConfig.Builder()
.merchantId(wxProperties.getMerchantId())
// 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
// .privateKeyFromPath(wxProperties.getPrivateKeyPath())
.privateKeyFromPath(wxProperties.getWechatPayCertificatePath())
.merchantSerialNumber(wxProperties.getMerchantSerialNumber())
// .wechatPayCertificatesFromPath(wechatPayCertificatePath)
.apiV3Key(wxProperties.getApiV3Key())
.build();
}
这两种配置选择一种,客服人员好像说不能两种同事使用,会抛异常
并且使用这两个配置中的一个那抹这个配置必须为单例的
本人写的方法,虽然懒,无所谓,刚出来的能多强啊
@Component
public class WXPayConfig {
@Resource
private WXProperties wxProperties;
private RSAAutoCertificateConfig rsaAutoCertificateConfig=null;
private synchronized RSAAutoCertificateConfig rsaAutoCertificateConfig(){
if (rsaAutoCertificateConfig==null) {
synchronized (Object.class) {
// 初始化商户配置
rsaAutoCertificateConfig =
new RSAAutoCertificateConfig.Builder()
.merchantId(wxProperties.getMerchantId())
// 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
// .privateKeyFromPath(wxProperties.getPrivateKeyPath())
.privateKeyFromPath(wxProperties.getWechatPayCertificatePath())
.merchantSerialNumber(wxProperties.getMerchantSerialNumber())
// .wechatPayCertificatesFromPath(wechatPayCertificatePath)
.apiV3Key(wxProperties.getApiV3Key())
.build();
}
}
return this.rsaAutoCertificateConfig;
}
/**
* 转账到零钱
* @return
*/
public TransferBatchService transferBatchService(){
TransferBatchService build = new TransferBatchService.Builder().config(rsaAutoCertificateConfig()).build();
return build;
}
/**
* 回调解析
* @return
*/
public NotificationParser notificationParser(){
NotificationParser build = new NotificationParser(rsaAutoCertificateConfig());
return build;
}
/**
* js下单
* @return
*/
public JsapiServiceExtension jsapiServiceExtension(){
JsapiServiceExtension build = new JsapiServiceExtension.Builder()
.config(rsaAutoCertificateConfig())
.signType("RSA")
.build();
return build;
}
三、我自己业务的支付实现
JS API 下单
controller
@Resource
private TransactionService transactionService;
/**
* 用户充值下单
*
* @param rechargeInfoLog 自己的业务充值记录表信息
* @return 微信支付API返回的对象,用于前端支付发起
*/
@PostMapping("/placeAnOrder")
private Result placeAnOrder(@Validated RechargeInfoLog rechargeInfoLog, String openid) {
Map<String, Object> map = transactionService.placeAnOrder(rechargeInfoLog, openid);
PrepayWithRequestPaymentResponse response = (PrepayWithRequestPaymentResponse) map.get("response");
return response == null ? error() : success(map);
}
service
@Resource
private WXProperties wxProperties;
@Resource
private WXPayConfig wxPayConfig;
/**
* 充值下单
*
* @param recharge
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Map<String,Object> placeAnOrder(RechargeInfoLog recharge, String openid) {
Map<String,Object> map = new HashMap<>();
PrepayWithRequestPaymentResponse response = null;
try {
/** 自己的业务逻辑*/
// ... 调用接口
/** Amount 金额
orderNum 自己业务系统的订单号
description 订单描述
openid 用户openid
notifyUrl 回调地址https */
response = prepayWithRequestPayment(Amount,
orderNum,
description,
openid,
"https://localhost/callback");
log.info(response.toString());
map.put("response",response);
map.put("orderId",orderNum);
} catch (HttpException e) { // 发送HTTP请求失败
// 调用e.getHttpRequest()获取请求打印日志或上报监控,更多方法见HttpException定义
} catch (com.wechat.pay.java.core.exception.ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
// 调用e.getResponseBody()获取返回体打印日志或上报监控,更多方法见ServiceException定义
} catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
// 调用e.getMessage()获取信息打印日志或上报监控,更多方法见MalformedMessageException定义
}
return map;
}
/**
* JSAPI支付下单,并返回JSAPI调起支付数据
payAmount 金额 单位分
orderId 自己业务系统的订单号
description 订单描述
openid 用户openid
notifyUrl 回调地址https
*/
private PrepayWithRequestPaymentResponse prepayWithRequestPayment(int payAmount,
@NotBlank String orderId,
@NotBlank String description,
String openid,
String notifyUrl) {
//微信支付SDK请求参数
PrepayRequest request = new PrepayRequest();
Amount amount = new Amount();
amount.setTotal(payAmount);
Payer payer = new Payer();
payer.setOpenid(openid);
request.setAppid(wxProperties.getAppId());
request.setOutTradeNo(orderId);
request.setMchid(wxProperties.getMerchantId());
request.setDescription(description);
request.setNotifyUrl(notifyUrl);
request.setAmount(amount);
request.setPayer(payer);
// 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
// 调用接口
return wxPayConfig.jsapiServiceExtension().prepayWithRequestPayment(request);
}
支付回调
controller
/**
* 商户订单号查询订单
*/
@PostMapping("/callback")
public String wxPaySuccessCallback(HttpServletRequest request, HttpServletResponse response) {
String msg = transactionService.wxPaySuccessCallback(request, response);
return msg;
}
支付查询与关闭
service
/**
* 微信支付订单号查询订单
*/
public Transaction queryOrderById(String wxTransactionId) {
//微信支付SDK请求参数
QueryOrderByIdRequest request = new QueryOrderByIdRequest();
request.setMchid(wxProperties.getMerchantId());
request.setTransactionId(wxTransactionId);
// 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
// 调用接口
return wxPayConfig.jsapiServiceExtension().queryOrderById(request);
}
/**
* 商户订单号查询订单
*/
public Transaction queryOrderByOutTradeNo(String outTradeNo) {
//微信支付SDK请求参数
QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
request.setMchid(wxProperties.getMerchantId());
request.setOutTradeNo(outTradeNo);
// 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
// 调用接口
return wxPayConfig.jsapiServiceExtension().queryOrderByOutTradeNo(request);
}
/**
* 关闭订单
*/
public void closeOrder(String outTradeNo) {
CloseOrderRequest request = new CloseOrderRequest();
request.setMchid(wxProperties.getMerchantId());
request.setOutTradeNo(outTradeNo);
// 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
// 调用接口
wxPayConfig.jsapiServiceExtension().closeOrder(request);
}
我的回调因为有点问题,我这边暂时做了一个订单处理接口,
前端支付完成或者取消支付去调用该业务接口处理该订单
@Override
public boolean handleOrderByNo(String orderId) {
boolean flag = false;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//调用微信查询订单api
Transaction transaction = queryOrderByOutTradeNo(orderId);
//判罚支付结果
if (transaction.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)) {
flag = handleOrder(transaction);
}eles{
//自己业务需求eg:
closeOrder(transaction.getOutTradeNo());
}
return flag;
}