当前位置:   article > 正文

spring cloud vue2 实现微信支付功能(全是干货)_vue2接入微信扫码支付

vue2接入微信扫码支付

目录

前言:

完整代码:

前端代码:

后端代码:

所需依赖:

代码部分:

config:

service:

创建订单功能详解: 

 创建二维码核心功能:

 返回订单状态核心功能:

成功结果返回核心功能: 

controller层:

 以上的代码还包含与实际业务有关的其他功能 比如rabbitmq的死信队列 分布式feign调用等,可以注释掉不使用


前言:

 点击购买按钮,创建二维码,让用户可以进行扫码支付。具体流程如下图

 

 我们主要负责商户后台系统的编写。

完整代码:

前端代码:

  1. <!-- 微信支付二维码-->
  2. <el-dialog :visible.sync="dialogFormVisible" :before-close="cancelOrder" :modal="true" :close-on-click-modal="false" style="width:800px;margin:0px auto;" >
  3. <h1 style="font-size:30px;color:#00B38A" >微信扫一扫支付</h1>
  4. <img id="qrcode" :src="wxpayUrl">
  5. <h2 id="statusText"></h2>
  6. <p id="closeText"></p>
  7. </el-dialog>
  8. <!-- 底部购买 -->
  9. <div
  10. class="public-class-footer"
  11. slot="bottom"
  12. style="border:1px solid #eee; height:60px; text-align:left;"
  13. >
  14. <span class="product-descript" style="font-size:.347rem"
  15. >成就自己</span
  16. >
  17. <span class="current-price" style="font-size:28px">
  18. <span class="current-price-unite" style="font-size:.347rem">
  19. ¥</span
  20. >{{course.discounts}}
  21. </span>
  22. <span class="current-price price">
  23. <span class="current-price-unite"></span>
  24. {{course.price}}
  25. </span>
  26. <button
  27. @click="buy(course.id)"
  28. type="button"
  29. class="weui-btn purchase-button weui-btn_mini weui-btn_primary"
  30. style="width:155px;height:45px;font-size:17px;"
  31. >
  32. 立即购买
  33. <!-- ::after -->
  34. </button>
  1. // 购买课程
  2. buy() {
  3. if( this.user != null ){
  4. this.dialogFormVisible = true; //显示提示框
  5. //微信下单
  6. console.log("user.id:"+this.user.id)
  7. console.log("course.id:"+this.course.id)
  8. console.log("activityId:"+this.course.activity.id)
  9. let args = {"userId":this.user.id,"courseId":this.course.id,"activityId":this.course.activity.id,"price":1};
  10. this.axios.post("/wxpay/makeOrder",this.qs.stringify(args))
  11. .then(res => {
  12. console.log(res.data);
  13. //利用返回的code_url,显示支付二维码
  14. this.wxpayUrl = "http://localhost:9000/wxpay/code?url="+res.data.code_url;
  15. console.log(this.wxpayUrl);
  16. //检查后台返回的订单号支付状态
  17. this.checkOrder(res.data.trade_no);
  18. });
  19. }else{
  20. this.$message.error("购买失败,请先登录!");
  21. }
  22. },
  23. //检查订单号支付状态 websocket
  24. checkOrder(tradeNo){
  25. console.log("订单的tradeno:"+tradeNo)
  26. let count = 0;
  27. //定时1分钟轮询检查
  28. let timer = setInterval(() =>{
  29. this.axios.get("/wxpay/checkOrder?tradeNo="+tradeNo)
  30. .then(res => {
  31. console.log(res.data +"," + count);
  32. if(res.data == "SUCCESS"){
  33. clearInterval(timer);
  34. this.dialogFormVisible = false;
  35. }
  36. });
  37. count++;
  38. if(count == 10){
  39. clearInterval(timer);
  40. this.dialogFormVisible = false;
  41. this.$message.error("支付超时");
  42. }
  43. },6000);
  44. },

this.axios.post("/wxpay/makeOrder",this.qs.stringify(args))

