畅购商城4.0 微信支付

畅购商城4.0
1.微信支付
1.1流程分析

1.2微信支付概述
1.2.1账号申请
步骤一:注册公众号,根据自身主体类型注册对应的公众号
只能申请服务号,订阅号没有办法申请支付
https://kf.qq.com/product/weixinmp.html#hid=87

步骤二:微信认证,公众号认证后才可申请微信支付

步骤三:申请微信支付
登录公众平台,点击左侧菜单【微信支付】,开始填写资料等待审核,审核时间为1-5个工作日内。

步骤四:商户账号审核
审核通过之后会往您填写的邮箱里发一封邮件是关于微信支付商户的帐号信息,同时您对公账户上也会收到几毛钱的汇款,需要您查看下具体的金额然后登录微信支付商户平台进行验证

步骤五:在线签署协议
本协议为线上电子协议,签署后方可进行交易及资金结算,签署完立即生效。

步骤六:完成上述步骤,你可以得到调用API用到的账号和密钥
appid:微信公众账号或开放平台APP的唯一标识
mch_id:商户号
key:商户密钥

1.2.2已有账号
以下为“传智播客”的微信支付账号
appid: wx8397f8696b538317
mch_id:1473426802
key: T6m9iK73b0kn9g5v426MKfHQH7X8rKwb

1.2.3支付接口和SDK(了解)
微信支付帮助文档地址:https://pay.weixin.qq.com/wiki/doc/api/index.html

手动调用,常见的接口(了解)
接口
下订单 https://api.mch.weixin.qq.com/pay/unifiedorder
查询订单 https://api.mch.weixin.qq.com/pay/orderquery
关闭订单 https://api.mch.weixin.qq.com/pay/closeorder

手动调用整体思路:
根据接口要求,组装请求参数
以XML的方式,通过POST请求,发送给支付接口
微信支付接口,以XML方式给予响应

实际开发中,我们很少直接使用“接口操作”。通常情况下使用微信提供的SDK(工具类)
com.github.wxpay.sdk.WXPay类就是核心操作封装类。

方法名 说明
microPay 刷卡支付
unifiedOrder 统一下单
orderQuery 查询订单
reverse 撤销订单
closeOrder 关闭订单
refund 申请退款
refundQuery 查询退款
downloadBill 下载对账单
report 交易保障
shortUrl 转换短链接
authCodeToOpenid 授权码查询openid

1.3入门案例
1.3.1 统一下单
在测试项目完成操作:test-wxpay
步骤一:添加依赖

com.github.wxpay
wxpay-sdk
0.0.3

步骤二:编写配置类,实现WXPayConfig接口

package com.czxy.test.pay;

import com.github.wxpay.sdk.WXPayConfig;

import java.io.InputStream;

/**

  • Created by liangtong.
    /
    public class MyWXPayConfig implements WXPayConfig {
    /
    *

    • 应用ID:微信开放平台审核通过的应用APPID
    • @return
      */
      @Override
      public String getAppID() {
      return “wx8397f8696b538317”;
      }

    /**

    • 商户号:微信支付分配的商户号
    • @return
      */
      @Override
      public String getMchID() {
      return “1473426802”;
      }

    /**

    • 秘钥,用于生成签名(sign)
    • @return
      */
      @Override
      public String getKey() {
      return “T6m9iK73b0kn9g5v426MKfHQH7X8rKwb”;
      }

    @Override
    public InputStream getCertStream() {
    return null;
    }

    /**

    • 连接超时时间,单位是毫秒
    • @return
      */
      @Override
      public int getHttpConnectTimeoutMs() {
      return 0;
      }

    /**

    • 读超时时间,单位是毫秒
    • @return
      */
      @Override
      public int getHttpReadTimeoutMs() {
      return 0;
      }
      }

步骤三:测试类
package com.czxy.test.pay;

import com.github.wxpay.sdk.WXPay;

import java.util.HashMap;
import java.util.Map;

