微信小程序-支付功能
首先我这里得声明,微信支付比较繁琐,所以我写的都很仔细,所以如果你没有耐心的化,应该是看不下去的,我力求,以后我们用到微信支付代码的时候,我看到这个文章就能很好的搭起来,而不是直接抄别人的代码,我觉得学的还是一个思想,和框架,了解它整体的流程,以后别人问了我们,肚子里才有墨水
流程
我们得从大体上来看,我们需要实现微信支付的化,要干什么
首先真正要实现微信支付的化,有一个大前提,就是我们得需要有商户认证,所以我这里无法真正实现这里的功能,也就是说,无法验证
大体流程分析
1 到 3 步
对于1 到 3步,来说,就是前端发请求过来,到我们的springboot系统
然后我们返回订单号,这里不太属于微信支付的真正流程里边,这个属于个人的业务,我们内部维护的一个订单号
4 到 8步
这个流程是比较核心的流程,整体的流程就是为了得到一个预交易标识
9 到 14步
这个流程,就是用户点了支付之后,会真正调用一个支付接口,然后支付之后,会有一个支付成功的回调函数,这个回调函数的工作就是去14. 更新订单状态!
所以我们整体来看,我门真正很需要关心的接口有两个
也就是这里的 5.调用微信下单接口, 10.调起支付接口
其他接口基本上是业务接口,例如,最后一步,更新订单状态,也算是我们的业务代码
详细流程分析
1 - 3
这里的1 - 3 步,属于业务代码,只要返回订单号就ok
核心预支付接口
4 ~ 8 步
5. 调用微信下单接口
这个接口的在微信支付的文档里边,这里的小程序调起的api叫做jsapi
接口说明
首先是这里的api
整体这个api 拼接起来就是
https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
请求头参数
第一个是,http请求头参数
特别要注意这些设置,它官方文档要怎么做,我们写代码的时候就要很注意了,它是硬性要求
body参数
第二个是body参数
这些参数,都是我截取的必填的
我们来看比较重要的
appid 小程序id
mchid 商户号id
out_trade_no 商户系统自带的订单号,必须是只能是数字 + 大小写字母,并且还需要唯一,这个参数,其实就是我们1 ~ 3步生成的订单号
notify_url: 这个是支付成功后的回调地址,这个地址也是需要配置的,特别需要注意这个接口
amount: 多少钱,这里的amount还是一个对象,里边包括
total: 金额多少
currency : 货币体系,这里一般是CNY
payer: 谁付的钱,而这个payer,里边是用户的标识,也是微信独有的
openid标识,一个openid,代表着一个用户
这里的第七步,也就是将组合数据再次签名的目的,就是为了网络传输的安全,给这些数据签上名,相当于是加密,这里会设计到加密 + 解密的问题
最后回复给前端 也就是我这里的小程序
返回参数
这个返回的就只有一个东西
类似于这样的
{
"prepay_id" : "wx201410272009395522657a690389285100"
}
我们可以看作是一个预交易的标识
这个的作用在之后的调起真正的支付接口的时候,是有用的
然后是第9步,用户确认支付,他就会发起这样的请求
这里的照片有点模糊没什么办法,但是我们就只用知道,这里就是加密后的信息,前端给这些信息,进行了封装,调用了这个方法,之后,小程序就会出席那一个支付框
这里的接口也有详细的介绍
我们直接用一个例子来看,就更为清楚了
wx.requestPayment
(
{
"timeStamp": "1414561699",
"nonceStr": "5K8264ILTKCH16CQ2502SI8ZNMTM67VS",
"package": "prepay_id=wx201410272009395522657a690389285100",
"signType": "RSA",
"paySign": "oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ\/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT+Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV+JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu+LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2+AehHvz+n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq\/xDg==",
"success":function(res){},
"fail":function(res){},
"complete":function(res){}
}
)
timeStamp就是时间戳,不重要
nonceStr 随机字符串,不知道干什么的
package: 这个就是核心预支付功能的返回值,prepare_id的值,而且他的提提交方式就是这样 prepare_id=xxx
signType: 就是加密的方式
paySign: 加密之后得出的签名值,这个pagSign会在之后,在我们真正支付的时候,会校验这个pagSign,实际就是校验appid是否是一致的,因为本来这个加密的东西里边就包括了appid
确认之后,就会真正发起一个请求,也就是我这里写的核心支付接口
支付接口
然后我们就来看这里的调起支付接口
掉了这个支付接口之后,就会回调给我们自己的商户系统,也就是支付成功的回调函数,这也是我们刚刚说过的事情,然后我们自己去更新支付状态
准备工作
这里的准备工作,就是要一般来说,我们这里的开发环境是内网,所以我们得需要有一个公网的ip地址才行,如果你有公网的ip的化,那么就可以跳过这里
这里用到的cploar
我们直接搜索cploar,然后注册一个账号,下载cploar
然后下载之后,我们要打开所在的目录
第一次来搞的化,要先弄这个步骤
就是验证一下,这里它是linux,windows,就前面直接这样写
然后就ok了
启动!
像这里,我们也是windows版本的化,我这里的后端的接口是8080 所以这里不屑80
直接这样写
cploar.exe http 8080
这样之后就成功了
这里的卡面的以top结尾的地址就是我的临时的公网ip地址
核心代码开发
配置
首先我们得先搞清楚配置项
@Component
@ConfigurationProperties(prefix = "sky.wechat")
@Data
public class WeChatProperties {
private String appid; //小程序的appid
private String secret; //小程序的秘钥
private String mchid; //商户号
private String mchSerialNo; //商户API证书的证书序列号
private String privateKeyFilePath; //商户私钥文件
private String apiV3Key; //证书解密的密钥
private String weChatPayCertFilePath; //平台证书
private String notifyUrl; //支付成功的回调地址
private String refundNotifyUrl; //退款成功的回调地址
}
这是配置类,这个是和yml进行映射的,更好的做一个配置
wechat:
appid: 小程序的id
secret: 小程序的密钥
#商户号
mchid: 自己的商户号
#商户API证书的证书序列号
mchSerialNo:商户号的序列号
#商户私钥文件
privateKeyFilePath: D:\pay\apiclient_key.pem
#证书解密的密钥
apiV3Key: CZBK51236435wxpay435434323FFDuv3
#平台证书
weChatPayCertFilePath: D:\pay\wechatpay_166D96F876F45C7D07CE98952A96EC980368ACFC.pem
#支付成功的回调地址
notifyUrl: http://6a5f907f.r6.cpolar.top/notify/paySuccess
#退款成功的回调地址
refundNotifyUrl: http://6a5f907f.r6.cpolar.top/notify/refundSuccess
我们这里privateKeyFilePath 和 apiV3Key 就是关于安全的问题
然后其他都是关于微信的,我们要自己看自己的情况进行填写
privateKeyFilePath: 就是一个pem的文件,加密文件
weChatPayCertFilePath: 这个也是微信生成的
然后这里关于我们的商户系统的地方就在于这个
notifyUrl: 这里我们测试的化,用到的是我在准备工作用到的,从本地转换为公网ip的地址,这是一个支付成功的地址,这里的后边跟着的
/notity/paySuccess,也是我们这里的controller的方法
refundNotifyUrl:
/notify/refundSuccess,也是我们这里的controller的方法
核心代码
首先,1 ~ 3 步,生成订单号的接口代码,这一步我们有各种实现的方法,我这里贴出我这里业务的代码
@ApiOperation("下单")
@PostMapping("/submit")
public Result submit(@RequestBody OrdersSubmitDTO ordersSubmitDTO) {
log.info("下单 参数为: {}",ordersSubmitDTO);
OrderSubmitVO orderSubmitVO = ordersService.submit(ordersSubmitDTO);
return Result.success(orderSubmitVO);
}
这里的返回的vo就是如下
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OrderSubmitVO implements Serializable {
//订单id
private Long id;
//订单号
private String orderNumber;
//订单金额
private BigDecimal orderAmount;
//下单时间
private LocalDateTime orderTime;
}
我这里的订单号,就设置成了时间戳,没什么
5 到 9 步,预支付代码
controller
@ApiOperation("订单支付")
@PutMapping("/payment")
public Result payment(@RequestBody OrdersPaymentDTO ordersPaymentDTO) throws Exception {
log.info("订单支付 参数为: {}",ordersPaymentDTO);
//预支付交易单
OrderPaymentVO orderPaymentVO = ordersService.payment(ordersPaymentDTO);
return Result.success(orderPaymentVO);
}
预支付的vo是如下
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OrderPaymentVO implements Serializable {
private String nonceStr; //随机字符串
private String paySign; //签名
private String timeStamp; //时间戳
private String signType; //签名算法
private String packageStr; //统一下单接口返回的 prepay_id 参数值
}
这里的返回值就对应着我前面的核心预支付接口下的,第二个接口,也就是
wx.requestPayment这个接口需要的值,我们要返回这个东西给前端去发请求
Service
/**
* 订单支付
* @param ordersPaymentDTO
* @return
*/
@Override
public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {
// 当前登录用户id
Long userId = BaseContext.getCurrentId();
User user = userService.getById(userId);
//调用微信支付接口,生成预支付交易单
JSONObject jsonObject = weChatPayUtil.pay(
ordersPaymentDTO.getOrderNumber(), //商户订单号
new BigDecimal(0.01), //支付金额,单位 元
"苍穹外卖订单", //商品描述
user.getOpenid() //微信用户的openid
);
//如果code是 orderpaid代表已支付!
if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) {
throw new OrderBusinessException("该订单已支付");
}
OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);
vo.setPackageStr(jsonObject.getString("package"));
return vo;
}
我们先不看,最重要的预支付的接口,我们直接来看其他的,我们预支付接口返回的是jsonObject,这里就是把微信支付封装了起来,首先是判断是不是已经支付了,如果已经支付了,就不用了,直接返回异常
如果不是的化,那么就要设置PackageStr,这个PackageStr也就是加密后的密文
微信支付工具类
这里的微信支付的工具类也是封装好的,我先把整体的代码贴出来
/**
* 微信支付工具类
*/
@Component
public class WeChatPayUtil {
//微信支付下单接口地址
public static final String JSAPI = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
//申请退款接口地址
public static final String REFUNDS = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
@Autowired
private WeChatProperties weChatProperties;
/**
* 获取调用微信接口的客户端工具对象
*
* @return
*/
private CloseableHttpClient getClient() {
PrivateKey merchantPrivateKey = null;
try {
//merchantPrivateKey商户API私钥,如何加载商户API私钥请看常见问题
merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream(new File(weChatProperties.getPrivateKeyFilePath())));
//加载平台证书文件
X509Certificate x509Certificate = PemUtil.loadCertificate(new FileInputStream(new File(weChatProperties.getWeChatPayCertFilePath())));
//wechatPayCertificates微信支付平台证书列表。你也可以使用后面章节提到的“定时更新平台证书功能”,而不需要关心平台证书的来龙去脉
List<X509Certificate> wechatPayCertificates = Arrays.asList(x509Certificate);
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(weChatProperties.getMchid(), weChatProperties.getMchSerialNo(), merchantPrivateKey)
.withWechatPay(wechatPayCertificates);
// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签
CloseableHttpClient httpClient = builder.build();
return httpClient;
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
}
/**
* 发送post方式请求
*
* @param url
* @param body
* @return
*/
private String post(String url, String body) throws Exception {
CloseableHttpClient httpClient = getClient();
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.toString());
httpPost.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString());
httpPost.addHeader("Wechatpay-Serial", weChatProperties.getMchSerialNo());
httpPost.setEntity(new StringEntity(body, "UTF-8"));
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
String bodyAsString = EntityUtils.toString(response.getEntity());
return bodyAsString;
} finally {
httpClient.close();
response.close();
}
}
/**
* 发送get方式请求
*
* @param url
* @return
*/
private String get(String url) throws Exception {
CloseableHttpClient httpClient = getClient();
HttpGet httpGet = new HttpGet(url);
httpGet.addHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.toString());
httpGet.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString());
httpGet.addHeader("Wechatpay-Serial", weChatProperties.getMchSerialNo());
CloseableHttpResponse response = httpClient.execute(httpGet);
try {
String bodyAsString = EntityUtils.toString(response.getEntity());
return bodyAsString;
} finally {
httpClient.close();
response.close();
}
}
/**
* jsapi下单
*
* @param orderNum 商户订单号
* @param total 总金额
* @param description 商品描述
* @param openid 微信用户的openid
* @return
*/
private String jsapi(String orderNum, BigDecimal total, String description, String openid) throws Exception {
JSONObject jsonObject = new JSONObject();
jsonObject.put("appid", weChatProperties.getAppid());
jsonObject.put("mchid", weChatProperties.getMchid());
jsonObject.put("description", description);
jsonObject.put("out_trade_no", orderNum);
jsonObject.put("notify_url", weChatProperties.getNotifyUrl());
JSONObject amount = new JSONObject();
amount.put("total", total.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue());
amount.put("currency", "CNY");
jsonObject.put("amount", amount);
JSONObject payer = new JSONObject();
payer.put("openid", openid);
jsonObject.put("payer", payer);
String body = jsonObject.toJSONString();
return post(JSAPI, body);
}
/**
* 小程序支付
*
* @param orderNum 商户订单号
* @param total 金额,单位 元
* @param description 商品描述
* @param openid 微信用户的openid
* @return
*/
public JSONObject pay(String orderNum, BigDecimal total, String description, String openid) throws Exception {
//统一下单,生成预支付交易单
String bodyAsString = jsapi(orderNum, total, description, openid);
//解析返回结果
JSONObject jsonObject = JSON.parseObject(bodyAsString);
System.out.println(jsonObject);
String prepayId = jsonObject.getString("prepay_id");
if (prepayId != null) {
String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
String nonceStr = RandomStringUtils.randomNumeric(32);
ArrayList<Object> list = new ArrayList<>();
list.add(weChatProperties.getAppid());
list.add(timeStamp);
list.add(nonceStr);
list.add("prepay_id=" + prepayId);
//二次签名,调起支付需要重新签名
StringBuilder stringBuilder = new StringBuilder();
for (Object o : list) {
stringBuilder.append(o).append("\n");
}
String signMessage = stringBuilder.toString();
byte[] message = signMessage.getBytes();
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(PemUtil.loadPrivateKey(new FileInputStream(new File(weChatProperties.getPrivateKeyFilePath()))));
signature.update(message);
String packageSign = Base64.getEncoder().encodeToString(signature.sign());
//构造数据给微信小程序,用于调起微信支付
JSONObject jo = new JSONObject();
jo.put("timeStamp", timeStamp);
jo.put("nonceStr", nonceStr);
jo.put("package", "prepay_id=" + prepayId);
jo.put("signType", "RSA");
jo.put("paySign", packageSign);
return jo;
}
return jsonObject;
}
/**
* 申请退款
*
* @param outTradeNo 商户订单号
* @param outRefundNo 商户退款单号
* @param refund 退款金额
* @param total 原订单金额
* @return
*/
public String refund(String outTradeNo, String outRefundNo, BigDecimal refund, BigDecimal total) throws Exception {
JSONObject jsonObject = new JSONObject();
jsonObject.put("out_trade_no", outTradeNo);
jsonObject.put("out_refund_no", outRefundNo);
JSONObject amount = new JSONObject();
amount.put("refund", refund.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue());
amount.put("total", total.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue());
amount.put("currency", "CNY");
jsonObject.put("amount", amount);
jsonObject.put("notify_url", weChatProperties.getRefundNotifyUrl());
String body = jsonObject.toJSONString();
//调用申请退款接口
return post(REFUNDS, body);
}
}
我们一个个拆解来看
首先是pay方法,我们这里下来整体来看这个pay方法
整体来看,就是先去调用jsapi,这个jsapi也就是我们真正调用的预支付接口
也是前面的那个核心接口
然后我们来看jsapi
/**
* jsapi下单
*
* @param orderNum 商户订单号
* @param total 总金额
* @param description 商品描述
* @param openid 微信用户的openid
* @return
*/
private String jsapi(String orderNum, BigDecimal total, String description, String openid) throws Exception {
JSONObject jsonObject = new JSONObject();
jsonObject.put("appid", weChatProperties.getAppid());
jsonObject.put("mchid", weChatProperties.getMchid());
jsonObject.put("description", description);
jsonObject.put("out_trade_no", orderNum);
jsonObject.put("notify_url", weChatProperties.getNotifyUrl());
JSONObject amount = new JSONObject();
amount.put("total", total.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue());
amount.put("currency", "CNY");
jsonObject.put("amount", amount);
JSONObject payer = new JSONObject();
payer.put("openid", openid);
jsonObject.put("payer", payer);
String body = jsonObject.toJSONString();
return post(JSAPI, body);
}
整体也是很好理解,就是装参数,然后发送post请求
这里的参数,也是我们说过了的
我们再来看这里的post请求
/**
* 发送post方式请求
*
* @param url
* @param body
* @return
*/
private String post(String url, String body) throws Exception {
CloseableHttpClient httpClient = getClient();
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.toString());
httpPost.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString());
httpPost.addHeader("Wechatpay-Serial", weChatProperties.getMchSerialNo());
httpPost.setEntity(new StringEntity(body, "UTF-8"));
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
String bodyAsString = EntityUtils.toString(response.getEntity());
return bodyAsString;
} finally {
httpClient.close();
response.close();
}
}
首先,我们发请求,肯定是要得到一个httpClient,这个也是封住好的方法
我们看这里的之后的代码,实际上就是装载请求头,这里也是按照微信文档来写的
最后发送请求!!!
然后这里的getClient
/**
* 获取调用微信接口的客户端工具对象
*
* @return
*/
private CloseableHttpClient getClient() {
PrivateKey merchantPrivateKey = null;
try {
//merchantPrivateKey商户API私钥,如何加载商户API私钥请看常见问题
merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream(new File(weChatProperties.getPrivateKeyFilePath())));
//加载平台证书文件
X509Certificate x509Certificate = PemUtil.loadCertificate(new FileInputStream(new File(weChatProperties.getWeChatPayCertFilePath())));
//wechatPayCertificates微信支付平台证书列表。你也可以使用后面章节提到的“定时更新平台证书功能”,而不需要关心平台证书的来龙去脉
List<X509Certificate> wechatPayCertificates = Arrays.asList(x509Certificate);
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(weChatProperties.getMchid(), weChatProperties.getMchSerialNo(), merchantPrivateKey)
.withWechatPay(wechatPayCertificates);
// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签
CloseableHttpClient httpClient = builder.build();
return httpClient;
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
}
这里我不是能搞懂,但是我看着像整加密的,也是调用微信的加密的
所以整体看下来,这个工具类,就是发请求 + 设置加密
回调代码
/**
* @author jjking
* @date 2024-01-28 20:13
*/
@RestController
@RequestMapping("/notify")
@Slf4j
public class PayNotifyController {
@Autowired
private OrdersService ordersService;
@Autowired
private WeChatProperties weChatProperties;
/**
* 支付成功回调
*
* @param request
*/
@RequestMapping("/paySuccess")
public void paySuccessNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
//读取数据
String body = readData(request);
log.info("支付成功回调:{}", body);
//数据解密
String plainText = decryptData(body);
log.info("解密后的文本:{}", plainText);
JSONObject jsonObject = JSON.parseObject(plainText);
String outTradeNo = jsonObject.getString("out_trade_no");//商户平台订单号
String transactionId = jsonObject.getString("transaction_id");//微信支付交易号
log.info("商户平台订单号:{}", outTradeNo);
log.info("微信支付交易号:{}", transactionId);
//业务处理,修改订单状态、来单提醒
ordersService.paySuccess(outTradeNo);
//给微信响应
responseToWeixin(response);
}
/**
* 读取数据
*
* @param request
* @return
* @throws Exception
*/
private String readData(HttpServletRequest request) throws Exception {
BufferedReader reader = request.getReader();
StringBuilder result = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
if (result.length() > 0) {
result.append("\n");
}
result.append(line);
}
return result.toString();
}
/**
* 数据解密
*
* @param body
* @return
* @throws Exception
*/
private String decryptData(String body) throws Exception {
JSONObject resultObject = JSON.parseObject(body);
JSONObject resource = resultObject.getJSONObject("resource");
String ciphertext = resource.getString("ciphertext");
String nonce = resource.getString("nonce");
String associatedData = resource.getString("associated_data");
AesUtil aesUtil = new AesUtil(weChatProperties.getApiV3Key().getBytes(StandardCharsets.UTF_8));
//密文解密
String plainText = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),
nonce.getBytes(StandardCharsets.UTF_8),
ciphertext);
return plainText;
}
/**
* 给微信响应
* @param response
*/
private void responseToWeixin(HttpServletResponse response) throws Exception{
response.setStatus(200);
HashMap<Object, Object> map = new HashMap<>();
map.put("code", "SUCCESS");
map.put("message", "SUCCESS");
response.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
response.getOutputStream().write(JSONUtils.toJSONString(map).getBytes(StandardCharsets.UTF_8));
response.flushBuffer();
}
}
我们需要注意的就是这里的paySuccessNotify方法,这主要就是
加载数据 + 数据解密 + 业务回调 + 给微信响应
我这里也贴出我自己的业务回调方法,也是为了记录一下
@Override
public void paySuccess(String outTradeNo) {
// 根据订单号查询订单
LambdaQueryWrapper<Orders> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Orders::getNumber,outTradeNo);
Orders ordersDB = getOne(wrapper);
// 根据订单id更新订单的状态、支付方式、支付状态、结账时间
Orders orders = Orders.builder()
.id(ordersDB.getId())
.status(Orders.TO_BE_CONFIRMED)
.payStatus(Orders.PAID)
.checkoutTime(LocalDateTime.now())
.build();
updateById(orders);
}
就是设置一个status
总结
我们总结来看,其实也不是很难,看起来很复杂其实没有,这里我认为比较难的是这里的加密 + 解密,我这里并没有搞懂,等我搞懂了这里的加密 + 解密,我再来更新这里的代码
然后这里的代码实际上复用性,还行,我们需要改的是,yml里边的设置,
我这里最后再来总结一下总体的流程
- 前端发请求过来,后端返回订单号
- 后端发请求到wx,然后收到预支付标识prepare_id,然后设置信息加密给到前端
- 前端带着这些加密信息,发请求直接给到wx,wx支付成功就会有回调函数,如果失败,就不返回
- 回调函数,我们就解密这些数据,最后调用我们业务回调代码
整体的流程就是这样,我们要复用的化,也就是修改哪些加密的方式,这些