微信支付前后端

1.建表语句,一个支付日志,一个订单表

# Host: localhost  (Version 5.7.19)
# Date: 2019-11-18 15:49:50
# Generator: MySQL-Front 6.1  (Build 1.26)


#
# Structure for table "t_order"
#

CREATE TABLE `t_order` (
  `id` char(19) NOT NULL DEFAULT '',
  `order_no` varchar(20) NOT NULL DEFAULT '' COMMENT '订单号',
  `course_id` varchar(19) NOT NULL DEFAULT '' COMMENT '课程id',
  `course_title` varchar(100) DEFAULT NULL COMMENT '课程名称',
  `course_cover` varchar(255) DEFAULT NULL COMMENT '课程封面',
  `teacher_name` varchar(20) DEFAULT NULL COMMENT '讲师名称',
  `member_id` varchar(19) NOT NULL DEFAULT '' COMMENT '会员id',
  `nickname` varchar(50) DEFAULT NULL COMMENT '会员昵称',
  `mobile` varchar(11) DEFAULT NULL COMMENT '会员手机',
  `total_fee` decimal(10,2) DEFAULT '0.01' COMMENT '订单金额(分)',
  `pay_type` tinyint(3) DEFAULT NULL COMMENT '支付类型(1:微信 2:支付宝)',
  `status` tinyint(3) DEFAULT NULL COMMENT '订单状态(0:未支付 1:已支付)',
  `is_deleted` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '逻辑删除 1(true)已删除, 0(false)未删除',
  `gmt_create` datetime NOT NULL COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_order_no` (`order_no`),
  KEY `idx_course_id` (`course_id`),
  KEY `idx_member_id` (`member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单';

#
# Data for table "t_order"
#

INSERT INTO `t_order` VALUES ('1195693605513891841','1195693605555834880','18','Java精品课程','http://guli-file.oss-cn-beijing.aliyuncs.com/cover/2019/03/06/866e9aca-b530-4f71-a690-72d4a4bfd1e7.jpg','晴天','1','小三1231','13700000001',1,NULL,0,0,'2019-11-16 21:22:25','2019-11-16 21:22:25'),('1195694200178118657','1195694200186507264','18','Java精品课程','http://guli-file.oss-cn-beijing.aliyuncs.com/cover/2019/03/06/866e9aca-b530-4f71-a690-72d4a4bfd1e7.jpg','晴天','1','小三1231','13700000001',1,NULL,0,0,'2019-11-16 21:24:47','2019-11-16 21:24:47'),('1196264007411744769','1196264005255872512','1192252213659774977','java基础课程:test','https://guli-file-190513.oss-cn-beijing.aliyuncs.com/cover/default.gif','晴天','1','小三1231','13700000001',1,NULL,1,0,'2019-11-18 11:09:00','2019-11-18 11:10:14'),('1196265495278174209','1196265495273979904','18','Java精品课程','http://guli-file.oss-cn-beijing.aliyuncs.com/cover/2019/03/06/866e9aca-b530-4f71-a690-72d4a4bfd1e7.jpg','晴天','1','小三1231','13700000001',1,NULL,0,0,'2019-11-18 11:14:54','2019-11-18 11:14:54');

#
# Structure for table "t_pay_log"
#

CREATE TABLE `t_pay_log` (
  `id` char(19) NOT NULL DEFAULT '',
  `order_no` varchar(20) NOT NULL DEFAULT '' COMMENT '订单号',
  `pay_time` datetime DEFAULT NULL COMMENT '支付完成时间',
  `total_fee` decimal(10,2) DEFAULT '0.01' COMMENT '支付金额(分)',
  `transaction_id` varchar(30) DEFAULT NULL COMMENT '交易流水号',
  `trade_state` char(20) DEFAULT NULL COMMENT '交易状态',
  `pay_type` tinyint(3) NOT NULL DEFAULT '0' COMMENT '支付类型(1:微信 2:支付宝)',
  `attr` text COMMENT '其他属性',
  `is_deleted` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '逻辑删除 1(true)已删除, 0(false)未删除',
  `gmt_create` datetime NOT NULL COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_order_no` (`order_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='支付日志表';

#
# Data for table "t_pay_log"
#

INSERT INTO `t_pay_log` VALUES ('1194498446013001730','1194498300579704832','2019-11-13 14:13:17',1,'4200000469201911130676624386','SUCCESS',1,'{\"transaction_id\":\"4200000469201911130676624386\",\"nonce_str\":\"2Lc23ILl231It53M\",\"trade_state\":\"SUCCESS\",\"bank_type\":\"CFT\",\"openid\":\"oNpSGwR-QGG5DaZtDkh2UZlsFDQE\",\"sign\":\"5404850AA3ED0E844DE104651477F07A\",\"return_msg\":\"OK\",\"fee_type\":\"CNY\",\"mch_id\":\"1473426802\",\"cash_fee\":\"1\",\"out_trade_no\":\"1194498300579704832\",\"cash_fee_type\":\"CNY\",\"appid\":\"wx8397f8696b538317\",\"total_fee\":\"1\",\"trade_state_desc\":\"支付成功\",\"trade_type\":\"NATIVE\",\"result_code\":\"SUCCESS\",\"attach\":\"\",\"time_end\":\"20191113141314\",\"is_subscribe\":\"N\",\"return_code\":\"SUCCESS\"}',0,'2019-11-13 14:13:17','2019-11-13 14:13:17'),('1195253787449430017','1195253049260314624','2019-11-15 16:14:44',1,'4200000454201911150981874895','SUCCESS',1,'{\"transaction_id\":\"4200000454201911150981874895\",\"nonce_str\":\"MAM5UM4Xhv1lItvO\",\"trade_state\":\"SUCCESS\",\"bank_type\":\"CFT\",\"openid\":\"oNpSGwR-QGG5DaZtDkh2UZlsFDQE\",\"sign\":\"7DBDCAF4A078B30BB3EF073E6A238C20\",\"return_msg\":\"OK\",\"fee_type\":\"CNY\",\"mch_id\":\"1473426802\",\"cash_fee\":\"1\",\"out_trade_no\":\"1195253049260314624\",\"cash_fee_type\":\"CNY\",\"appid\":\"wx8397f8696b538317\",\"total_fee\":\"1\",\"trade_state_desc\":\"支付成功\",\"trade_type\":\"NATIVE\",\"result_code\":\"SUCCESS\",\"attach\":\"\",\"time_end\":\"20191115161440\",\"is_subscribe\":\"N\",\"return_code\":\"SUCCESS\"}',0,'2019-11-15 16:14:44','2019-11-15 16:14:44'),('1196264321397342210','1196264005255872512','2019-11-18 11:10:14',1,'4200000453201911184025781554','SUCCESS',1,'{\"transaction_id\":\"4200000453201911184025781554\",\"nonce_str\":\"D1dHexCLIFIxAAg2\",\"trade_state\":\"SUCCESS\",\"bank_type\":\"CFT\",\"openid\":\"oNpSGwR-QGG5DaZtDkh2UZlsFDQE\",\"sign\":\"C9F5CA1EE49EA7891736D73BEB423962\",\"return_msg\":\"OK\",\"fee_type\":\"CNY\",\"mch_id\":\"1473426802\",\"cash_fee\":\"1\",\"out_trade_no\":\"1196264005255872512\",\"cash_fee_type\":\"CNY\",\"appid\":\"wx8397f8696b538317\",\"total_fee\":\"1\",\"trade_state_desc\":\"支付成功\",\"trade_type\":\"NATIVE\",\"result_code\":\"SUCCESS\",\"attach\":\"\",\"time_end\":\"20191118111011\",\"is_subscribe\":\"N\",\"return_code\":\"SUCCESS\"}',0,'2019-11-18 11:10:14','2019-11-18 11:10:14');

2.需要接口:

1》生成订单,返回订单的订单编号


import java.util.UUID;

/**
 * <p>
 * 订单 服务实现类
 * </p>
 *
 * @author zyk
 * @since 2023-05-28
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
    @Autowired
    EduClinent eduClinent;
    @Autowired
    UserClient userClient;

    //    生成订单
    @Override
    public R saveOrder(String courseId, String userId) {
//        通过远程调用获取用户信息
        UcenterMemberOrder userInfoOrder = userClient.getUserInfoOrder(userId);
//        通过远程调用获取课程信息
        CourseWebVoOrder courseInfoOrder = eduClinent.queryCourse(courseId);
        Order order=new Order();
        String orderNo = UUID.randomUUID().toString().substring(0,20);
        order.setOrderNo(orderNo);//订单号
        order.setCourseId(courseId); //课程id
        order.setCourseTitle(courseInfoOrder.getTitle());//价格
        order.setCourseCover(courseInfoOrder.getCover());//课程封面
        order.setTeacherName(courseInfoOrder.getTeacherName());//讲师名字
        order.setTotalFee(courseInfoOrder.getPrice());//价格
        order.setMemberId(userId);//用户id
        order.setMobile(userInfoOrder.getMobile());//用户手机号
        order.setNickname(userInfoOrder.getNickname());//用户名
        order.setStatus(0);  //订单状态(0:未支付 1:已支付)
        order.setPayType(1);  //支付类型 ,微信1
        baseMapper.insert(order);
        return R.ok().data("orderNo",orderNo);
    }
}

2》根据订单编号,生成微信支付二维码(返回二维码的链接,返回给前端,由前端处理,显示二维码)

 /**
     * 根据订单编号,生成支付二维码
     * @param orderNo
     * @return
     */
    @Override
    public Map  creatQrCode(String orderNo) {
        try {
//         1.根据订单编号查询订单信息
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("order_no", orderNo);
            Order order = orderService.getOne(queryWrapper);

//         2.使用map设置生成二维码需要的参数
            Map map = new HashMap();
            map.put("appid","wx74862e0dfcf69954"); //支付id
            map.put("mch_id", "1558950191"); //商户号
            map.put("nonce_str", WXPayUtil.generateNonceStr()); //生成随机的字符串,让每次生成的二维码不一样
            map.put("body", order.getCourseTitle()); //生成二维码的名字,会显示在微信扫码后的界面
            map.put("out_trade_no", orderNo); //二维码唯一的标识,只要不重复就行,这里是订单编号
            map.put("total_fee", order.getTotalFee().multiply(new BigDecimal("100")).longValue()+""); //支付金额
            map.put("spbill_create_ip", "127.0.0.1"); //进行支付的ip地址,实际项目使用项目的域名
            map.put("notify_url", "http://guli.shop/api/order/weixinPay/weixinNotify"); //支付后回调地址
            map.put("trade_type", "NATIVE"); //支付类型,NATIVE:知道价格,生成二维码

//         3.发送httpclient请求,(需要xml格式参数) 地址是微信支付的固定地址
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
            client.setXmlParam(WXPayUtil.generateSignedXml(map, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));
            client.setHttps(true);
            //执行post请求发送
            client.post();

//         4.得到返回结果,结果是xml格式的
            String xml = client.getContent();
            // 将结果转为map
            Map<String, String> map2 = WXPayUtil.xmlToMap(xml);
            System.out.println("生成二维码,返回的结果"+map2);
            // 最终返回数据的封装
            Map resultMap = new HashMap();
            resultMap.put("out_trade_no", orderNo);//订单编号
            resultMap.put("course_id", order.getCourseId()); //课程编号
            resultMap.put("total_fee", order.getTotalFee() + ""); // 价格
            resultMap.put("result_code", map2.get("result_code"));  //返回二维码状态码
            resultMap.put("code_url", map2.get("code_url"));        //二维码地址
            return  resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            throw new GuLiExeception(20001, "生成二维码时发生错误");
        }
    }

3》查询订单支付状态

    /**
     * 通过订单编号查询支付状态
     * @param orderNo
     * @return
     */
    @Override
    public Map<String, String> querypayStatus(String orderNo) {
        try {
            // 1.使用map设置生成二维码需要的参数
            Map m = new HashMap<>();
            m.put("appid", "wx74862e0dfcf69954");
            m.put("mch_id", "1558950191");
            m.put("nonce_str", WXPayUtil.generateNonceStr());
            m.put("out_trade_no", orderNo);//订单编号
            // 2.发送httpClient请求
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
            client.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));
            client.setHttps(true);
            client.post();
            // 3.得到返回内容
            String xml = client.getContent();
            Map<String, String> map = WXPayUtil.xmlToMap(xml);
            System.out.println("查询订单支付状态接口返回:"+map);
            return map;
        } catch (Exception e) {
            e.printStackTrace();
            throw new GuLiExeception(20001, "在查询订单状态时发生异常");
        }
    }

