畅购商城之微信支付

流程图

1、JS版二维码

  • QRCode.js是一个用于生产二维码的JavaScript 库。
    • 主要是通过获取DOM的标签,再通过 HTML5 Canvas 绘制而成,不依赖任何库。
    • 通过document获得标签,此js库不能使用在nuxt.js服务端渲染中。

  • 后端:根据订单号生成微信支付的支付连接
  • 前端:根据支付连接生成对应的二维码

2、后端实现

  • pom
      <!--微信支付-->
        <dependency>
            <groupId>com.github.wxpay</groupId>
            <artifactId>wxpay-sdk</artifactId>
            <version>0.0.3</version>
        </dependency>
  • yml
server:
  port: 8100

spring:
  application:
    name: cgorderservice
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/changgou_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: 1234
    driver-class-name: com.mysql.jdbc.Driver
    druid:
      initial-size: 5
      min-idle: 5
      max-active: 20
      max-wait: 1000
      test-on-borrow: true
  redis:
    host: 127.0.0.1
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1
    instance-id: ${eureka.instance.ip-address}.${server.port}
    lease-renewal-interval-in-seconds: 3
    lease-expiration-duration-in-seconds: 10
sc:
  worker:
    workerId: 1
    datacenterId: 1
  jwt:
    secret: sc@Login(Auth}*^31)&czxy% # 登录校验的密钥
    pubKeyPath: D:/rsa/rsa.pub # 公钥地址
    priKeyPath: D:/rsa/rsa.pri # 私钥地址
    expire: 360 # 过期时间,单位分钟
  pay:
    appID: wx8397f8696b538317
    mchID: 1473426802
    key: T6m9iK73b0kn9g5v426MKfHQH7X8rKwb
    httpConnectTimeoutMs: 5000
    httpReadTimeoutMs: 10000
  • 配置类

package com.czxy.config;

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

import java.io.InputStream;

/**
 * @author 庭前云落
 * @Date 2020/5/8 15:12
 * @description
 */
@Data
@Component
@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;
    }
   private String notifyUrl;    //回调程序地址
}

  • 工具类:

    • PayState :枚举类,用于列举支付查询返回结果
    • PayHelper:工具类

  • PayState :枚举类,用于列举支付查询返回结果

    package com.czxy.utils;
    
    import lombok.Getter;
    
    /**
     * @author 庭前云落
     * @Date 2020/5/8 17:40
     * @description
     */
    @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.utils;

import com.czxy.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 庭前云落
 * @Date 2020/5/8 15:29
 * @description
 */
@Component
@EnableConfigurationProperties(PayProperties.class)
public class PayHelper {

    private WXPay wxPay;

    private PayProperties payProperties;

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

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

    public PayHelper() {

    }

    public PayHelper(PayProperties payProperties) {
        // 真实开发时
        wxPay = new WXPay(payProperties);
        // 测试时
        // wxPay = new WXPay(payProperties, WXPayConstants.SignType.MD5, true);
    }

    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;
        }
    }
}

  • controller
package com.czxy.controller;

import com.czxy.utils.PayHelper;
import com.czxy.vo.BaseResult;
import com.czxy.vo.PayRequest;
import com.github.wxpay.sdk.WXPayUtil;
import org.apache.commons.io.IOUtils;
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;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * @author 庭前云落
 * @Date 2020/5/8 17:43
 * @description
 */
@RestController
@RequestMapping("/pay")
public class PayController {

  @Resource
  private PayHelper payHelper;

  @PostMapping
  public BaseResult pay(@RequestBody PayRequest payRequest){
      String payUrl = payHelper.createPayUrl(payRequest.getSn());
      return BaseResult.ok("二维码生产成功").append("wxurl",payUrl);
  }

    @PostMapping("/callback")
    public void callback(HttpServletRequest request , HttpServletResponse response){

        try {
            //1 处理请求
            // 1.1 以流的方式,获得请求体(请求参数)
            ServletInputStream is = request.getInputStream();
            // 1.2 将流转换成字符串  "<xml></xml>"
            String xmlStr = IOUtils.toString(is, "UTF-8");
            // 1.3 将字符串转换Map
            Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);

            //2 获得订单号,修改状态
            if("SUCCESS".equals(map.get("return_code")) &&
                    "SUCCESS".equals(map.get("result_code"))){  //返回状态码  &&  业务结果
                String sn = map.get("out_trade_no");
                System.out.println(sn);

                //3 响应规定格式的内容
                // 3.1 响应类型
                response.setContentType("text/xml");
                // 3.2 响应内容
                response.getWriter().print("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
            } else {
                System.out.println("错误了");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3、前端实现

  • 获得微信支付的路径

    //获得微信支付路径  
    pay: (params) => {
            return axios.post("/cgorderservice/pay", params)
        }
    
  • 创建flow3组件,导入第三方资源(QRCode.js)

    • 页面加载成功后,获得支付路径,在指定位置处,渲染二维码
    <template>
      <div>
        <!-- 顶部导航 start -->
        <TopNav></TopNav>
        <!-- 顶部导航 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>
    
            	<p>
                    <div id="qrcode" style="width:256px;margin:0 auto;"></div>
                </p>
            <p class="message">
              完成支付后,你可以
              <a href>查看订单状态</a>
              <a href>继续购物</a>
              <a href>问题反馈</a>
            </p>
          </div>
        </div>
        <!-- 主体部分 end -->
    
        <div style="clear:both;"></div>
        <!-- 底部版权 start -->
        <Footer></Footer>
        <!-- 底部版权 end -->
      </div>
    </template>
    
    <script>
    import TopNav from "../components/TopNav";
    import Footer from "../components/Footer";
    export default {
      head: {
        title: "支付页面",
        link: [{ rel: "stylesheet", href: "/style/success.css" }],
        script: [{ type: "text/javascript", src: "/js/qrcode.min.js" },]
      },
      components: {
        TopNav,
        Footer
      },
      data() {
        return {
          sn: this.$route.query.sn
        };
      },
      async mounted() {
    
        let { data } = await this.$request.pay({ "sn": this.sn });
        new QRCode(document.getElementById("qrcode"), data.other.wxurl);
      }
    };
    </script>
    
    <style>
    #qrcode img {
      background-color: #fff;
      padding: 6px;
    }
    </style>
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值