在做完一个仿美团的应用,我将其中涉及到的一些技术点进行总结和整理,当下次遇到类似的问题就能省下不少时间,避免踩坑。
一、微信小程序支付的使用
<dependency> <groupId>com.github.binarywang
groupId> <artifactId>wx-java-pay-spring-boot-starter
artifactId> <version>4.0.0
version>
dependency>
然后去 https://github.com/Wechat-Group/WxJava 下载一个demo,将demo中的 WxPayConfiguration.java、WxPayProperties.java 文件复制到自己的项目中

也可以直接复制我在下方提供的代码,是一模一样的
WxPayConfiguration.java
package com.cmzn.meigo.wx.pay.config; import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.service.WxPayService; import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; import lombok.AllArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; / * @author Binary Wang */ @Configuration @ConditionalOnClass(WxPayService.class) @EnableConfigurationProperties(WxPayProperties.class) @AllArgsConstructor public class WxPayConfiguration {
private WxPayProperties properties; @Bean @ConditionalOnMissingBean public WxPayService wxService() {
WxPayConfig payConfig = new WxPayConfig(); payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId())); payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId())); payConfig.setMchKey(StringUtils.trimToNull(this.properties.getMchKey())); payConfig.setSubAppId(StringUtils.trimToNull(this.properties.getSubAppId())); payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId())); payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath())); // 可以指定是否使用沙箱环境 payConfig.setUseSandboxEnv(false); WxPayService wxPayService = new WxPayServiceImpl(); wxPayService.setConfig(payConfig); return wxPayService; } }
WxPayProperties.java
import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; / * wxpay pay properties. * * @author Binary Wang */ @Data @ConfigurationProperties(prefix = "wx.pay") public class WxPayProperties {
/ * 设置微信公众号或者小程序等的appid */ private String appId; / * 微信支付商户号 */ private String mchId; / * 微信支付商户密钥 */ private String mchKey; / * 服务商模式下的子商户公众账号ID,普通模式请不要配置,请在配置文件中将对应项删除 */ private String subAppId; / * 服务商模式下的子商户号,普通模式请不要配置,最好是请在配置文件中将对应项删除 */ private String subMchId; / * apiclient_cert.p12文件的绝对路径,或者如果放在项目中,请以classpath:开头指定 */ private String keyPath; }
然后在application.yml中配置参数,支付用不到证书,可以注释掉,我的也不是服务商模式,不用理subAppId和subMchId
wx: pay: appId: #小程序APPID mchId: #商户号ID mchKey: #商户号秘钥 subAppId: #服务商模式下的子商户公众账号ID subMchId: #服务商模式下的子商户号 #keyPath: classpath:/wx/apiclient_cert.p12 # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头) secret: #小程序秘钥
二、唤起微信支付窗口
写一个简单的下单流程,业务逻辑代码我给他省略了
private HttpResult order(OrderRequest orderRequest, String gkId) throws WxPayException{
/* * 业务代码省略 */ wxPayMpOrderResult = myWxPayService.createDdzqOrder(ddzqOrder); //调用唤起窗口方法 if(wxPayMpOrderResult == null){
throw new RuntimeException("创建订单异常"); }else{
return HttpResult.ok(wxPayMpOrderResult); } }
唤起微信小程序支付窗口 参数可以按自己需要进行增加 https://pay.weixin..com/wiki/doc/api/jsapi_sl.php?chapter=9_1 参考微信支付开发文档
public WxPayMpOrderResult createDdzqOrder(DdzqOrder ddzqOrder)throws WxPayException {
String endPayMoney = ddzqOrder.getEndPayMoney().multiply(BigDecimal.valueOf(100)).stripTrailingZeros().toPlainString(); //将金额转换为分 WxPayUnifiedOrderRequest.WxPayUnifiedOrderRequestBuilder builder = WxPayUnifiedOrderRequest.newBuilder(); WxPayUnifiedOrderRequest wxOrder = builder .body("") //商品描述 .openid("") //用户openid .outTradeNo(ddzqOrder.getMasterId()) //商户订单号 .spbillCreateIp("0.0.0.0") //终端IP .totalFee(endPayMoney) // 支付收款金额 100分 注意:单位(分) //.totalFee(1) 测试时可以设置一分钱 .timeStart(DateTimeUtils.yyyyMMddHHmmssDateTime(0)) //交易起始时间 .timeExpire(DateTimeUtils.yyyyMMddHHmmssDateTime(2)) //交易结束时间 .tradeType(WxPayConstants.TradeType.JSAPI).build(); wxOrder.setSignType("MD5"); //wxOrder.setNotifyUrl("https://微信支付成功回调地址*/pay/ddzqOrder"); //不测试时需要放开注释 return wxPayService.createOrder(wxOrder); }
三、微信支付成功回调
https://pay.weixin..com/wiki/doc/api/jsapi.php?chapter=9_7&index=8
意思就是支付成功后,微信会调用我们之前设置的 微信支付成功回调地址
wxOrder.setNotifyUrl("https://微信支付成功回调地址*/pay/ddzqOrder");
@Api("微信支付") @RestController @RequestMapping("/pay") @AllArgsConstructor public class WxPayController {
//监听到店自取下单的支付成功回调 @PostMapping("/ddzqOrder") public String ddzqOrderPay(HttpServletRequest request, HttpServletResponse response) throws WxPayException {
return myWxPayService.ddzqOrder(request); } }
那微信那边重复请求我们应该怎么处理呢,其实这里有个小技巧,我们可以通过数据库锁避免同一条数据被重复操作。
update st_order set pay_status = #{
payStatus } where pay_status = 0
通过 where pay_status = 0 这个条件,那么这条订单数据只会被修改一次,以下就是我处理订单成功回调的方法
public String ddzqOrder(HttpServletRequest request) {
try {
String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding()); WxPayOrderNotifyResult payResult = wxPayService.parseOrderNotifyResult(xmlResult); String masterOrderId = payResult.getOutTradeNo();//内部订单记录ID String wxTransactionId = payResult.getTransactionId();//商户号订单ID BigDecimal wxRealPayAmount = new BigDecimal(BaseWxPayResult.fenToYuan(payResult.getTotalFee()));//微信真实支付金额 StOrder stOrder = stOrderMapper.selectByEOrderId(masterOrderId); Date nowTime = new Date(); if(stOrder.getPayStatus() == 1){
//下一个进程进来的时候,上一个进程已经修改了订单支付状态 return WxPayNotifyResponse.success("处理成功!"); } StOrder orderRequest = new StOrder(); orderRequest.setPayStatus(1);//标记已支付 orderRequest.setMasterOrderId(masterOrderId); orderRequest.setPaymentTime(nowTime); orderRequest.setStoreReceiveTime(nowTime); orderRequest.setOrderStatus(10); //等待顾客取货 stOrderMapper.updateByMasterOrderIdSelective(orderRequest); StOrderPay stOrderPay = new StOrderPay(); stOrderPay.setMasterOrderId(masterOrderId); stOrderPay.setWxRealPayAmount(wxRealPayAmount); stOrderPay.setWxTransactionId(wxTransactionId); stOrderPay.setPayWay(1); //支付方式 微信支付:1 支付宝支付:2 stOrderPayMapper.insert(stOrderPay); / * 打印订单 */ List<StPrinter> stPrinterList = stPrinterMapper.selectPrintersByStoreId(stOrder.getStoreId()); for (StPrinter stPrinter:stPrinterList) {
stPrinterService.printOrder(stOrder.getEOrderId(),stOrder.getStoreId(),stPrinter.getOkPrinterSn()); } return WxPayNotifyResponse.success("处理成功!"); } catch (Exception e) {
e.printStackTrace(); return WxPayNotifyResponse.fail(e.getMessage()); } }
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/223477.html原文链接:https://javaforall.net