/**

  • Created by liangtong.
    */
    public class TestPayUnifiedOrder {
    public static void main(String[] args) throws Exception {

     WXPay wxPay = new WXPay(new MyWXPayConfig());
    
     Map<String,String> map=new HashMap();
     map.put("body","畅购");                          //商品描述
     map.put("out_trade_no","20200401001");         //订单号
     map.put("total_fee","1");                       //金额
     map.put("spbill_create_ip","127.0.0.1");      //终端IP
     map.put("notify_url","http://www.baidu.com");//回调地址
     //JSAPI--JSAPI支付(或小程序支付)、NATIVE--Native支付、APP--app支付,MWEB--H5支付
     map.put("trade_type","NATIVE");              //交易类型
    
     Map<String, String> result = wxPay.unifiedOrder( map );
     System.out.println("支付结果:" + result.get("code_url"));
     System.out.println("返回状态码:" + result.get("return_code"));
     System.out.println("返回信息:" + result.get("return_msg"));
     System.out.println("业务结果:" + result.get("result_code"));
     System.out.println(result);
    

    }
    }

步骤四:结果
支付结果:weixin://wxpay/bizpayurl?pr=Mfqcl2R
返回状态码:SUCCESS
返回信息:OK
业务结果:SUCCESS

1.3.2查询订单
package com.czxy.test.pay;

import com.github.wxpay.sdk.WXPay;

import java.util.HashMap;
import java.util.Map;

/**

  • Created by liangtong.
    */
    public class TestPayOrderQuery {
    public static void main(String[] args) throws Exception {

     WXPay wxPay = new WXPay(new MyWXPayConfig());
    
     Map<String,String> map=new HashMap();
     map.put("out_trade_no","20200401001");         //订单号
    
     Map<String, String> result = wxPay.orderQuery( map );
     System.out.println("返回状态码:" + result.get("return_code"));
     System.out.println("返回信息:" + result.get("return_msg"));
     System.out.println("业务结果:" + result.get("result_code"));
     System.out.println("交易状态:" + result.get("trade_state"));
     /*
         SUCCESS—支付成功
         REFUND—转入退款
         NOTPAY—未支付
         CLOSED—已关闭
         REVOKED—已撤销(刷卡支付)
         USERPAYING--用户支付中
         PAYERROR--支付失败
      */
     System.out.println("交易状态:" + result.get("trade_state"));
     System.out.println("交易状态描述:" + result.get("trade_state_desc"));
     System.out.println(result);
    

    }
    }

1.4JS版二维码:QRCode.js
1.4.1概述
QRCode.js 是一个用于生成二维码的 JavaScript 库。主要是通过获取 DOM 的标签,再通过 HTML5 Canvas 绘制而成,不依赖任何库。

1.4.2入门案例
拷贝 qrcode.min.js

编写wxpay.html

二维码入门案例

http://localhost:3000/wxpay.html

1.5支付模块
1.5.1支付页面
步骤一:创建 flow3.vue组件

步骤二:引入第三方资源(js、css)

1.5.2接口
POST http://localhost:10010/order-service/pay
{
“sn” : “1255513323915579400”
}

1.5.3后端实现
步骤一:编写 PayRequest,用于封装数据

package com.czxy.changgou4.vo;

import lombok.Data;

/**

  • @author 桐叔
  • @email [email protected]
    */
    @Data
    public class PayRequest {
    private Long sn;
    }

步骤二:检查order服务,yml文件中是否有微信配置

sc:
pay:
appID: wx8397f8696b538317
mchID: 1473426802
key: T6m9iK73b0kn9g5v426MKfHQH7X8rKwb
httpConnectTimeoutMs: 5000
httpReadTimeoutMs: 10000

步骤三:编写PayProperties,用于加载微信配置

package com.czxy.changgou4.config;

import com.github.wxpay.sdk.WXPayConfig;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.io.InputStream;

/**

  • @author 桐叔

  • @email [email protected]
    */
    @Data
    @ConfigurationProperties(prefix = “sc.pay”)
    public class PayProperties implements WXPayConfig {

    private String appID; // 公众账号ID

    private String mchID; // 商户号

    private String key; // 生成签名的密钥

    private int httpConnectTimeoutMs; // 连接超时时间

    private int httpReadTimeoutMs; // 读取超时时间

    @Override
    public InputStream getCertStream() {
    //加载证书,需要通过账号中心生成
    return null;
    }

}

步骤四:编写PayState,自定义支付状态

package com.czxy.changgou4.utils;

import lombok.Getter;