.then(res => {
  console.log(res.data);
  //利用返回的code_url,显示支付二维码
  this.wxpayUrl = "http://localhost:9000/wxpay/code?url="+res.data.code_url;
  console.log(this.wxpayUrl);
  //检查后台返回的订单号支付状态
  this.checkOrder(res.data.trade_no);
});

 注:估计现在很多人一脸懵逼,二维码怎么莫名其妙生成了,记得往后面看,前端只不过是调接口,后端才是满满干货。

后端代码:

所需依赖:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>com.dmdd</groupId>
  7. <artifactId>educate_paopao</artifactId>
  8. <version>0.0.1-SNAPSHOT</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.example</groupId>
  12. <artifactId>edu-pay-service</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>edu-pay-service</name>
  15. <description>edu-pay-service</description>
  16. <properties>
  17. <java.version>8</java.version>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-web</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework.boot</groupId>
  26. <artifactId>spring-boot-starter-test</artifactId>
  27. <scope>test</scope>
  28. </dependency>
  29. <dependency>
  30. <groupId>com.github.wxpay</groupId>
  31. <artifactId>wxpay-sdk</artifactId>
  32. <version>0.0.3</version>
  33. </dependency>
  34. <!-- https://mvnrepository.com/artifact/com.google.zxing/core -->
  35. <dependency>
  36. <groupId>com.google.zxing</groupId>
  37. <artifactId>core</artifactId>
  38. <version>3.3.3</version>
  39. </dependency>
  40. <!-- https://mvnrepository.com/artifact/com.google.zxing/javase -->
  41. <dependency>
  42. <groupId>com.google.zxing</groupId>
  43. <artifactId>javase</artifactId>
  44. <version>3.3.3</version>
  45. </dependency>
  46. <dependency>
  47. <groupId>org.springframework.cloud</groupId>
  48. <artifactId>spring-cloud-config-client</artifactId>
  49. </dependency>
  50. <dependency>
  51. <groupId>com.alibaba.cloud</groupId>
  52. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  53. </dependency>
  54. <dependency>
  55. <groupId>com.dmdd</groupId>
  56. <artifactId>common-api</artifactId>
  57. <version>0.0.1-SNAPSHOT</version>
  58. </dependency>
  59. <dependency>
  60. <groupId>com.alibaba.cloud</groupId>
  61. <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  62. </dependency>
  63. <!--rabitmq-->
  64. <dependency>
  65. <groupId>org.springframework.boot</groupId>
  66. <artifactId>spring-boot-starter-amqp</artifactId>
  67. </dependency>
  68. <dependency>
  69. <groupId>org.springframework.cloud</groupId>
  70. <artifactId>spring-cloud-starter-openfeign</artifactId>
  71. </dependency>
  72. </dependencies>
  73. <build>
  74. <plugins>
  75. <plugin>
  76. <groupId>org.springframework.boot</groupId>
  77. <artifactId>spring-boot-maven-plugin</artifactId>
  78. </plugin>
  79. </plugins>
  80. </build>
  81. </project>

我用的功能比较多,所以依赖有点杂,我把只跟微信支付相关的依赖列出来,并讲解

<dependency>
    <groupId>com.github.wxpay</groupId>
    <artifactId>wxpay-sdk</artifactId>
    <version>0.0.3</version>
</dependency>

调用微信的api就需要这依赖

<!-- https://mvnrepository.com/artifact/com.google.zxing/core -->
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>core</artifactId>
    <version>3.3.3</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.google.zxing/javase -->
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>javase</artifactId>
    <version>3.3.3</version>
</dependency>

这两个依赖是用于生成二维码的,二维码只不过是一个链接,我们扫码,就等于访问一个链接

代码部分:

config:

  1. package com.dmdd.edupayservice.config;
  2. import com.github.wxpay.sdk.WXPayConfig;
  3. import java.io.InputStream;
  4. public class MyWXPayConfig implements WXPayConfig {
  5. @Override
  6. public String getAppID() {
  7. return "wx30************e";
  8. }
  9. @Override
  10. public String getMchID() {
  11. return "15**********81";
  12. }
  13. @Override
  14. public String getKey() {
  15. return "HJd*******************g";
  16. }
  17. @Override
  18. public InputStream getCertStream() {
  19. return null;
  20. }
  21. @Override
  22. public int getHttpConnectTimeoutMs() {
  23. return 0;
  24. }
  25. @Override
  26. public int getHttpReadTimeoutMs() {
  27. return 0;
  28. }
  29. }

需要向微信申请才可获得

service:

  1. package com.dmdd.edupayservice.service.impl;
  2. import com.dmdd.common.entity.UserCourseOrder;
  3. import com.dmdd.edupayservice.config.MyWXPayConfig;
  4. import com.dmdd.edupayservice.config.RabbitMQConfig;
  5. import com.dmdd.edupayservice.feign.CourseServiceFeignClient;
  6. import com.dmdd.edupayservice.feign.OrderServiceFeignClient;
  7. import com.dmdd.edupayservice.service.IWxPayService;
  8. import com.github.wxpay.sdk.WXPay;
  9. import com.github.wxpay.sdk.WXPayUtil;
  10. import com.google.zxing.BarcodeFormat;
  11. import com.google.zxing.EncodeHintType;
  12. import com.google.zxing.MultiFormatWriter;
  13. import com.google.zxing.client.j2se.MatrixToImageWriter;
  14. import com.google.zxing.common.BitMatrix;
  15. import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
  16. import lombok.extern.slf4j.Slf4j;
  17. import org.apache.tomcat.util.http.fileupload.util.Streams;
  18. import org.springframework.amqp.rabbit.core.RabbitTemplate;
  19. import org.springframework.beans.factory.annotation.Autowired;
  20. import org.springframework.http.ResponseEntity;
  21. import org.springframework.stereotype.Service;
  22. import javax.servlet.http.HttpServletRequest;
  23. import javax.servlet.http.HttpServletResponse;
  24. import java.io.Console;
  25. import java.io.IOException;
  26. import java.sql.Timestamp;
  27. import java.time.LocalDateTime;
  28. import java.util.HashMap;
  29. import java.util.Map;
  30. import java.util.UUID;
  31. /**
  32. * 微信支付Service
  33. */
  34. @Slf4j
  35. @Service
  36. public class WxPayServiceImpl implements IWxPayService {
  37. @Autowired
  38. private CourseServiceFeignClient courseServiceFeignClient;
  39. @Autowired
  40. private OrderServiceFeignClient orderServiceFeignClient;
  41. @Autowired
  42. private RabbitTemplate rabbitTemplate;
  43. public static final String DEVICE_INFO = "WEB";
  44. public static final String BODY = "dmdd";
  45. public static final String FEE_TYPE = "CNY";
  46. //回调接口的URL
  47. public static final String NOTIFY_URL = "http://ygp8pz4342342ee.cc/wxpay/callback";
  48. public static final String TRADE_TYPE = "NATIVE";
  49. public static final String SIGN = "5E00F9F72173C9449F802411E362012312312317078";
  50. /**
  51. * 下单
  52. */
  53. public Map<String, String> makeWxOrder(long userId, long courseId, long activityId, long price) throws Exception {
  54. //创建支付对象
  55. MyWXPayConfig config = new MyWXPayConfig();
  56. WXPay wxPay = new WXPay(config);
  57. //配置微信支付
  58. Map<String, String> map = new HashMap<>();
  59. //应用id
  60. map.put("appid", config.getAppID());
  61. //商户id
  62. map.put("mch_id", config.getMchID());
  63. //device_info web
  64. map.put("device_info", DEVICE_INFO);
  65. map.put("nonce_str", WXPayUtil.generateNonceStr());
  66. map.put("body", BODY);
  67. //创建随机订单号
  68. String tradeNo = UUID.randomUUID().toString().replace("-", "");
  69. map.put("out_trade_no", tradeNo);
  70. //FEE_TYPE=CNY 代表人民币
  71. map.put("fee_type", FEE_TYPE);
  72. //价格
  73. map.put("total_fee", String.valueOf(price));
  74. //微信对商户后台的回调接口,更新订单状态
  75. map.put("notify_url", NOTIFY_URL);
  76. map.put("trade_type", TRADE_TYPE);
  77. map.put("product_id", String.valueOf(activityId));
  78. //执行统一下单
  79. Map<String, String> result = wxPay.unifiedOrder(map);
  80. log.info("微信下单:{}", result);
  81. if (result != null) {
  82. //保存订单号
  83. result.put("trade_no", tradeNo);
  84. //创建课程订单
  85. Timestamp now = Timestamp.valueOf(LocalDateTime.now());
  86. UserCourseOrder order = new UserCourseOrder(System.currentTimeMillis(), userId, courseId, activityId, 1L, 0, tradeNo, price, now, now, 0);
  87. orderServiceFeignClient.makeOrder(order);
  88. //减少课程库存
  89. courseServiceFeignClient.reduceStock(activityId);
  90. //发送订单号,超时会进入死信队列
  91. rabbitTemplate.convertAndSend(RabbitMQConfig.ORDER_EXCHANGE, RabbitMQConfig.ORDER_QUEUE_KEY, tradeNo,
  92. //消息的后置处理
  93. message -> {
  94. message.getMessageProperties().setMessageId(UUID.randomUUID().toString());
  95. //设置消息超时
  96. message.getMessageProperties().setExpiration(String.valueOf(30 * 1000));
  97. return message;
  98. });
  99. log.info("完成下单,订单:{}", result);
  100. }
  101. return result;
  102. }
  103. @Override
  104. public void makeQRCode(String url, HttpServletResponse response) {
  105. //通过支付链接生成二维码
  106. HashMap<EncodeHintType, Object> hints = new HashMap<>();
  107. hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
  108. hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
  109. hints.put(EncodeHintType.MARGIN, 2);
  110. try {
  111. //把code_url包装到二维码图片
  112. BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 200, 200, hints);
  113. MatrixToImageWriter.writeToStream(bitMatrix, "PNG", response.getOutputStream());
  114. log.info("创建二维码完成");
  115. } catch (Exception e) {
  116. e.printStackTrace();
  117. }
  118. }
  119. @Override
  120. /**
  121. * 检查订单状态
  122. */
  123. public String checkWxOrder(String tradeNo) throws Exception {
  124. MyWXPayConfig config = new MyWXPayConfig();
  125. WXPay pay = new WXPay(config);
  126. Map<String, String> map = new HashMap<>();
  127. map.put("appid", config.getAppID());
  128. map.put("mch_id", config.getMchID());
  129. map.put("nonce_str", WXPayUtil.generateNonceStr());
  130. map.put("out_trade_no", tradeNo);
  131. map.put("sign", SIGN);
  132. //查询订单
  133. Map<String, String> res = pay.orderQuery(map);
  134. String state = res.get("trade_state");
  135. log.info("订单" + tradeNo + ",状态" + state);
  136. return state;
  137. }
  138. @Override
  139. public void wxpayCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
  140. //获得微信传来的xml字符串
  141. String str = Streams.asString(request.getInputStream());
  142. //将字符串xml转换为Map
  143. Map<String, String> map = WXPayUtil.xmlToMap(str);
  144. //给微信发送消息
  145. response.getWriter().println("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
  146. //读取订单号
  147. String tradeNo = map.get("out_trade_no");
  148. //查询课程id
  149. ResponseEntity<UserCourseOrder> entity = orderServiceFeignClient.getOrderByTradeNo(tradeNo);
  150. UserCourseOrder order = entity.getBody();
  151. //增加课程销量
  152. log.info("课程id为" + order.getCourseId());
  153. log.info("order:" + order);
  154. courseServiceFeignClient.addCourseSales(order.getCourseId());
  155. // //修改订单状态为已支付
  156. order.setStatus(1);
  157. orderServiceFeignClient.changeOrderStatus(order);
  158. log.info("支付成功:{}", order);
  159. }
  160. }

