springboot集成微信jsapi支付,使用v3接口,实现获取预支付交易id
springboot集成微信jsapi支付,使用v3接口,实现获取预支付交易id,code是由前端调用拼接的指定地址获取的,看一下文章下面三个文档
·
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

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