/**

  • 自定义支付状态,微信支持多种状态,此处统一四种:

  • SUCCESS—支付成功、NOTPAY—未支付、CLOSED—已关闭、PAYERROR–支付失败

  • @author 桐叔

  • @email [email protected]
    */
    @Getter
    public enum PayState {
    NOT_PAY(0,“未支付”),SUCCESS(1,“支付成功”),CLOSED(2,“已关闭”),PAY_ERROR(3,“支付失败”);

    PayState(int code,String desc) {
    this.code = code;
    this.desc = desc;
    }
    private int code; //自定义编码
    private String desc; //描述信息
    }

步骤五:编写PayHelper,用于微信操作的工具类

package com.czxy.changgou4.utils;

import com.czxy.changgou4.config.PayProperties;
import com.github.wxpay.sdk.WXPay;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**

  • @author 桐叔

  • @email [email protected]
    */
    @Component
    @EnableConfigurationProperties(PayProperties.class)
    public class PayHelper {

    private WXPay wxPay;

    @Bean
    public WXPay wxPay(PayProperties payProperties){
    if(wxPay == null){
    wxPay = new WXPay(payProperties);
    }
    return wxPay;
    }

    private static final Logger logger = LoggerFactory.getLogger(PayHelper.class);

    public PayHelper() {

    }

    public PayHelper(PayProperties payProperties) {
    wxPay = new WXPay(payProperties);
    }

    public String createPayUrl(Long sn) {
    String key = “pay.url.” + sn;

     try {
         Map<String, String> data = new HashMap<>();
         // 商品描述
         data.put("body", "商城测试");
         // 订单号
         data.put("out_trade_no", sn.toString());
         //货币
         data.put("fee_type", "CNY");
         //金额,单位是分
         data.put("total_fee", "1");
         //调用微信支付的终端IP(商城的IP)
         data.put("spbill_create_ip", "127.0.0.1");
         //回调地址
         data.put("notify_url", "http://test.jingxi.com/wxpay/notify");
         // 交易类型为扫码支付
         data.put("trade_type", "NATIVE");
         //商品id,使用假数据
         data.put("product_id", "1234567");
    
         Map<String, String> result = this.wxPay.unifiedOrder(data);
         if ("SUCCESS".equals(result.get("return_code"))) {
             if("SUCCESS".equals(result.get("result_code"))){
                 String url = result.get("code_url");
    
                 return url;
             } else {
                 logger.error("创建预交易订单失败,错误信息:{}", result.get("err_code_des"));
                 return null;
             }
         } else {
             logger.error("创建预交易订单失败,错误信息:{}", result.get("return_msg"));
             return null;
         }
     } catch (Exception e) {
         logger.error("创建预交易订单异常", e);
         return null;
     }
    

    }

    /**

    • 查询订单状态
    • 交易状态参考:(trade_state)
      SUCCESS—支付成功
      REFUND—转入退款
      NOTPAY—未支付
      CLOSED—已关闭
      REVOKED—已撤销(付款码支付)
      USERPAYING–用户支付中(付款码支付)
      PAYERROR–支付失败(其他原因,如银行返回失败)
    • @param sn
    • @return
      */
      public PayState queryOrder(Long sn) {
      Map<String, String> data = new HashMap<>();
      // 订单号
      data.put(“out_trade_no”, sn.toString());
      try {
      Map<String, String> result = this.wxPay.orderQuery(data);
      if(“SUCCESS”.equals(result.get(“return_code”))){
      if(“SUCCESS”.equals(result.get(“result_code”))) {
      String tradeState = result.get(“trade_state”);
      if (“SUCCESS”.equals(tradeState)) {
      return PayState.SUCCESS;
      }
      if (“NOTPAY”.equals(tradeState)) {
      return PayState.NOT_PAY;
      }
      if (“CLOSED”.equals(tradeState)) {
      return PayState.CLOSED;
      }
      }
      }
      return PayState.PAY_ERROR;
      } catch (Exception e) {
      logger.error(“查询订单状态异常”, e);
      return PayState.PAY_ERROR;
      }
      }
      }

步骤五:编写PayService,调用工具类,用于生成支付接口

package com.czxy.changgou4.service;

import com.czxy.changgou4.vo.PayRequest;

/**

  • @author 桐叔

  • @email [email protected]
    */
    public interface PayService {

    public String pay(PayRequest payRequest);
    }

package com.czxy.changgou4.service.impl;

