第一个就是需要在商户系统当中调用微信后台的一个下单接口,就是生成预支付交易单。
第二个就是支付成功之后微信后台会给推送消息。
这两个接口数据的安全性,要求其实是非常高的。
解决:
1. 主要的实现原理如下
2. 在微信商户中开通相应的功能
3. 主要的过程
请求的url为:
https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
主要的yml的配置:
wechat:
appid: wxcd2e39f677fd30ba
secret: 84fbfdf5ea288f0c432d829599083637
mchid : 1561414331
mchSerialNo: 4B3B3DC35414AD50B1B755BAF8DE9CC7CF407606
privateKeyFilePath: D:\apiclient_key.pem
apiV3Key: CZBK51236435wxpay435434323FFDuv3
weChatPayCertFilePath: D:\wechatpay_166D96F876F45C7D07CE98952A96EC980368ACFC.pem
notifyUrl: https://www.weixin.qq.com/wxpay/pay.php
refundNotifyUrl: https://www.weixin.qq.com/wxpay/pay.php
wechat:
appid: ${sky.wechat.appid}
secret: ${sky.wechat.secret}
mchid : ${sky.wechat.mchid}
mchSerialNo: ${sky.wechat.mchSerialNo}
privateKeyFilePath: ${sky.wechat.privateKeyFilePath}
apiV3Key: ${sky.wechat.apiV3Key}
weChatPayCertFilePath: ${sky.wechat.weChatPayCertFilePath}
notifyUrl: ${sky.wechat.notifyUrl}
refundNotifyUrl: ${sky.wechat.refundNotifyUrl}
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; //退款成功的回调地址
OrderMapper:
* 根据订单号和用户id查询订单
* @param orderNumber
* @param userId
*/
@Select("select * from orders where number = #{orderNumber} and user_id= #{userId}")
Orders getByNumberAndUserId(String orderNumber, Long userId);
/**
* 修改订单信息
* @param orders
*/
void update(Orders orders);
OrderMapper.xml:
<update id="update" parameterType="com.sky.entity.Orders">
update orders
<set>
<if test="cancelReason != null and cancelReason!='' ">
cancel_reason=#{cancelReason},
</if>
<if test="rejectionReason != null and rejectionReason!='' ">
rejection_reason=#{rejectionReason},
</if>
<if test="cancelTime != null">
cancel_time=#{cancelTime},
</if>
<if test="payStatus != null">
pay_status=#{payStatus},
</if>
<if test="payMethod != null">
pay_method=#{payMethod},
</if>
<if test="checkoutTime != null">
checkout_time=#{checkoutTime},
</if>
<if test="status != null">
status = #{status},
</if>
<if test="deliveryTime != null">
delivery_time = #{deliveryTime}
</if>
</set>
where id = #{id}
</update>
在OrderService.java中添加payment和paySuccess两个方法定义:
* 订单支付
* @param ordersPaymentDTO
* @return
*/
OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception;
/**
* 支付成功,修改订单状态
* @param outTradeNo
*/
void paySuccess(String outTradeNo);
在OrderServiceImpl.java中实现payment和paySuccess两个方法:
@Autowired
private UserMapper userMapper;
@Autowired
private WeChatPayUtil weChatPayUtil;
/**
* 订单支付
*
* @param ordersPaymentDTO
* @return
*/
public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {
// 当前登录用户id
Long userId = BaseContext.getCurrentId();
User user = userMapper.getById(userId);
//调用微信支付接口,生成预支付交易单
JSONObject jsonObject = weChatPayUtil.pay(
ordersPaymentDTO.getOrderNumber(), //商户订单号
new BigDecimal(0.01), //支付金额,单位 元
user.getOpenid() //微信用户的openid
);
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;
}
/**
* 支付成功,修改订单状态
*
* @param outTradeNo
*/
public void paySuccess(String outTradeNo) {
// 当前登录用户id
Long userId = BaseContext.getCurrentId();
// 根据订单号查询当前用户的订单
Orders ordersDB = orderMapper.getByNumberAndUserId(outTradeNo, userId);
// 根据订单id更新订单的状态、支付方式、支付状态、结账时间
Orders orders = Orders.builder()
.id(ordersDB.getId())
.status(Orders.TO_BE_CONFIRMED)
.payStatus(Orders.PAID)
.checkoutTime(LocalDateTime.now())
.build();
orderMapper.update(orders);
}
在OrderController.java中添加payment方法:
* 订单支付
*
* @param ordersPaymentDTO
* @return
*/
@PutMapping("/payment")
@ApiOperation("订单支付")
public Result<OrderPaymentVO> payment(@RequestBody OrdersPaymentDTO ordersPaymentDTO) throws Exception {
log.info("订单支付:{}", ordersPaymentDTO);
OrderPaymentVO orderPaymentVO = orderService.payment(ordersPaymentDTO);
log.info("生成预支付交易单:{}", orderPaymentVO);
return Result.success(orderPaymentVO);
}
PayNotifyController.java:
@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);
//业务处理,修改订单状态、来单提醒
orderService.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();
}
需要的代码为:
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
暂无评论内容