02 - generate payment QR code

Keywords: Vue xml Java SDK

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>
Conclusion message: knowledge comes from accumulation, and peak comes from self-discipline
Published 9 original articles, won praise 1, visited 236
Private letter follow

Posted by anser316 on Sun, 16 Feb 2020 21:38:15 -0800