import com.czxy.changgou4.service.PayService;
import com.czxy.changgou4.utils.PayHelper;
import com.czxy.changgou4.vo.PayRequest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**

  • @author 桐叔

  • @email [email protected]
    */
    @Service
    public class PayServiceImpl implements PayService {
    @Resource
    private PayHelper payHelper;

    @Override
    public String pay(PayRequest payRequest) {
    //根据sn查询订单
    //获得微信支付路径
    String payUrl = payHelper.createPayUrl(payRequest.getSn());
    //返回支付路径
    return payUrl;

    }
    }

步骤六:编写PayController,根据sn生产微信支付路径

package com.czxy.changgou4.controller;

import com.czxy.changgou4.service.PayService;
import com.czxy.changgou4.vo.BaseResult;
import com.czxy.changgou4.vo.PayRequest;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**

  • @author 桐叔

  • @email [email protected]
    */
    @RestController
    @RequestMapping(“/pay”)
    public class PayController {

    @Resource
    private PayService payService;

    @PostMapping
    public BaseResult pay(@RequestBody PayRequest payRequest){
    //获得支付路径
    String payUrl = payService.pay(payRequest);
    //返回
    return BaseResult.ok(“二维码生产成功”).append(“wxurl”,payUrl);
    }

}

1.5.4前端实现
步骤一:修改apiclient.js文件,生成位置支付路径

pay : ( params ) => {
return axios.post(“/order-service/pay” ,params )
}

步骤二:拷贝qrcode.min.js 用于生成二维码

步骤三:导入qrcode.min.js

script: [
  { type: 'text/javascript', src: '/js/qrcode.min.js' }
]

步骤四:页面加载成功,把微信支付路径生产二维码
data() {
return {
sn: this.KaTeX parse error: Expected 'EOF', got '}' at position 21: ….query.sn, }̲ }, async m…request.pay({“sn”:this.sn})
new QRCode( document.getElementById(“qrcode”) , data.other.wxurl )
},

步骤五:确定二维码生成的位置

   

步骤六:优化,添加样式,

1.6内网穿透:
1.6.1概述
EchoSite一款收费的内网映射工具(已下架)
花生壳:内网穿透工具,免费版需要6元激活http映射,除了贵其他都不错。
神卓:内网穿透工具,价格相对比较便宜,但需要包年。

1.6.2注册用户
推荐码:
84cc732860786d78bd0cb90b5a0bdd9d8fc159a1

打开网址: https://www.echosite.cn/ ,点击右上角“控制台”进入登录页面,再进行注册

1.6.3抢注域名

1.6.4下载客户端
进入“客户端下载”界面,更加个人情况进行下载,我们下载的是“windows 客户端64位”

1.6.5编写配置文件
server_addr: “cross.echosite.cn:4443”
echosite_id: “18835954236”
echosite_token: “$2y 10 10 10P4EY42KG1al7XKAPTX6h2ukyZip1sgu5.BTWQF2U7EVSIcQGjNeZe”
tunnels:
changgou:
subdomain: java
proto:
http: 127.0.0.1:3000

1.6.6启动
echosite -config=config.yml start-all

1.6.7访问
本地访问
http://localhost:3000/wxpay.html

外网访问
http://java.cross.echosite.cn/wxpay.html

1.7内网穿透:神卓
1.7.1概述

1.7.2下载

1.7.3安装

1.7.4运行

1.8内网穿透:花生壳
1.8.1概述
花生壳是款具备内网穿透功能的软件。
花生壳内网穿透,是通过云服务器快速与内网服务器建立连接,同时把内网端口映射到云端,实现各类基于域名的互联网应用服务。

1.8.2下载

1.8.3安装

1.8.4配置

1.8.5访问
http://40m459492i.wicp.vip/order-service/swagger-ui.html

1.9Nuxt.js IP 启动

“config”: {
“nuxt”: {
“host”: “0.0.0.0”,
“port”: “3000”
}
},

1.10支付回调
1.10.1回调接口
步骤一:修改yml文件,添加notifyUrl配置
步骤二:修改配置文件
步骤三:修改工具类

步骤一:修改yml文件,添加notifyUrl配置

sc:
pay:
notifyUrl: http://40m459492i.wicp.vip/order-service/pay/callback

步骤二:修改配置文件

private String notifyUrl; //回调路径

步骤三:修改工具类

package com.czxy.changgou4.utils;

