赞
踩
目录
以上的代码还包含与实际业务有关的其他功能 比如rabbitmq的死信队列 分布式feign调用等,可以注释掉不使用
点击购买按钮,创建二维码,让用户可以进行扫码支付。具体流程如下图
我们主要负责商户后台系统的编写。
- <!-- 微信支付二维码-->
- <el-dialog :visible.sync="dialogFormVisible" :before-close="cancelOrder" :modal="true" :close-on-click-modal="false" style="width:800px;margin:0px auto;" >
- <h1 style="font-size:30px;color:#00B38A" >微信扫一扫支付</h1>
- <img id="qrcode" :src="wxpayUrl">
- <h2 id="statusText"></h2>
- <p id="closeText"></p>
- </el-dialog>
-
- <!-- 底部购买 -->
- <div
- class="public-class-footer"
- slot="bottom"
- style="border:1px solid #eee; height:60px; text-align:left;"
- >
- <span class="product-descript" style="font-size:.347rem"
- >成就自己</span
- >
- <span class="current-price" style="font-size:28px">
- <span class="current-price-unite" style="font-size:.347rem">
- ¥</span
- >{{course.discounts}}
- </span>
- <span class="current-price price">
- <span class="current-price-unite">¥</span>
- {{course.price}}
- </span>
- <button
- @click="buy(course.id)"
- type="button"
- class="weui-btn purchase-button weui-btn_mini weui-btn_primary"
- style="width:155px;height:45px;font-size:17px;"
- >
- 立即购买
- <!-- ::after -->
- </button>
- // 购买课程
- buy() {
- if( this.user != null ){
- this.dialogFormVisible = true; //显示提示框
- //微信下单
- console.log("user.id:"+this.user.id)
- console.log("course.id:"+this.course.id)
- console.log("activityId:"+this.course.activity.id)
- let args = {"userId":this.user.id,"courseId":this.course.id,"activityId":this.course.activity.id,"price":1};
-
- 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);
- });
- }else{
- this.$message.error("购买失败,请先登录!");
- }
- },
-
- //检查订单号支付状态 websocket
- checkOrder(tradeNo){
- console.log("订单的tradeno:"+tradeNo)
- let count = 0;
- //定时1分钟轮询检查
- let timer = setInterval(() =>{
- this.axios.get("/wxpay/checkOrder?tradeNo="+tradeNo)
- .then(res => {
- console.log(res.data +"," + count);
- if(res.data == "SUCCESS"){
- clearInterval(timer);
- this.dialogFormVisible = false;
- }
- });
- count++;
- if(count == 10){
- clearInterval(timer);
- this.dialogFormVisible = false;
- this.$message.error("支付超时");
- }
- },6000);
- },
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); });
注:估计现在很多人一脸懵逼,二维码怎么莫名其妙生成了,记得往后面看,前端只不过是调接口,后端才是满满干货。
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>com.dmdd</groupId>
- <artifactId>educate_paopao</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <relativePath/> <!-- lookup parent from repository -->
- </parent>
- <groupId>com.example</groupId>
- <artifactId>edu-pay-service</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <name>edu-pay-service</name>
- <description>edu-pay-service</description>
- <properties>
- <java.version>8</java.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>com.github.wxpay</groupId>
- <artifactId>wxpay-sdk</artifactId>
- <version>0.0.3</version>
- </dependency>
-
- <!-- 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>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-config-client</artifactId>
- </dependency>
-
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
- </dependency>
-
- <dependency>
- <groupId>com.dmdd</groupId>
- <artifactId>common-api</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- </dependency>
-
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
- </dependency>
-
- <!--rabitmq-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-amqp</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-openfeign</artifactId>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
-
- </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>这两个依赖是用于生成二维码的,二维码只不过是一个链接,我们扫码,就等于访问一个链接
- package com.dmdd.edupayservice.config;
-
- import com.github.wxpay.sdk.WXPayConfig;
-
- import java.io.InputStream;
-
- public class MyWXPayConfig implements WXPayConfig {
- @Override
- public String getAppID() {
- return "wx30************e";
- }
-
- @Override
- public String getMchID() {
- return "15**********81";
- }
-
- @Override
- public String getKey() {
- return "HJd*******************g";
- }
-
- @Override
- public InputStream getCertStream() {
- return null;
- }
-
- @Override
- public int getHttpConnectTimeoutMs() {
- return 0;
- }
-
- @Override
- public int getHttpReadTimeoutMs() {
- return 0;
- }
- }
需要向微信申请才可获得
- package com.dmdd.edupayservice.service.impl;
-
- import com.dmdd.common.entity.UserCourseOrder;
- import com.dmdd.edupayservice.config.MyWXPayConfig;
- import com.dmdd.edupayservice.config.RabbitMQConfig;
- import com.dmdd.edupayservice.feign.CourseServiceFeignClient;
- import com.dmdd.edupayservice.feign.OrderServiceFeignClient;
- import com.dmdd.edupayservice.service.IWxPayService;
- import com.github.wxpay.sdk.WXPay;
- import com.github.wxpay.sdk.WXPayUtil;
- import com.google.zxing.BarcodeFormat;
- import com.google.zxing.EncodeHintType;
- import com.google.zxing.MultiFormatWriter;
- import com.google.zxing.client.j2se.MatrixToImageWriter;
- import com.google.zxing.common.BitMatrix;
- import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.tomcat.util.http.fileupload.util.Streams;
- import org.springframework.amqp.rabbit.core.RabbitTemplate;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.http.ResponseEntity;
- import org.springframework.stereotype.Service;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.io.Console;
- import java.io.IOException;
- import java.sql.Timestamp;
- import java.time.LocalDateTime;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.UUID;
-
- /**
- * 微信支付Service
- */
- @Slf4j
- @Service
- public class WxPayServiceImpl implements IWxPayService {
- @Autowired
- private CourseServiceFeignClient courseServiceFeignClient;
- @Autowired
- private OrderServiceFeignClient orderServiceFeignClient;
-
-
- @Autowired
- private RabbitTemplate rabbitTemplate;
-
- public static final String DEVICE_INFO = "WEB";
- public static final String BODY = "dmdd";
- public static final String FEE_TYPE = "CNY";
- //回调接口的URL
- public static final String NOTIFY_URL = "http://ygp8pz4342342ee.cc/wxpay/callback";
- public static final String TRADE_TYPE = "NATIVE";
- public static final String SIGN = "5E00F9F72173C9449F802411E362012312312317078";
-
- /**
- * 下单
- */
- public Map<String, String> makeWxOrder(long userId, long courseId, long activityId, long price) throws Exception {
- //创建支付对象
- MyWXPayConfig config = new MyWXPayConfig();
- WXPay wxPay = new WXPay(config);
- //配置微信支付
- Map<String, String> map = new HashMap<>();
- //应用id
- map.put("appid", config.getAppID());
- //商户id
- map.put("mch_id", config.getMchID());
- //device_info web
- map.put("device_info", DEVICE_INFO);
- map.put("nonce_str", WXPayUtil.generateNonceStr());
- map.put("body", BODY);
- //创建随机订单号
- String tradeNo = UUID.randomUUID().toString().replace("-", "");
- map.put("out_trade_no", tradeNo);
- //FEE_TYPE=CNY 代表人民币
- map.put("fee_type", FEE_TYPE);
- //价格
- map.put("total_fee", String.valueOf(price));
- //微信对商户后台的回调接口,更新订单状态
- map.put("notify_url", NOTIFY_URL);
- map.put("trade_type", TRADE_TYPE);
- map.put("product_id", String.valueOf(activityId));
- //执行统一下单
- Map<String, String> result = wxPay.unifiedOrder(map);
- log.info("微信下单:{}", result);
- if (result != null) {
- //保存订单号
- result.put("trade_no", tradeNo);
- //创建课程订单
- Timestamp now = Timestamp.valueOf(LocalDateTime.now());
- UserCourseOrder order = new UserCourseOrder(System.currentTimeMillis(), userId, courseId, activityId, 1L, 0, tradeNo, price, now, now, 0);
- orderServiceFeignClient.makeOrder(order);
- //减少课程库存
- courseServiceFeignClient.reduceStock(activityId);
- //发送订单号,超时会进入死信队列
- rabbitTemplate.convertAndSend(RabbitMQConfig.ORDER_EXCHANGE, RabbitMQConfig.ORDER_QUEUE_KEY, tradeNo,
- //消息的后置处理
- message -> {
- message.getMessageProperties().setMessageId(UUID.randomUUID().toString());
- //设置消息超时
- message.getMessageProperties().setExpiration(String.valueOf(30 * 1000));
- return message;
- });
- log.info("完成下单,订单:{}", result);
- }
- return result;
- }
-
- @Override
- public void makeQRCode(String url, HttpServletResponse response) {
- //通过支付链接生成二维码
- HashMap<EncodeHintType, Object> hints = new HashMap<>();
- hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
- hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
- hints.put(EncodeHintType.MARGIN, 2);
- try {
- //把code_url包装到二维码图片
- BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 200, 200, hints);
- MatrixToImageWriter.writeToStream(bitMatrix, "PNG", response.getOutputStream());
- log.info("创建二维码完成");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- @Override
- /**
- * 检查订单状态
- */
- public String checkWxOrder(String tradeNo) throws Exception {
- MyWXPayConfig config = new MyWXPayConfig();
- WXPay pay = new WXPay(config);
- Map<String, String> map = new HashMap<>();
- map.put("appid", config.getAppID());
- map.put("mch_id", config.getMchID());
- map.put("nonce_str", WXPayUtil.generateNonceStr());
- map.put("out_trade_no", tradeNo);
- map.put("sign", SIGN);
- //查询订单
- Map<String, String> res = pay.orderQuery(map);
- String state = res.get("trade_state");
- log.info("订单" + tradeNo + ",状态" + state);
- return state;
- }
-
- @Override
- public void wxpayCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
- //获得微信传来的xml字符串
- String str = Streams.asString(request.getInputStream());
- //将字符串xml转换为Map
- Map<String, String> map = WXPayUtil.xmlToMap(str);
- //给微信发送消息
- response.getWriter().println("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
- //读取订单号
- String tradeNo = map.get("out_trade_no");
- //查询课程id
- ResponseEntity<UserCourseOrder> entity = orderServiceFeignClient.getOrderByTradeNo(tradeNo);
- UserCourseOrder order = entity.getBody();
- //增加课程销量
- log.info("课程id为" + order.getCourseId());
- log.info("order:" + order);
- courseServiceFeignClient.addCourseSales(order.getCourseId());
- // //修改订单状态为已支付
- order.setStatus(1);
- orderServiceFeignClient.changeOrderStatus(order);
- log.info("支付成功:{}", order);
- }
-
-
- }
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返回给我们的支付状态,不懂?看下面
支付有没有成功,看上面的打印就知道了。玩过连连看的,应该都看得懂。
注:大伙应该都点过外卖,在支付超时的时间之内,每隔一段时间就会通知我们支付结果。
根据自己的实际需求来。
- package com.dmdd.edupayservice.controller;
-
- import com.dmdd.edupayservice.service.IWxPayService;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.util.StringUtils;
- import org.springframework.web.bind.annotation.PostMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.util.Map;
- @RestController
- @Slf4j
- @RequestMapping("wxpay")
- public class WXOrderController {
- @Autowired
- private IWxPayService payService;
-
- /**
- * 微信下单
- */
- @PostMapping("makeOrder")
- public Map<String,String> makeOrder(Long userId, Long courseId, Long activityId, Long price) throws Exception {
- //微信下单
- return payService.makeWxOrder(userId,courseId, activityId, price);
- }
-
- /**
- * 生成支付二维码
- * @param url
- * @param response
- */
- @RequestMapping("code")
- public void createWxPayCode(String url, HttpServletResponse response){
- //创建支付二维码
- payService.makeQRCode(url,response);
- log.info("生成微信支付二维码:{}",url);
- }
-
-
- /**
- * 检查订单状态
- */
- @RequestMapping("checkOrder")
- public String checkOrder(String tradeNo) throws Exception {
- if (StringUtils.isEmpty(tradeNo)) {
- return null;
- }
- String status = payService.checkWxOrder(tradeNo);
- log.info("检查订单{} 状态:{}",tradeNo,status);
- return status;
- }
-
- /**
- * 微信支付平台支付成功的回调
- * @param request
- * @param response
- * @throws Exception
- */
- @RequestMapping("callback")
- public void paySuccessCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
- payService.wxpayCallback(request,response);
- }
- }
以上的代码还包含与实际业务有关的其他功能 比如rabbitmq的死信队列 分布式feign调用等,可以注释掉不使用
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。