/**
     * 在支付成功后,更新订单表订单状态、向支付记录表添加支付记录
     * @param map
     */
    @Override
    public void updateOrdersStatus(Map<String, String> map) {
        //从map获取订单号
        String orderNo =map.get("out_trade_no");
        //根据订单号查询订单信息
        QueryWrapper<Order> wrapper =new QueryWrapper<>();
        wrapper.eq("order_no",orderNo);
        Order order=orderService.getOne(wrapper);
        // 如果该订单已支付,则直接返回
        if(order.getStatus()==1)
        {
            return;
        }
        // 更新订单表订单状态
        order.setStatus(1);
        orderService.updateById(order);
        //向支付记录表中添加支付记录
        PayLog payLog =new PayLog();
        payLog.setOrderNo(orderNo);
        payLog.setPayTime(new Date());
        payLog.setPayType(1);//支付类型 1微信
        payLog.setTotalFee(order.getTotalFee());//总价格
        payLog.setAttr(JSONObject.toJSONString(map));//将其他属性存储到数据库

        baseMapper.insert(payLog);
    }

controller 

    // 查询订单状态(是否支付成功)
    @GetMapping("queryPayStatus/{orderNo}")
    public R queryStatus(@PathVariable String orderNo) throws Exception {
        Map<String, String> map = baseService.querypayStatus(orderNo);
        //如果map返回值为空,那绝对是订单支付出错了
        if (map == null) {
            return R.error().message("订单支付出错了!");
        }
        //如果支付成功
        if (map.get("trade_state").equals("SUCCESS")) {
            //添加支付记录到支付日志表,更新订单表订单状态
            baseService.updateOrdersStatus(map);
            return R.ok().message("支付成功");
        }
        //如果未支付成功
        return R.ok().code(25000).message("支付中");
    }