import com.czxy.changgou4.config.PayProperties;
import com.github.wxpay.sdk.WXPay;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**

  • @author 桐叔

  • @email [email protected]
    */
    @Component
    @EnableConfigurationProperties(PayProperties.class)
    public class PayHelper {

    private WXPay wxPay;
    private PayProperties payProperties;

    @Bean
    public WXPay wxPay(PayProperties payProperties){
    if(wxPay == null){
    this.payProperties = payProperties;
    wxPay = new WXPay(payProperties);
    }
    return wxPay;
    }

    private static final Logger logger = LoggerFactory.getLogger(PayHelper.class);

    public PayHelper() {

    }

    public PayHelper(PayProperties payProperties) {
    wxPay = new WXPay(payProperties);
    }

    public String createPayUrl(Long sn) {
    String key = “pay.url.” + sn;

     try {
         Map<String, String> data = new HashMap<>();
         // 商品描述
         data.put("body", "商城测试");
         // 订单号
         data.put("out_trade_no", sn.toString());
         //货币
         data.put("fee_type", "CNY");
         //金额,单位是分
         data.put("total_fee", "1");
         //调用微信支付的终端IP(商城的IP)
         data.put("spbill_create_ip", "127.0.0.1");
         //回调地址
         data.put("notify_url", this.payProperties.getNotifyUrl());
         // 交易类型为扫码支付
         data.put("trade_type", "NATIVE");
         //商品id,使用假数据
         data.put("product_id", "1234567");
    
         Map<String, String> result = this.wxPay.unifiedOrder(data);
         if ("SUCCESS".equals(result.get("return_code"))) {
             if("SUCCESS".equals(result.get("result_code"))){
                 String url = result.get("code_url");
    
                 return url;
             } else {
                 logger.error("创建预交易订单失败,错误信息:{}", result.get("err_code_des"));
                 return null;
             }
         } else {
             logger.error("创建预交易订单失败,错误信息:{}", result.get("return_msg"));
             return null;
         }
     } catch (Exception e) {
         logger.error("创建预交易订单异常", e);
         return null;
     }
    

    }

    /**

    • 查询订单状态
    • 交易状态参考:(trade_state)
      SUCCESS—支付成功
      REFUND—转入退款
      NOTPAY—未支付
      CLOSED—已关闭
      REVOKED—已撤销(付款码支付)
      USERPAYING–用户支付中(付款码支付)
      PAYERROR–支付失败(其他原因,如银行返回失败)
    • @param sn
    • @return
      */
      public PayState queryOrder(Long sn) {
      Map<String, String> data = new HashMap<>();
      // 订单号
      data.put(“out_trade_no”, sn.toString());
      try {
      Map<String, String> result = this.wxPay.orderQuery(data);
      if(“SUCCESS”.equals(result.get(“return_code”))){
      if(“SUCCESS”.equals(result.get(“result_code”))) {
      String tradeState = result.get(“trade_state”);
      if (“SUCCESS”.equals(tradeState)) {
      return PayState.SUCCESS;
      }
      if (“NOTPAY”.equals(tradeState)) {
      return PayState.NOT_PAY;
      }
      if (“CLOSED”.equals(tradeState)) {
      return PayState.CLOSED;
      }
      }
      }
      return PayState.PAY_ERROR;
      } catch (Exception e) {
      logger.error(“查询订单状态异常”, e);
      return PayState.PAY_ERROR;
      }
      }
      }

1.10.2后端实现
步骤一:修改PayController,添加callback方法
步骤二:检查网关,放行callback方法
步骤三:修改花生壳,访问10010端口

https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_7&index=8

步骤一:修改PayController,添加callback方法
@PostMapping(“/callback”)
public void callback(HttpServletRequest request, HttpServletResponse response) throws IOException {
try {
//1 获得响应内容
String xml = IOUtils.toString(request.getInputStream(), “UTF-8”);
System.out.println(xml);
//解析
Map<String, String> map = WXPayUtil.xmlToMap( xml );

    // 查询成功
    if("SUCCESS".equals(map.get( "result_code" )  )){

        // 获得订单号
        String sn = map.get("out_trade_no");

        //TODO  更新订单状态
        System.out.println(sn);

        //如果成功,给微信支付一个成功的响应
        response.setContentType("text/xml");
        String data = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
        response.getWriter().write(data);
    }

} catch (Exception e) {
    e.printStackTrace();
    response.setContentType("text/xml");
    String data = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA["+e.getMessage()+"]]></return_msg></xml>";
    response.getWriter().write(data);
}

}