创建订单功能详解: 

public static final String BODY = "dmdd";

app的名字,随便取。

public static final String FEE_TYPE = "CNY";

表示支付的货币类型是人民币。

//回调接口的URL
public static final String NOTIFY_URL = "http://ygp8pz.natappfree.cc/wxpay/callback";

 

 微信服务会跟我们的后端发送一个一个请求,告诉我们商户支付结果,因为企业内部都是把服务部署到内网里面,所以想要微信访问就得用内网穿透这种技术,顾名思义就是外网可以访问内网。

//微信对商户后台的回调接口,更新订单状态
map.put("notify_url", NOTIFY_URL);

创建订单的时候把回调url的信息也存入订单中

那么如何内网穿透?

到natapp官网申请隧道,下载软件

"http://ygp8pz.natappfree.cc/wxpay/callback"

表示从外网访问 内网7777服务器内的wxpay/callback的请求。

 

 嫌麻烦这一块也可以不搞,不影响微信支付的功能。

订单创建返回结果如下,红色框框勾出来的url就是调用微信支付功能的url,我们需要把这个url转换成二维码

 创建二维码核心功能:

//把code_url包装到二维码图片
BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 200, 200, hints);
MatrixToImageWriter.writeToStream(bitMatrix, "PNG", response.getOutputStream());
log.info("创建二维码完成");

