Hello everyone, I'm the white book demon!
Knowledge comes from accumulation, the peak comes from self-discipline
Today, I have sorted out some small knowledge points based on some documents, notes and other materials I have learned before. If there are any improper points, you are welcome to correct them
1, Add dependency
Add wechat sdk dependency in service order
<dependency> <groupId>com.github.wxpay</groupId> <artifactId>wxpay-sdk</artifactId> <version>0.0.3</version> </dependency>
2. Configure yml parameters
WeChat parameter
weixin: pay: #Associated official account appid appid: wx74862e0dfcf69954 #Merchant number partner: 1558950191 #Merchant key partnerkey: T6m9iK73b0kn9g5v426MKfHQH7X8rKwb #token url notifyurl: http://guli.shop/api/order/weixinPay/weixinNotify
redis parameter
spring: redis: host: 39.106.16.235 port: 6379 database: 0 timeout: 1800000 password: 123456 jedis: pool: max-active: 20 #maximum connection max-wait: -1 #Maximum blocking waiting time (negative indicates unlimited) max-idle: 5 #Maximum idle time min-idle: 0 #Minimum idle time
3. Parameter reading tool class
package com.atguigu.guli.service.order.util; @Data @Component //Note that prefix is written before the last "." @ConfigurationProperties(prefix="weixin.pay") public class WeixinPayProperties { private String appid; private String partner; private String partnerkey; private String notifyurl; }
4. httpClinet tool class
HttpClient.java put into the current project
2, Generate payment QR code according to order number
1. API: unified order interface document
https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1
2. Auxiliary business method
OrderService: getOrderByOrderNo
Interface:
/** * Query order according to order No * @param orderNo * @return */ Order getOrderByOrderNo(String orderNo);
Realization:
/** * Query Order entity according to order No * * @param orderNo * @return */ public Order getOrderByOrderNo(String orderNo) { QueryWrapper<Order> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("order_no", orderNo); return orderMapper.selectOne(queryWrapper); }
3. Order business (generate payment QR code)
Create WeixinPayService: createNative
Interface:
package com.atguigu.guli.service.order.service; public interface WeixinPayService { /** * Order according to order number, generate payment link * @param orderNo * @return */ Map<String, Object> createNative(String orderNo, String remoteAddr); }
Realization:
package com.atguigu.guli.service.order.service.impl; @Service @Slf4j public class WeixinPayServiceImpl implements WeixinPayService { @Autowired private OrderService orderService; @Autowired private RedisTemplate redisTemplate; @Autowired private WeixinPayProperties weixinPayProperties; /** * Order according to order number, generate payment link * @param orderNo * @return */ @Override public Map<String, Object> createNative(String orderNo, String remoteAddr) { try { Map<String, Object> payMap = (Map)redisTemplate.opsForValue().get(orderNo); if(payMap != null) { return payMap; } Order order = orderService.getOrderByOrderNo(orderNo); Map<String, String> m = new HashMap<>(); //1. Set parameters m.put("appid", weixinPayProperties.getAppid()); m.put("mch_id", weixinPayProperties.getPartner()); m.put("nonce_str", WXPayUtil.generateNonceStr()); m.put("body", order.getCourseTitle()); m.put("out_trade_no", orderNo); int totalFee = order.getTotalFee().multiply(new BigDecimal("100")).intValue(); //Convert to string, otherwise there will be java.lang.Integer cannot be cast to java.lang.String in generateSignedXml below m.put("total_fee", totalFee + ""); m.put("spbill_create_ip", remoteAddr); m.put("notify_url", weixinPayProperties.getNotifyurl()); m.put("trade_type", "NATIVE"); //2. HTTP client to access the third-party interface according to the URL and pass the parameters HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder"); //client setting parameters client.setXmlParam(WXPayUtil.generateSignedXml(m, weixinPayProperties.getPartnerkey())); client.setHttps(true); client.post(); //3. Return third party data String xml = client.getContent(); Map<String, String> resultMap = WXPayUtil.xmlToMap(xml); //4. Encapsulate return result set System.out.println(xml); System.out.println(resultMap.get("return_code")); System.out.println(resultMap.get("return_msg")); System.out.println(resultMap.get("err_code")); System.out.println(resultMap.get("err_code_des")); if("FAIL".equals(resultMap.get("return_code")) || "FAIL".equals(resultMap.get("result_code")) ){ log.error("Unified order error - " + "return_msg: " + resultMap.get("return_msg") + ", " + "err_code: " + resultMap.get("err_code") + ", " + "err_code_des: " + resultMap.get("err_code_des")); throw new GuliException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR); } Map<String, Object> map = new HashMap<>(); map.put("result_code", resultMap.get("result_code")); map.put("code_url", resultMap.get("code_url")); map.put("course_id", order.getCourseId()); map.put("total_fee", order.getTotalFee()); map.put("out_trade_no", orderNo); //Wechat payment QR code expires in 2 hours, and the order can be cancelled in 2 hours without payment redisTemplate.opsForValue().set(orderNo, map, 120, TimeUnit.MINUTES); return map; } catch (Exception e) { log.error(ExceptionUtils.getMessage(e)); throw new GuliException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR); } } }
4. Single interface
ApiWeixinPayController: createNative
package com.atguigu.guli.service.order.controller.api; @RestController @RequestMapping("/api/order/weixinPay") @Api(description = "Website wechat payment") @CrossOrigin //Cross domain @Slf4j public class ApiWeixinPayController { @Autowired private WeixinPayService weixinPayService; /** * Generate QR code * * @return */ @GetMapping("/createNative/{orderNo}") public R createNative(@PathVariable String orderNo, HttpServletRequest request) { String remoteAddr = request.getRemoteAddr(); Map map = weixinPayService.createNative(orderNo, remoteAddr); return R.ok().data(map); } }
3, Payment front end
According to the QR code url returned from the wechat payment order interface, generate QR code on the page, and call the payment query interface regularly according to the order number to check whether the payment is successful. If the payment is successful, return to the course details page to watch the course video
1. Install QR code generator
npm install vue-qriously@1.1.1
2. Configure plug-ins
Create plugins / vue-qrious-plugin.js
import Vue from 'vue' import VueQriously from 'vue-qriously' Vue.use(VueQriously)
Configuration in nuxt.config.js
plugins: [ { src: '~/plugins/vue-qriously-plugin.js', ssr: false } ],
3,api
Create api/pay.js
import request from '@/utils/request' const apiPath = '/api/order/weixinPay' export default { createNative(orderId) { return request({ baseURL: 'http://localhost:8170', url: `${apiPath}/createNative/${orderId}`, method: 'get' }) } }
4. Payment page
Create pages/pay/_id.vue
<template> <div class="cart py-container"> <!--Main content--> <div class="checkout py-container pay"> <div class="checkout-tit"> <h4 class="fl tit-txt"><span class="success-icon"/><span class="success-info">Order submitted successfully, please pay in time! Order number:{{ payObj.out_trade_no }}</span> </h4> <span class="fr"><em class="sui-lead">Amount payable:</em><em class="orange money">¥{{ payObj.total_fee }}</em></span> <div class="clearfix"/> </div> <div class="checkout-steps"> <div class="fl weixin">WeChat payment</div> <div class="fl sao"> <p class="red">Please use wechat to scan.</p> <div class="fl code"> <!-- <img id="qrious" src="~/assets/img/erweima.png" alt=""> --> <qriously :value="payObj.code_url" :size="338"/> <div class="saosao"> <p>Please use wechat to scan</p> <p>Scan QR code payment</p> </div> </div> </div> <div class="clearfix"/> <!-- <p><a href="pay.html" target="_blank">> Other payment methods</a></p> --> </div> </div> </div> </template> <script> import pay from '~/api/pay' export default { async asyncData({ params }) { const response = await pay.createNative(params.id) return { payObj: response.data.data } }, // Get the data in created and report Invalid prop: type check failed for prop "value" // created() { // pay.createNative(this.$route.params.id).then(response => { // this.payObj = response.data.data // }) // } } </script>