步骤二:检查网关,放行callback方法

步骤三:修改花生壳,访问10010端口

查看控制台结果

<![CDATA[wx8397f8696b538317]]>
<bank_type><![CDATA[COMM_CREDIT]]></bank_type>
<cash_fee><![CDATA[1]]></cash_fee>
<fee_type><![CDATA[CNY]]></fee_type>
<is_subscribe><![CDATA[N]]></is_subscribe>
<mch_id><![CDATA[1473426802]]></mch_id>
<nonce_str><![CDATA[47e529ea929e4c9e847ee9699751a648]]></nonce_str>
<![CDATA[oNpSGwZaaw_0uBEMwFpkwIwFsttw]]>
<out_trade_no><![CDATA[1259484402174529500]]></out_trade_no>
<result_code><![CDATA[SUCCESS]]></result_code>
<return_code><![CDATA[SUCCESS]]></return_code>
<![CDATA[2D4BC610795C1DC303B0B26092D6C6E3]]>
<time_end><![CDATA[20200510220429]]></time_end>
<total_fee>1</total_fee>
<trade_type><![CDATA[NATIVE]]></trade_type>
<transaction_id><![CDATA[4200000568202005108477965385]]></transaction_id>

1259484402174529500

1.11查看支付状态
1.11.1后端实现
步骤一:修改PayService,查询订单支付状态
步骤二:编写PayService实现类
步骤三:修改PayController

步骤一:修改PayService,查询订单支付状态
package com.czxy.changgou4.service;

import com.czxy.changgou4.utils.PayState;
import com.czxy.changgou4.vo.PayRequest;

/**

  • @author 桐叔
  • @email [email protected]
    /
    public interface PayService {
    /
    *
    • 查看支付状态
    • @param sn
    • @return
      */
      public PayState query(Long sn);
      }

步骤二:编写PayService实现类
@Override
public PayState query(Long sn) {
//查询微信支付状态
PayState payState = payHelper.queryOrder(sn);
return payState;

}

步骤三:修改PayController
@GetMapping(“/{sn}”)
public BaseResult query(@PathVariable(“sn”) Long sn){
//查询
PayState payState = payService.query(sn);
//返回
if(payState.getCode() == 1) {
return BaseResult.ok(payState.getDesc());
}
return BaseResult.error(payState.getDesc());
}

1.11.2前端实现
如果订单已经支付,跳转到支付成功页面。

步骤一:修改api.js,查询订单支付状态
步骤二:修改flow3,“查询订单状态”绑定事件
步骤三:修改flow3,编写事件,如果是成功,调到到flow4
步骤四:编写flow4,与flow3基本内容一致,提示信息为“支付成功,货物即将送出!”

步骤一:修改api.js,查询订单支付状态
findPayStatus : ( sn ) => {
return axios.get(“/cgorderservice/pay/”+sn )
}

步骤二:修改flow3,“查询订单状态”绑定事件

步骤三:修改flow3,编写事件,如果是成功,调到到flow4
methods: {
async findPayStatusFn() {
let { data } = await this.$request.findPayStatus( this.sn );
if( data.code == 1) {
location.href = ‘flow4’
} else {
alert( data.message );
}
}
},

步骤四:编写flow4,与flow3基本内容一致,提示信息为“支付成功,货物即将送出!”

    </div>
    <div class="topnav_right fr">
      <ul>
        <li>您好,欢迎来到畅购![<a href="login.html">登录</a>] [<a href="register.html">免费注册</a>] </li>
        <li class="line">|</li>
        <li>我的订单</li>
        <li class="line">|</li>
        <li>客户服务</li>

      </ul>
    </div>
  </div>
</div>
<!-- 顶部导航 end -->

<div style="clear:both;"></div>

<!-- 页面头部 start -->
<div class="header w990 bc mt15">
  <div class="logo w990">
    <h2 class="fl"><a href="index.html"><img src="images/logo.png" alt="畅购商城"></a></h2>
    <div class="flow fr flow3">
      <ul>
        <li>1.我的购物车</li>
        <li>2.填写核对订单信息</li>
        <li class="cur">3.成功提交订单</li>
      </ul>
    </div>
  </div>
</div>
<!-- 页面头部 end -->

<div style="clear:both;"></div>