4.前端    

点击支付按钮后,访问生成二维码的接口,跳转到支付页面,并每三秒查询一次支付状态接口,如果支付成功,就跳转到课程详情界面,如果正在支付则不处理。

<template>
  <div class="Page Confirm">
    <div class="Title">
      <h1 class="fl f18">订单确认</h1>
      <img src="~/assets/img/cart_setp2.png" class="fr">
      <div class="clear"></div>
    </div>
    <form name="flowForm" id="flowForm" method="post" action="">
      <table class="GoodList">
        <tbody>
        <tr>
          <th class="name">商品</th>
          <th class="price">原价</th>
          <th class="priceNew">价格</th>
        </tr>
        </tbody>
        <tbody>
        <!-- <tr>
          <td colspan="3" class="Title red f18 fb"><p>限时折扣</p></td>
        </tr> -->
        <tr>
          <td colspan="3" class="teacher">讲师:{
   
   {order.teacherName}}</td>
        </tr>
        <tr class="good">
          <td class="name First">
            <a target="_blank" :href="'https://localhost:3000/course/'+order.courseId">
              <img :src="order.courseCover"></a>
            <div class="goodInfo">
              <input type="hidden" class="ids ids_14502" value="14502">
              <a target="_blank" :href="'https://localhost:3000/course/'+ order.courseId">{
   
   {order.courseTitle}}</a>
            </div>
          </td>
          <td class="price">
            <p>¥<strong>{
   
   {order.totalFee}}</strong></p>
            <!-- <span class="discName red">限时8折</span> -->
          </td>
          <td class="red priceNew Last">¥<strong>{
   
   {order.totalFee}}</strong></td>
        </tr>
        <tr>
          <td class="Billing tr" colspan="3">
            <div class="tr">
              <p>共 <strong class="red">1</strong> 件商品,合计<span
                class="red f20">¥<strong>{
   
   {order.totalFee}}</strong></span></p>
            </div>
          </td>
        </tr>
        </tbody>
      </table>
      <div class="Finish">
        <div class="fr" id="AgreeDiv">
          
          <label for="Agree"><p class="on"><input type="checkbox" checked="checked">我已阅读并同意<a href="javascript:" target="_blank">《谷粒学院购买协议》</a></p></label>
        </div>
        <div class="clear"></div>
        <div class="Main fl">
          <div class="fl">
            <a :href="'/course/'+order.courseId">返回课程详情页</a>
          </div>
          <div class="fr">
            <p>共 <strong class="red">1</strong> 件商品,合计<span class="red f20">¥<strong
              id="AllPrice">{
   
   {order.totalFee}}</strong></span></p>
          </div>
        </div>
        <input name="score" value="0" type="hidden" id="usedScore">
        <button class="fr redb" type="button" id="submitPay" @click="toPay()">去支付</button>
        <div class="clear"></div>
      </div>
    </form>
  </div>
