微信支付踩坑血泪史(JAVA -V3版本)
背景介绍
项目中使用的接入方式是JSAPI(参考 ),当然也可以使用其他接入方式,根据需求来。
项目中我们选择的非官方SDK binarywang,没什么别的原因,主要是更方便。
官网:;
GitHub:
一、接入前准备
接入前需要创建账号等步骤,可以参考官方文档:
二、引入依赖
<dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-mp</artifactId> </dependency> <dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-pay</artifactId> </dependency>
三、编写配置文件
开发环境下可以把秘钥存到本地,线上建议放到服务器。
因为支付会有回调和退款等操作,本地接口不能被访问。建议使用内网穿透工具进行测试()
四、数据库设计
订单表
退款表 支付单表
订单与支付单和退款单关系为一对多 不同用户扫码会产生多个支付记录,同样退款有多个退款记录。业务代码需要做支付幂等,同一笔不允许重复支付,重复支付需要调用退款接口。
五、业务代码
1.控制层
@Api(tags = "订单管理") @RestController public class OrderController { @Autowired private OrderService orderService; @Operation(summary = "提交订单") @PostMapping("/order/create") public BizResult<String> createOrder(@Valid @RequestBody OrderCreateReq req) { String orderNO = orderService.createOrder(req); return BizResult.create(orderNO); } @Operation(summary = "订单详情") @GetMapping("/order/detail") public BizResult<OrderRsp> orderDetail(@RequestParam String orderNo) { OrderRsp orderRsp = orderService.orderDetail(orderNo); return BizResult.create(orderRsp); } @Operation(summary = "轮询订单") @GetMapping("/order/polling") public BizResult<Boolean> pollingOrder(@RequestParam String orderNo) { Boolean result = orderService.pollingOrder(orderNo); return BizResult.create(result); } @Operation(summary = "订单列表") @PostMapping("/order/list") public BizResult<PageData<OrderListRsp>> queryOrderList(@RequestBody OrderListReq req) { req.check(); PageData<OrderListRsp> pageData = orderService.queryOrderList(req); return BizResult.create(pageData); } }
2.业务层
3.manager
@Slf4j @Component public class WxManager { @Autowired WxPayProperties wxPayProperties; @Resource private RedissonClient redissonClient; @Autowired private WxMpProperties wxMpProperties; public WxMpService getWxMpService() { WxMpRedissonConfigImpl config = new WxMpRedissonConfigImpl(redissonClient, CommonConstants.NAMESPACE); config.setAppId(wxMpProperties.getAppId()); config.setSecret(wxMpProperties.getSecret()); WxMpService service = new WxMpServiceImpl(); service.setWxMpConfigStorage(config); return service; } public WxPayService getWxPayService() { WxPayConfig payConfig = new WxPayConfig(); payConfig.setAppId(wxPayProperties.getAppid()); payConfig.setMchId(wxPayProperties.getMchId()); payConfig.setPrivateKeyPath(wxPayProperties.getPrivateKeyPath()); payConfig.setNotifyUrl(wxPayProperties.getNotifyUrl()); payConfig.setApiV3Key(wxPayProperties.getApiV3key()); payConfig.setPrivateCertPath(wxPayProperties.getPrivateCertPath()); WxPayService wxPayService = new WxPayServiceImpl(); wxPayService.setConfig(payConfig); return wxPayService; } public WxPayService getWxPayRefundService() { WxPayConfig payConfig = new WxPayConfig(); payConfig.setAppId(wxPayProperties.getAppid()); payConfig.setMchId(wxPayProperties.getMchId()); payConfig.setPrivateKeyPath(wxPayProperties.getPrivateKeyPath()); payConfig.setNotifyUrl(wxPayProperties.getRefundNotifyUrl()); payConfig.setApiV3Key(wxPayProperties.getApiV3key()); payConfig.setPrivateCertPath(wxPayProperties.getPrivateCertPath()); WxPayService wxPayService = new WxPayServiceImpl(); wxPayService.setConfig(payConfig); return wxPayService; } }
4.Properties
@Data @Component @Configuration @ConfigurationProperties(prefix = "wechat-pay") public class WxPayProperties { /** * 商户号 */ private String mchId; /** * 证书解密的密钥 */ private String apiV3key; /** * 商户私钥文件 */ private String privateKeyPath; /** * apiclient_cert.pem证书文件 */ private String privateCertPath; /** * 商户证书序列号 */ private String serialNo; /** * 赋选供应链 服务号appid */ private String appid; /** * 支付回调通知地址 */ private String notifyUrl; /** * 退款回调通知地址 */ private String refundNotifyUrl; }
总结
以上就是核心业务代码,涉及到具体业务mapper没有放上来,但是核心的处理步骤已经体现出来了。主要是对订单状态需要仔细判断,不同操作会引起状态的变更。业务中,当多个人扫同一个码,后续扫码成功会调用退款接口。
上一篇:
通过多线程提高代码的执行效率例子
下一篇:
基础篇-ArrayList的扩容机制