学习使用微信的jsapi支付,即微信内置浏览器或者小程序唤起微信支付
因为没有办法申请商户号,所以无法验证是否正确,只能先记录下代码
1.注册绑定商户号
微信支付 - 中国领先的第三方支付平台 | 微信支付提供安全快捷的支付方式 (qq.com)
商户号后台绑定小程序的AppID
2.导入依赖
1 2 3 4 5
| <dependency> <groupId>com.github.wechatpay-apiv3</groupId> <artifactId>wechatpay-apache-httpclient</artifactId> <version>0.4.8</version> </dependency>
|
3.准备参数
application.yml
1 2 3 4 5 6 7 8 9 10 11
| sky: 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}
|
application-dev.yml
1 2 3 4 5 6 7 8 9 10 11
| sky: wechat: appid: 小程序的appid secret: 小程序的秘钥 mchid: 商户号 mchSerialNo: 商户API证书的证书序列号 privateKeyFilePath: 商户私钥文件绝对路径 apiV3Key: 证书解密的密钥绝对路径 weChatPayCertFilePath: 平台证书绝对路径 notifyUrl: 支付成功的回调地址 refundNotifyUrl: 退款成功的回调地址
|
参数配置类 WeChatProperties
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import lombok.Data; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component;
@Component @ConfigurationProperties(prefix = "sky.wechat") @Data public class WeChatProperties {
private String appid; private String secret; private String mchid; private String mchSerialNo; private String privateKeyFilePath; private String apiV3Key; private String weChatPayCertFilePath; private String notifyUrl; private String refundNotifyUrl;
}
|
4.小程序下单生成预支付交易单
小程序下单 - 小程序支付 | 微信支付商户文档中心 (qq.com)
利用已经封装好的工具类来进行操作:WeChatPayUtil.java
OrdersPaymentDTO
1 2 3 4 5 6 7 8 9
| @Data public class OrdersPaymentDTO implements Serializable { private String orderNumber;
private Integer payMethod;
}
|
Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
@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); }
|
Service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public interface OrderService { OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO);
OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception;
void paySuccess(String outTradeNo);
}
|
ServiceImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
|
public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception { Long userId = BaseContext.getCurrentId(); User user = userMapper.selectById(userId);
JSONObject jsonObject = weChatPayUtil.pay( ordersPaymentDTO.getOrderNumber(), new BigDecimal(0.01), "苍穹外卖订单", user.getOpenid() );
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; }
public void paySuccess(String outTradeNo) {
LambdaQueryWrapper<Orders> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Orders::getNumber,outTradeNo); Orders ordersDB = orderMapper.selectOne(wrapper);
Orders orders = Orders.builder() .id(ordersDB.getId()) .status(Orders.TO_BE_CONFIRMED) .payStatus(Orders.PAID) .checkoutTime(LocalDateTime.now()) .build();
orderMapper.updateById(orders); }
|
OrderPaymentVO
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Data @Builder @NoArgsConstructor @AllArgsConstructor public class OrderPaymentVO implements Serializable {
private String nonceStr; private String paySign; private String timeStamp; private String signType; private String packageStr;
}
|
PayNotifyController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
|
@RestController @RequestMapping("/notify") @Slf4j public class PayNotifyController { @Autowired private OrderService orderService; @Autowired private WeChatProperties weChatProperties;
@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); }
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(); }
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; }
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(); } }
|
5.小程序调起支付
小程序调起支付 - 小程序支付 | 微信支付商户文档中心 (qq.com)
调用wx.requestPayment(OBJECT)发起微信支付
请求示例:
1 2 3 4 5 6 7 8 9 10 11 12 13
| wx.requestPayment 2( 3 { 4 "timeStamp": "1414561699", 5 "nonceStr": "5K8264ILTKCH16CQ2502SI8ZNMTM67VS", 6 "package": "prepay_id=wx201410272009395522657a690389285100", 7 "signType": "RSA", 8 "paySign": "xxxx", 9 "success":function(res){}, 10 "fail":function(res){}, 11 "complete":function(res){} 12 } 13)
|