手把手教你springboot集成微信支付
20220727

最近要做一个微信小程序,需要微信支付,所以研究了下怎么在 java 上集成微信支付功能,特此记录下。
本文完整代码:点击跳转
准备工作
小程序开通微信支付
- 首先需要在微信支付的官网点击跳转上注册一个服务商
- 在服务商的管理页面中申请关联小程序,通过小程序的 appid 进行关联
- 进入微信公众平台,功能-微信支付中确认关联(如果服务商和小程序的注册主体不一样,还要经过微信的审核)
获取各种证书、密钥文件
这里比较麻烦,需要认真点。
目前微信支付的 api 有 V2 和 V3 两个版本,V2 是 xml 的数据结构不建议用了,很麻烦(虽然 V3 也不简单).
以下内容全部基于微信支付 V3 的版本
你需要获取如下东西:
- 商户 id:这个可以在小程序微信公众平台-功能-微信支付 页面中的已关联商户号中得到
- 商户密钥:这个需要在微信支付的管理后台中申请获取
- 证书编号: 同样在微信支付的管理后台中申请证书,申请证书后就会看到证书编号
- 证书私钥:上一步申请证书的时候同时也会获取到证书的公钥、私钥文件。开发中只需要私钥文件
代码开发
由于支付属于比较敏感的操作,所以建议将参数配置放在后台,前端请求获取到参数后直接调起微信支付。
整个微信支付流程如下:
实际开发中,小程序端的开发内容很少,98%的工作量都在后台。
准备请求 htpClient
虽然微信官方目前没有正式放出官方 sdk,但是 github 上已经有了 sdk 的仓库,目前正在开发中,地址.这个工具做了一定程度的封装,极大简化了加密解密证书配置等繁琐的操作。
和微信的请求需要做双向加密,因此要在系统启动时创建一个专用的 httpClient,用来调用微信支付 api.代码如下:
@PostConstruct
public void init() throws Exception {
log.info("私钥路径:{}", certKeyPath);
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream(certKeyPath));
// 获取证书管理器实例
certificatesManager = CertificatesManager.getInstance();
sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, merchantPrivateKey.getEncoded(), null);
// 向证书管理器增加需要自动更新平台证书的商户信息
certificatesManager.putMerchant(merchantId, new WechatPay2Credentials(merchantId,
new PrivateKeySigner(merchantSerialNumber, merchantPrivateKey)), apiV3Key.getBytes(StandardCharsets.UTF_8));
// 从证书管理器中获取verifier
Verifier verifier = certificatesManager.getVerifier(merchantId);
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(merchantId, merchantSerialNumber, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier));
httpClient = builder.build();
}
预定单生成并返回小程序请求参数
代码如下:
JSONObject obj = new JSONObject();
obj.put("mchid", merchantId);
obj.put("appid", appId);
obj.put("description", body.getDescription());
obj.put("out_trade_no", body.getSn());
obj.put("notify_url", "https://backend/asdfasdf/notify");
Map<String, String> attach = new HashMap<>();
attach.put("sn", body.getSn());
obj.put("attach", JSON.toJSONString(attach));
JSONObject amount = new JSONObject();
amount.put("total", body.getPrice().multiply(BigDecimal.valueOf(100)).intValue());
obj.put("amount", amount);
JSONObject payer = new JSONObject();
//放入用户的openId
payer.put("openid", "");
obj.put("payer", payer);
log.info("请求参数为:" + JSON.toJSONString(obj));
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
httpPost.setEntity(new StringEntity(obj.toJSONString(), "UTF-8"));
try {
CloseableHttpResponse response = httpClient.execute(httpPost);
String bodyAsString = EntityUtils.toString(response.getEntity());
String prePayId = JSONObject.parseObject(bodyAsString).getString("prepay_id");
//准备小程序端的请求参数
Map<String, String> map = new HashMap<>(6);
map.put("appId", appId);
String timeStamp = String.valueOf(now / 1000);
map.put("timeStamp", timeStamp);
String nonceStr = IdUtil.fastSimpleUUID();
map.put("nonceStr", nonceStr);
String packageStr = "prepay_id=" + prePayId;
map.put("package", packageStr);
map.put("signType", "RSA");
// 注意\n必须添加
map.put("paySign", Base64.encode(sign.sign(appId + "\n" + timeStamp + "\n" + nonceStr + "\n" + packageStr + "\n")));
return map;
} catch (IOException e) {
throw new RuntimeException(e);
}
注意在生成小程序请求参数 paySign 时,\n 必须添加
小程序端请求
小程序端获取请求参数后,直接调用wx.requestPayment(后台返回的参数),即可调起支付
支付成功回调
微信支付成功后,会通知服务端支付成功,通过之前配置的回调接口。注意回调接口必须为 https。
微信回调参数也是加密的,必须要经过解密后才能获取,代码如下:
注意:部分参数是通过请求头提供的,nginx 等代理在转发请求时可能会将请求头过滤掉,导致无法获取对应参数
@Override
public void notify(HttpServletRequest servletRequest) {
String timeStamp = servletRequest.getHeader("Wechatpay-Timestamp");
String nonce = servletRequest.getHeader("Wechatpay-Nonce");
String signature = servletRequest.getHeader("Wechatpay-Signature");
String certSn = servletRequest.getHeader("Wechatpay-Serial");
try (BufferedReader reader = new BufferedReader(new InputStreamReader(servletRequest.getInputStream()))) {
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
String obj = stringBuilder.toString();
log.info("回调数据:{},{},{},{},{}", obj, timeStamp, nonce, signature, certSn);
Verifier verifier = certificatesManager.getVerifier(merchantId);
String sn = verifier.getValidCertificate().getSerialNumber().toString(16).toUpperCase(Locale.ROOT);
NotificationRequest request = new NotificationRequest.Builder().withSerialNumber(sn)
.withNonce(nonce)
.withTimestamp(timeStamp)
.withSignature(signature)
.withBody(obj)
.build();
NotificationHandler handler = new NotificationHandler(verifier, apiV3Key.getBytes(StandardCharsets.UTF_8));
// 验签和解析请求体
Notification notification = handler.parse(request);
JSONObject res = JSON.parseObject(notification.getDecryptData());
//做一些操作
JSONObject attach = res.getJSONObject("attach");
} catch (Exception e) {
log.error("微信支付回调失败", e);
}
}
拓展
以上只有关键的支付和回调接口示例,其他的接口请求也是类似的,就不一一列出。
手把手教你springboot集成微信支付的更多相关文章
- 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_1-1.SpringBoot整合微信支付开发在线教育视频站点介绍
笔记 第一章项目介绍和前期准备 1.SpringBoot整合微信支付开发在线教育视频站点介绍 简介: 课程介绍,和小D课堂在线教育项目搭建开发 1.课程大纲介绍 2.微信支付项 ...
- 手把手教你springboot中导出数据到excel中
手把手教你springboot中导出数据到excel中 问题来源: 前一段时间公司的项目有个导出数据的需求,要求能够实现全部导出也可以多选批量导出(虽然不是我负责的,我自己研究了研究),我们的项目是x ...
- ***CodeIgniter集成微信支付(转)
微信支付Native扫码支付模式二之CodeIgniter集成篇 http://www.cnblogs.com/24la/p/wxpay-native-qrcode-codeigniter.html ...
- iOS开发集成微信支付
首先需要理清楚流程: 1.用户使用APP客户端,选择商品下单. 2.商户客户端(就是你做的APP)将用户的商品数据传给商户服务器,请求生成支付订单. 3.商户后台调用统一下单API向微信的服务器发送请 ...
- 关于ApiCloud的Superwebview在androidstudio中集成微信支付模块,提示模块未绑定的问题
前两天ApiCloud项目集成了微信支付模块,android端今天也将ApiCloud官方的uzWxPay.jar集成了.在编译玩测试的时候提示wxPay模块为绑定!我的项目是使用ApiCloud推出 ...
- iOS 集成微信支付【转载】
目前项目里有微信支付的需求,调研过一段时间后,发现其实并没有想象中的那么困难.如果你只是想实现该功能,一个方法足以,但是若你想深入了解实现原理.就需要花费更多的功夫了.目前我只清楚微信支付需要做签名, ...
- 如何在Spring Boot项目中集成微信支付V3
Payment Spring Boot 是微信支付V3的Java实现,仅仅依赖Spring内置的一些类库.配置简单方便,可以让开发者快速为Spring Boot应用接入微信支付. 演示例子: paym ...
- iOS集成微信支付
微信支付的开发 前言:之前听说过微信支付有很多坑,其实没有想象的那么坑,整体感觉很容易上手,按照它的流程来不会有错!PS:官方的流程看的TMD烦,好啦,废话有点多,进入开发.(ps:每个微信的版本一直 ...
- app集成微信支付服务端代码-php版本
1.微信支付分为两种,一种是微信公众品台的微信支付,另一种是微信开放平台的微信支付 2.上周做的是开放品台的微信支付,把遇到的问题总结一下 第一,下载官方提供的代码,解压后放到根目录下,然后认真读文档 ...
随机推荐
- bind-utils-测试域名解析
bind-utils是一个网络管理类工具集,其集成了我们常用的命令"nslookup",我们可以使用诊断域名解析情况. 1.安装bind-utils [root@localhost ...
- 记一次IIS网站启动不了的问题排查
今天清理了下机器中的IIS网站,将很久不用的网站都删除. 因为需要删除的比较多,正在使用的很少,就将网站全部删除了,然后准备重新添加需要用的. 在添加了网站后,点击启动按钮,发现网站启动不了,因为网站 ...
- 定制ASP.NET 6.0的应用配置
大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进. 本文的主题是应用程序配置.要介绍的是如何使用配置.如何自定义配置,以采用不同的方式 ...
- 白嫖Azure与体验GoLand远程开发
前言 近期因为有本地开发远程使用Linux编译部署的需求,而虚拟机的性能实在是不敢恭维,WSL的坑之前也踩过(没有systemd等),故考虑使用SSH连接云服务器开发. 目前VSCode提出了Remo ...
- 解决WIN7无法安装高版本Node.js问题
网上很多文章都让去安装低版本node 由于业务需求,低版本node npm 有一些包支持的不好 npm出cb() never call 本着更新npm 顺带弄个高版本的node 单独更新npm npm ...
- Asp.Net Core Identity 多数据库支持
Asp.Net Core Identity 是.Net自带的身份认证系统,支持用户界面 (UI) 登录功能,并且管理用户.密码.配置文件数据.角色.声明.令牌.电子邮件确认等等.使用Visual St ...
- 构建基于React18的电子表格程序
背景 2022年3月29日,React正式发布18.0.0.本次升级内容包括开箱即用的改进,如自动批处理.新的API(如startTransition)和支持Suspense 的流式服务器端渲染.关于 ...
- SpringCloudAlibaba分布式流量控制组件Sentinel实战与源码分析(上)
概述 定义 Sentinel官网地址 https://sentinelguard.io/zh-cn/index.html 最新版本v1.8.4 Sentinel官网文档地址 https://senti ...
- Wireshark学习笔记(一)常用功能案例和技巧
@ 目录 常用功能 1.统计->捕获属性 2.统计->协议分级 3.过滤包Apply as filter E1:过滤出特定序号的包 E2:过滤出某IP地址或端口 E3:导出php文件 E4 ...
- SQL的语法
SQL的语法 SQL通用语法 SQL语句可以单行或多行书写,以分号(";")结尾. SQL语句可以使用空格或缩进增强可读性. MySQL数据库的SQL语句不区分大小写(建议关键字大 ...