微信支付 SpringCloud+Vue

微信支付

1、创建二维码

1、安装 qrcodejs2 (注意:安装的是qrcodejs2,不要安装qrcode ---> 会报错)

npm install  qrcodejs2 --save

2、页面中引入

<el-dialog :visible.sync="dialogFormVisible" style="width:800px;margin:0px auto;" >
  <h1 style="font-size:30px;color:#00B38A">微信扫一扫支付</h1>
  <div id="qrcode" style="width:210px;margin:20px auto;"></div>
</el-dialog>

<script>
import QRCode from 'qrcodejs2'; // 引入qrcodejs

export default {
  name: "Index",
  components: {
    Header,
    Footer,
    QRCode  // 声明组件
  },
  data() {
    return {
      dialogFormVisible: false, // 是否显示登录框,true:显示,false:隐藏
    };
  },
  methods: {
    // 购买课程
    buy(courseid) {
      //alert("购买第【" + courseid + "】门课程成功,加油!");
      this.dialogFormVisible = true; //显示提示框

      // 待dom更新之后再用二维码渲染其内容
      this.$nextTick(function(){
          this.createCode(); // 直接调用会报错:TypeError: Cannot read property 'appendChild' of null
      });
    },
    // 生成二维码
    createCode(){
      // QRCode(存放二维码的dom元素id,二维码的属性参数)
      let qrcode = new QRCode('qrcode',{
         width:200,  // 二维码的宽度
         height:200,  // 二维码的高度
         text:"我爱你中国"  // 二维码中包含的信息
      });
    },
  },
};
</script>

2、准备工作

2.1 名词介绍

参数说明
appid微信公众帐号或开放平台APP的唯一标识
partner商户号(配置文件中的partner:账户)
partnerkey商户密钥(密码)
sign数字签名,根据微信官方提供的密钥和一套算法生成的一个加密信息,就是为了保证交易安全
  • 如果获得这些信息?

    • 需要注册认证公众号,费用300元/次

2.2 获取认证的流程

1) 注册公众号(类型:服务号)

根据营业执照类型选择以下主体注册: 个体工商户 | 企业/公司 | 政府 | 媒体 | 其他类型

2) 认证公众号

公众号认证后才申请微信支付:300元/次

3) 提交材料申请微信支付

登录公众平台,左侧菜单【微信支付】,开始填写资料等待审核,审核时间1~5工作日 这里需要提交的资料有营业执照!

4) 开户成功,登录商户平台进行验证

资料审核通过后,请登录联系人邮箱查收商户号和密码,并登录商户平台填写财付通备付金打的小额资金数额,完成账户验证。

5) 在线签署协议

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

6) 查看自己的公众号的参数

public class PayConfig {
    //企业公众号ID
    public static String appid="wx307113892f15a42e";
    //财付通平台的商户帐号
    public static String partner="1508236581";
    //财付通平台的商户密钥
    public static String partnerKey="HJd7sHGHd6djgdgFG5778GFfhghghgfg";
    //回调URL
    public static String notifyurl="http://localhost:8004/order/wxCallback";
}

3、支付流程

4、工具介绍

4.1 SDK

https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=11_1

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

主要使用sdk中的三个功能:

1、获取随机字符串(生成订单编号)

WXPayUtil.generateNonceStr();

2、将map转换成xml字符串(自动添加签名)

WXPayUtil.generateSignedXml(map,partnerKey);

3、将xml字符串转换整map

WXPayUtil.xmlToMap(result);