</template>
      
<script>
import orders from '@/api/orders'
export default {
  data() {
      return {
        order:''
      }
    },
    //根据订单id获取订单信息
    //异步调用的方式
    asyncData({params, error}) {
        return orders.getOrderInfo(params.oid).then(response => {
            return {
                order: response.data.data.data
            }
        })
    },
    methods: {
        //点击去支付,跳转到支付页面
        toPay() {
        this.$router.push({path: '/pay/' + this.order.orderNo})
        }
    }
}
</script>
<template>
  <div class="cart py-container">
    <!--主内容-->
    <div class="checkout py-container  pay">
      <div class="checkout-tit">
        <h4 class="fl tit-txt"><span class="success-icon"></span><span class="success-info">订单提交成功,请您及时付款!订单号:{
   
   {payObj.out_trade_no}}</span>
        </h4>
        <span class="fr"><em class="sui-lead">应付金额:</em><em class="orange money">¥{
   
   {payObj.total_fee}}</em></span>
        <div class="clearfix"></div>
      </div>
      <div class="checkout-steps">
        <div class="fl weixin">微信支付</div>
        <div class="fl sao">
          <p class="red">请使用微信扫一扫。</p>
          <div class="fl code">
            <!-- <img id="qrious" src="~/assets/img/erweima.png" alt=""> -->
            <!-- <qriously value="weixin://wxpay/bizpayurl?pr=R7tnDpZ" :size="338"/> -->
            <qriously :value="payObj.code_url" :size="338"/>
            <div class="saosao">
              <p>请使用微信扫一扫</p>
              <p>扫描二维码支付</p>
            </div>

          </div>

        </div>
        <div class="clearfix"></div>
        <!-- <p><a href="pay.html" target="_blank">> 其他支付方式</a></p> -->
        
      </div>
    </div>
  </div>
</template>
<script>
import orders from '@/api/orders'

  export default {
    //根据订单id生成微信支付二维码
    asyncData({params, error}) {
      return orders.createNative(params.pid).then(response => {
        return {//异步请求需要return
           payObj: response.data.data
        }

      })
    },
    data() {
      return {
        timer: null,  // 定时器名称
        
      }
    },
    mounted() {
      //在页面渲染之后执行
      //每隔三秒,去查询一次支付状态
      this.timer1 = setInterval(() => {
        this.queryPayStatus(this.payObj.out_trade_no)
      }, 3000);
    },
    methods: {
      //查询支付状态的方法
      queryPayStatus(out_trade_no) {
        orders.queryPayStatus(out_trade_no).then(response => {
          if (response.data.success) {
              //如果支付成功,清除定时器
              clearInterval(this.timer1)
                this.$message({
                type: 'success',
                message: '支付成功!'
                })
             //跳转到课程详情页面观看视频
             this.$router.push({path: '/course/' + this.payObj.course_id})
          }
        })
      }
    }
  }
</script>

猜你喜欢

转载自blog.csdn.net/sharesb/article/details/130915121