<!-- 主体部分 start -->
<div class="success w990 bc mt15">
  <div class="success_hd">
    <h2>订单支付成功</h2>
  </div>
  <div class="success_bd">
    <p><span></span>支付成功,货物即将送出!</p>
  </div>
</div>
<!-- 主体部分 end -->

<div style="clear:both;"></div>
<!-- 底部版权 start -->
<Footer></Footer>
<!-- 底部版权 end -->

1.12前置技术:RabbitMQ

1.13更新订单状态
步骤一:配置环境,
rabbitmq中添加order_pay队列
添加依赖
添加yml配置
步骤二:修改回调函数,将sn存放到rabbit中
步骤三:编写监听器(消费者),更新订单状态
步骤四:修改OrderService,完成修改功能
步骤五:修改OrderMapper,完成修改功能

步骤一:配置环境,
rabbitmq中添加order_pay队列,添加rabbit配置类

package com.czxy.changgou4.config;

import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

/**

  • @author 桐叔

  • @email [email protected]
    */
    @Component
    public class OrderPayQueue {

    private static final String ORDER_PAY_QUEUE = “order_pay”;

    @Bean
    public Queue queue() {
    return new Queue(ORDER_PAY_QUEUE);
    }
    }

添加依赖

org.springframework.boot spring-boot-starter-amqp

添加yml配置

spring:
rabbitmq:
host: 127.0.0.1
username: guest
password: guest

步骤二:修改回调函数,将sn存放到rabbit中

rabbitTemplate.convertAndSend(“”, “order_pay”, sn);

步骤三:编写监听器(消费者),更新订单状态
package com.czxy.changgou4.listener;

import com.czxy.changgou4.service.OrderService;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**

  • @author 桐叔

  • @email [email protected]
    */
    @Component
    @RabbitListener(queues = “order_pay”)
    public class OrderPayListener {

    @Autowired
    private OrderService orderService;

    /**

    • 更新支付状态
    • @param message
      */
      @RabbitHandler
      public void updatePayStatus(String message){
      orderService.updatePayStatus( message , “1” );
      }
      }

步骤四:修改OrderService,完成修改功能
package com.czxy.changgou4.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.czxy.changgou4.pojo.Order;
import com.czxy.changgou4.pojo.User;
import com.czxy.changgou4.vo.CartVo;
import com.czxy.changgou4.vo.OrderVo;

import java.util.List;

public interface OrderService extends IService {

void updatePayStatus(String sn, String status);

}

package com.czxy.changgou4.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.czxy.changgou4.pojo.Order;
import com.czxy.changgou4.pojo.OrderGoods;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

@Service
@Transactional
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
@Override
public void updatePayStatus(String sn, String status) {
//更新状态
baseMapper.updateStatus(sn,status);
}
}

步骤五:修改OrderMapper,完成修改功能
package com.czxy.changgou4.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.czxy.changgou4.pojo.Order;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;

@Mapper
public interface OrderMapper extends BaseMapper {
/**
* 更加sn修改状态
* @param sn
* @param status
*/
@Update(“UPDATE tb_order SET STATUS = #{status} WHERE sn = #{sn}”)
void updateStatus(@Param(“sn”) String sn, @Param(“status”) String status);
}

测试:在rabbitMQ web控制台,可以手动发布消息

1.14推送服务
1.14.1需求
当用户完成扫码支付成功后,自动跳转到支付成功页面。
我们可以采用“服务端推送”来完成。

1.14.2服务端推送方案
服务器端推送,主要有三种实现方案
Ajax 短轮询:Ajax 轮询主要通过页面端的 JS 定时异步刷新任务来实现数据的加载。
缺点:这种方式实时效果较差,而且对服务端的压力也较大
长轮询:长轮询主要也是通过 Ajax 机制,但区别于传统的 Ajax 应用,长轮询的服务器端会在没有数据时阻塞请求直到有新的数据产生或者请求超时才返回,之后客户端再重新建立连接获取数据。
缺点:长轮询服务端会长时间地占用资源,如果消息频繁发送的话会给服务端带来较大的压力。
WebSocket 双向通信:WebSocket 是 HTML5 中一种新的通信协议,能够实现浏览器与服务器之间全双工通信。

1.14.3RabbitMQ Web STOMP 插件
借助于 RabbitMQ 的 Web STOMP 插件,实现浏览器与服务端的全双工通信。
从本质上说,RabbitMQ 的 Web STOMP 插件也是利用 WebSocket 对 STOMP 协议进行了一次桥接,从而实现浏览器与服务端的双向通信。

1.14.4安装插件
rabbitmq-plugins enable rabbitmq_web_stomp rabbitmq_web_stomp_examples

注意:需要重启RabbitMQ

访问http://localhost:15670 可以看到stomp的例子代码

1.14.5入门案例
步骤一:从实例代码中,拷贝stomp.js
步骤二:创建 stomp.html ,编写如下内容

Document

//2. 设置调试函数
// client.debug = function(str) {
// console.info(‘---------------’ + str)
// };
client.debug = false

//3.1 连接成功回调函数
var on_connect = function(x) {
id = client.subscribe(“/queue/changgou_test”, function(d) {
console.info(‘@@@@@@’ + d.body);
});
};
//3.2 连接失败回调函数
var on_error = function() {
console.log(‘error’);
};
//3.3 连接RabbitMQ ,connect(账号,密码,成功回调,失败回调,host)
client.connect(‘guest’, ‘guest’, on_connect, on_error, ‘/’);

//4 发送数据
function send(obj){
client.send(‘/queue/changgou_test’, {“content-type”:“text/plain”}, obj.value);
}

1.14.6自动显示支付成功
步骤一:在RabbitMQ中创建queue, order_pay_auto

package com.czxy.changgou4.config;

import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

/**

  • @author 桐叔

  • @email [email protected]
    */
    @Component
    public class OrderPayQueue {