4.2 JFinal 框架

  • JFinal 是基于Java 语言的极速 web 开发框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展

  • 取代HttpClient

    <dependency>
        <groupId>com.jfinal</groupId>
        <artifactId>jfinal</artifactId>
        <version>3.5</version>
    </dependency>

    5、构建二维码

  • Course.vue
    <script>
    //  生成二维码
        createCode () {
          this.axios
            .get("http://localhost:80/order/createCode", {
              params: {
                courseid: this.course.id,  // 课程编号
                courseid: this.course.courseName, // 课程名称
                price: this.course.discounts,  // 优惠价,非原价
              },
            })
            .then((result) => {
              console.log(result);
              let qrcode = new QRCode('qrcode',{
                width:200,
                height:200,
                text:result.data.code_url  // 将支付连接嵌入到二维码中
              });
            })
            .catch((error) => {
              this.$message.error("二维码生成失败!");
            });
        }
    </script>

    支付配置

    public class PayConfig {
        //企业公众号ID
        public static String appid="wx307113892f15a42e";
        //财付通平台的商户帐号
        public static String partner="1508236581";
        //财付通平台的商户密钥
        public static String partnerKey="HJd7sHGHd6djgdgFG5778GFfhghghgfg";
        //回调URL
        public static String notifyurl="http://localhost:8004/order/wxCallback";
    }

    createCodeController

    import com.alibaba.fastjson.JSON;
    import com.github.wxpay.sdk.WXPayUtil;
    import com.jfinal.kit.HttpKit;
    import commons.PayConfig;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @RestController
    @RequestMapping("order")
    public class PayAction {
    
        @GetMapping("createCode")
        public Object createCode(String courseid,String coursename, String price) throws Exception {
    
            //1.编写商户信息
            Map<String,String> mm = new HashMap();
            mm.put("appid",PayConfig.appid); //公众账号ID
            mm.put("mch_id",PayConfig.mchid);//商户号
            mm.put("nonce_str",WXPayUtil.generateNonceStr());//随机字符串
            mm.put("body",coursename); //商品名称
            String orderId = WXPayUtil.generateNonceStr();
            System.out.println("订单编号 = "+orderId);
            mm.put("out_trade_no",orderId); //商户订单号
            mm.put("total_fee",price+""); //订单金额,单位分
            mm.put("spbill_create_ip","127.0.0.1"); //终端IP
            mm.put("notify_url",PayConfig.notifyurl); //通知地址
            mm.put("trade_type","NATIVE"); //交易类型
            System.out.println("发送的map = "+mm.toString());
            
            //2.生成数字签名,并把上面的map转换成xml格式
            String xml = WXPayUtil.generateSignedXml(mm,PayConfig.partnerKey);
            System.out.println("转换后的xml = "+xml);
    
            //3.将数据发送给微信后台,并得到微信后台返回的数据
            String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            String result = HttpKit.post(url,xml);
            System.out.println("返回的xml = "+result); //如果报错:<![CDATA[签名错误]]> 商户四要素的原因,重置商户API密钥。
    
            //4.后台返回的xml格式,转成map,并添加两个参数
            Map<String,String> resultMap = WXPayUtil.xmlToMap(result);
            resultMap.put("orderId",orderId);
            resultMap.put("money",price+"");
    
            //5.将map返回给浏览器
            return resultMap;
        }
        
        
        @RequestMapping("wxCallback")
        public String wxCallBack(HttpServletRequest request, HttpServletResponse response) throws IOException {
            InputStream inStream = null;
            ByteArrayOutputStream outSteam = null;
            String resultxml = null;
            try {
                inStream = request.getInputStream();
                outSteam = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int len = 0;
                while ((len = inStream.read(buffer)) != -1) {
                    outSteam.write(buffer, 0, len);
                }
                resultxml = new String(outSteam.toByteArray(), "utf-8");
            } catch (Exception e) {
                System.out.println("回调处理失败");
            }finally {
                if(null != outSteam) {
                    outSteam.close();
                }
                if(null != inStream) {
                    inStream.close();
                }
            }
            System.out.println("wxCallback - 回调请求参数:"+ resultxml);
            return resultxml;
        }
    }

    coursename = new String(coursename.getBytes("ISO-8859-1"),"UTF-8");

    6、检查支付状态

    <!-- 微信支付二维码-->
    <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>
      <div id="qrcode" style="width:210px;margin:20px auto;"></div>
      <h2 id="statusText"></h2>
      <p id="closeText"></p>
    </el-dialog>
    <script>
    data() {
        return {
          time:null // 定时器
        };
    },
    // 生成二维码
    createCode(){
      // 将上一次的二维码清除,防止出现多个二维码
      document.getElementById("qrcode").innerHTML = "";
    
      // 去获取支付连接
      this.axios
        .get("http://localhost:8004/order/createCode",{
          params:{
            courseid: this.course.id,
            coursename: this.course.courseName,
            price:1, //测试支付金额固定为1分钱,真实上线环境再改回此真实价钱:this.course.discounts
          }
        })
        .then((result) => {
          console.log(result);
          // QRCode(存放二维码的dom元素id,二维码的属性参数)
          let qrcode = new QRCode('qrcode',{
            width:200,
            height:200,
            text:result.data.code_url  // 将返回的数据嵌入到二维码中
          });
    
          this.orderNo = result.data.orderId;
    
          // 保存订单, 状态为:已创建 0
          this.saveOrder();
    
          // 检查支付状态
          this.axios
            .get("http://localhost:8004/order/checkOrderStatus",{
              params:{
                orderId: result.data.orderId // 传递 订单编号 进行查询
              }
            })
            .then((result) => {
              console.log(result.data.trade_state);
              if(result.data.trade_state=="SUCCESS"){
                document.getElementById("statusText").innerHTML = "<i style='color:#00B38A' class='el-icon-success'></i> 支付成功!";
                // 支付成功
                this.updateOrder(20);
    
                // 3秒后关闭二维码窗口
                let s = 3;
                this.closeQRForm(s);
    
    
              }
              /*
              else if(result.data.trade_state=="NOTPAY"){
                document.getElementById("statusText").innerHTML = "<i style='color:#00B38A' class='el-icon-success'></i> 未支付!";
                this.updateOrder(10);
              }
              */
            })
            .catch( (error)=>{
              this.$message.error("查询订单失败!");
            });
        })
        .catch( (error)=>{
          this.$message.error("生成二维码失败!");
          console.log(error);
        });
    },
    // 倒计时关闭二维码窗口
    closeQRForm( s ){
      let that = this;
      that.time = setInterval(function(){
        document.getElementById("closeText").innerHTML = "( "+ s-- +" ) 秒后关闭本窗口";
        if(s == 0){
          clearInterval(that.time); // 停止计时器
          that.dialogFormVisible = false; // 二维码窗口隐藏
          that.isBuy = true; // 修改购买状态(已购买)
    
        }
      }, 1000);
    
       this.$router.go(0);//刷新页面
    },
    // 保存订单
    saveOrder(){
      return this.axios
        .get("http://localhost:8003/order/saveOrder",{
          params:{
            orderNo:this.orderNo,
            user_id: this.user.content.id,
            course_id:this.course.id,
            activity_course_id:this.course.id,
            source_type:1,
          }
        })
        .then((result) => {
          // console.log(result);
          console.log("保存订单");
        })
        .catch( (error)=>{
          this.$message.error("保存订单失败!");
      });
    },
    // 更新订单的状态
    updateOrder(statusCode){
      return this.axios
        .get("http://localhost:8003/order/updateOrder",{
          params:{
            orderNo:this.orderNo,
            status:statusCode,
          }
        })
        .then((result) => {
           console.log("更新订单【"+this.orderNo+"】状态:" + statusCode);
        }).catch( (error)=>{
           this.$message.error("更新订单失败!");
        });
    },
    // 取消订单
    cancelOrder(){
      this.dialogFormVisible= false;
    
      return this.axios
        .get("http://localhost:8003/order/deleteOrder",{
          params:{
            orderno:this.orderNo,
          }
        })
        .then((result) => {
          // console.log(result);
          console.log("取消订单");
        })
        .catch( (error)=>{
          this.$message.error("取消订单失败!");
      });
    }
    </script>
    @GetMapping("createCode")
    public Object createCode(String courseid,String coursename,String price) throws Exception {
        // 省略...
        // 查询订单状态需要订单编号,所以将订单编号保存并返回给前端
        resultMap.put("out_trade_no",mm.get("out_trade_no"));
        return resultMap;
    }
    @GetMapping("checkOrderStatus")
    public Object checkOrderStatus(String orderId) throws Exception {
        //1.编写商户信息
        Map<String,String> mm = new HashMap();
        mm.put("appid",PayConfig.appid); //公众账号ID
        mm.put("mch_id",PayConfig.partner);//商户号
        mm.put("out_trade_no",orderId);//订单编号
        mm.put("nonce_str",WXPayUtil.generateNonceStr()); //随机字符串
        System.out.println(mm);
        //2.生成数字签名,并把上面的map转换成xml格式
        String xml = WXPayUtil.generateSignedXml(mm, PayConfig.partnerKey);
        System.out.println(xml);
    
        //3.将数据发送给微信后台,并得到微信后台返回的数据
        String url = "https://api.mch.weixin.qq.com/pay/orderquery";
    
        //第一次询问时间
        long beginTime = System.currentTimeMillis();
    
        while(true) { //不停的去微信后台询问是否支付
            String result = HttpKit.post(url, xml);
            System.out.println(result);//报错:<![CDATA[签名错误]]>
    
            //4.后台返回的xml格式,转成map,并添加两个参数
            Map<String, String> resultMap = WXPayUtil.xmlToMap(result);
    
            //5.将map转成json并返回给浏览器
            //已经成功支付,停止询问
            if(resultMap.get("trade_state").equalsIgnoreCase("success")){
                return resultMap;
            }
            //超过30秒未支付,停止询问
            if(System.currentTimeMillis() - beginTime > 30000){
                return resultMap;
            }
            Thread.sleep(3000); //每隔3秒,询问一次微信后台
        }
    }

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柚几哥哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值