创建二维码图片的核心功能。

 返回订单状态核心功能:

public static final String SIGN = "5E00F9************************8";

认证签名,只有正确的签名wx才会接受你的返回

WXPay pay = new WXPay(config);
//查询订单
Map<String, String> res = pay.orderQuery(map);

得到wx返回给我们的支付状态,不懂?看下面

支付有没有成功,看上面的打印就知道了。玩过连连看的,应该都看得懂。 

注:大伙应该都点过外卖,在支付超时的时间之内,每隔一段时间就会通知我们支付结果。

成功结果返回核心功能: 

根据自己的实际需求来。

controller层

  1. package com.dmdd.edupayservice.controller;
  2. import com.dmdd.edupayservice.service.IWxPayService;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.util.StringUtils;
  6. import org.springframework.web.bind.annotation.PostMapping;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.RestController;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;
  11. import java.util.Map;
  12. @RestController
  13. @Slf4j
  14. @RequestMapping("wxpay")
  15. public class WXOrderController {
  16. @Autowired
  17. private IWxPayService payService;
  18. /**
  19. * 微信下单
  20. */
  21. @PostMapping("makeOrder")
  22. public Map<String,String> makeOrder(Long userId, Long courseId, Long activityId, Long price) throws Exception {
  23. //微信下单
  24. return payService.makeWxOrder(userId,courseId, activityId, price);
  25. }
  26. /**
  27. * 生成支付二维码
  28. * @param url
  29. * @param response
  30. */
  31. @RequestMapping("code")
  32. public void createWxPayCode(String url, HttpServletResponse response){
  33. //创建支付二维码
  34. payService.makeQRCode(url,response);
  35. log.info("生成微信支付二维码:{}",url);
  36. }
  37. /**
  38. * 检查订单状态
  39. */
  40. @RequestMapping("checkOrder")
  41. public String checkOrder(String tradeNo) throws Exception {
  42. if (StringUtils.isEmpty(tradeNo)) {
  43. return null;
  44. }
  45. String status = payService.checkWxOrder(tradeNo);
  46. log.info("检查订单{} 状态:{}",tradeNo,status);
  47. return status;
  48. }
  49. /**
  50. * 微信支付平台支付成功的回调
  51. * @param request
  52. * @param response
  53. * @throws Exception
  54. */
  55. @RequestMapping("callback")
  56. public void paySuccessCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
  57. payService.wxpayCallback(request,response);
  58. }
  59. }

 以上的代码还包含与实际业务有关的其他功能 比如rabbitmq的死信队列 分布式feign调用等,可以注释掉不使用

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号