    public static final String ORDER_PAY_QUEUE = “order_pay”;
    public static final String ORDER_PAY_AUTO_QUEUE = “order_pay_auto”;

    @Bean(ORDER_PAY_QUEUE)
    public Queue queue() {
    return new Queue(ORDER_PAY_QUEUE);
    }

    @Bean(ORDER_PAY_AUTO_QUEUE)
    public Queue queueAuto() {
    return new Queue(ORDER_PAY_AUTO_QUEUE);
    }
    }

步骤二:支付成功后,将订单号发送到RabbitMQ中,进行服务端消息推送

步骤三:修改 flow3组件,页面加载成功后,与后端服务建立连接

autoChange() {
//1. 创建客户端
var client = Stomp.client(‘ws://localhost:15674/ws’);

  //2. 设置调试函数
  client.debug = false

  //3.1 连接成功回调函数 ,需要使用箭头函数,否则this.sn无法获得数据
  var on_connect = (x) => {
    client.subscribe("/queue/order_pay_auto", (d) => {
      if(this.sn == d.body){
        location.href = 'flow4'
      }
    });
  };
  //3.2 连接失败回调函数
  var on_error =  function() {
    console.log('error');
  };
  //3.3 连接RabbitMQ ,connect(账号,密码,成功回调,失败回调,host)
  client.connect('guest', 'guest', on_connect, on_error, '/');
}

步骤四:编写flow4页面

    </div>
    <div class="topnav_right fr">
      <ul>
        <li>您好,欢迎来到畅购![<a href="login.html">登录</a>] [<a href="register.html">免费注册</a>] </li>
        <li class="line">|</li>
        <li>我的订单</li>
        <li class="line">|</li>
        <li>客户服务</li>

      </ul>
    </div>
  </div>
</div>
<!-- 顶部导航 end -->

<div style="clear:both;"></div>

<!-- 页面头部 start -->
<div class="header w990 bc mt15">
  <div class="logo w990">
    <h2 class="fl"><a href="index.html"><img src="images/logo.png" alt="畅购商城"></a></h2>
    <div class="flow fr flow3">
      <ul>
        <li>1.我的购物车</li>
        <li>2.填写核对订单信息</li>
        <li class="cur">3.成功提交订单</li>
      </ul>
    </div>
  </div>
</div>
<!-- 页面头部 end -->

<div style="clear:both;"></div>

<!-- 主体部分 start -->
<div class="success w990 bc mt15">
  <div class="success_hd">
    <h2>订单支付成功</h2>
  </div>
  <div class="success_bd">
    <p><span></span>支付成功,货物即将送出!</p>
  </div>
</div>
<!-- 主体部分 end -->

<div style="clear:both;"></div>
<!-- 底部版权 start -->
<Footer></Footer>
<!-- 底部版权 end -->

猜你喜欢

转载自blog.csdn.net/qq_58432443/article/details/130677657
今日推荐