谷粒学院——Day15【微信支付】

news2024/11/14 5:48:15

❤ 作者主页:Java技术一点通的博客
❀ 个人介绍:大家好,我是Java技术一点通!( ̄▽ ̄)~*
🍊 记得关注、点赞、收藏、评论⭐️⭐️⭐️
📣 认真学习,共同进步!!!🎉🎉

课程评论功能

一、数据库设计

  • 数据库
    edu_comment

  • 数据表

    CREATE TABLE `edu_comment` (
      `id` char(19) NOT NULL COMMENT '讲师ID',
      `course_id` varchar(19) NOT NULL DEFAULT '' COMMENT '课程id',
      `teacher_id` char(19) NOT NULL DEFAULT '' COMMENT '讲师id',
      `member_id` varchar(19) NOT NULL DEFAULT '' COMMENT '会员id',
      `nickname` varchar(50) DEFAULT NULL COMMENT '会员昵称',
      `avatar` varchar(255) DEFAULT NULL COMMENT '会员头像',
      `content` varchar(500) DEFAULT NULL 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`),
      KEY `idx_course_id` (`course_id`),
      KEY `idx_teacher_id` (`teacher_id`),
      KEY `idx_member_id` (`member_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='评论';
    
    #
    # Data for table "edu_comment"
    #
    
    INSERT INTO `edu_comment` VALUES ('1194499162790211585','1192252213659774977','1189389726308478977','1','小三123','http://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoj0hHXhgJNOTSOFsS4uZs8x1ConecaVOB8eIl115xmJZcT4oCicvia7wMEufibKtTLqiaJeanU2Lpg3w/132','课程很好',0,'2019-11-13 14:16:08','2019-11-13 14:16:08'),('1194898406466420738','1192252213659774977','1189389726308478977','1','小三123','http://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoj0hHXhgJNOTSOFsS4uZs8x1ConecaVOB8eIl115xmJZcT4oCicvia7wMEufibKtTLqiaJeanU2Lpg3w/132','11',0,'2019-11-14 16:42:35','2019-11-14 16:42:35'),('1194898484388200450','1192252213659774977','1189389726308478977','1','小三123','http://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoj0hHXhgJNOTSOFsS4uZs8x1ConecaVOB8eIl115xmJZcT4oCicvia7wMEufibKtTLqiaJeanU2Lpg3w/132','111',0,'2019-11-14 16:42:53','2019-11-14 16:42:53'),('1195251020861317122','1192252213659774977','1189389726308478977','1',NULL,NULL,'2233',0,'2019-11-15 16:03:45','2019-11-15 16:03:45'),('1195251382720700418','1192252213659774977','1189389726308478977','1',NULL,NULL,'4455',0,'2019-11-15 16:05:11','2019-11-15 16:05:11'),('1195252819177570306','1192252213659774977','1189389726308478977','1','小三1231','http://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoj0hHXhgJNOTSOFsS4uZs8x1ConecaVOB8eIl115xmJZcT4oCicvia7wMEufibKtTLqiaJeanU2Lpg3w/132','55',0,'2019-11-15 16:10:53','2019-11-15 16:10:53'),('1195252899448160258','1192252213659774977','1189389726308478977','1','小三1231','http://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoj0hHXhgJNOTSOFsS4uZs8x1ConecaVOB8eIl115xmJZcT4oCicvia7wMEufibKtTLqiaJeanU2Lpg3w/132','55',0,'2019-11-15 16:11:13','2019-11-15 16:11:13'),('1195252920587452417','1192252213659774977','1189389726308478977','1','小三1231','http://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoj0hHXhgJNOTSOFsS4uZs8x1ConecaVOB8eIl115xmJZcT4oCicvia7wMEufibKtTLqiaJeanU2Lpg3w/132','223344',0,'2019-11-15 16:11:18','2019-11-15 16:11:18'),('1195262128095559681','14','1189389726308478977','1','小三1231','http://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoj0hHXhgJNOTSOFsS4uZs8x1ConecaVOB8eIl115xmJZcT4oCicvia7wMEufibKtTLqiaJeanU2Lpg3w/132','11',0,'2019-11-15 16:47:53','2019-11-15 16:47:53'),('1196264505170767874','1192252213659774977','1189389726308478977','1','小三1231','http://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoj0hHXhgJNOTSOFsS4uZs8x1ConecaVOB8eIl115xmJZcT4oCicvia7wMEufibKtTLqiaJeanU2Lpg3w/132','666666',0,'2019-11-18 11:10:58','2019-11-18 11:10:58');
    

 


二、课程评论后端整合

1. 在service-edu模块,生成课程评论代码

使用mp代码生成器生成:

public class CodeGenerator {

    @Test
    public void run() {

        // 1、创建代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 2、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir("D:\\IDEA\\guli_parent\\service\\service_edu" + "/src/main/java"); //输出目录

        gc.setAuthor("jyu_zwy"); //作者名
        gc.setOpen(false); //生成后是否打开资源管理器
        gc.setFileOverride(false); //重新生成时文件是否覆盖

        gc.setServiceName("%sService");	//去掉Service接口的首字母I
        gc.setIdType(IdType.ID_WORKER_STR); //主键策略
        gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
        gc.setSwagger2(true);//开启Swagger2模式

        mpg.setGlobalConfig(gc);

        // 3、数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/guli?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("abc123");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 4、包配置
        PackageConfig pc = new PackageConfig();

        //生成包:com.atguigu.eduservice
        pc.setModuleName("eduservice"); //模块名
        pc.setParent("com.atguigu");

        //生成包:com.atguigu.controller
        pc.setController("controller");
        pc.setEntity("entity");
        pc.setService("service");
        pc.setMapper("mapper");
        mpg.setPackageInfo(pc);

        // 5、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("edu_comment");//根据数据库哪张表生成,有多张表就加逗号继续填写

        strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
        strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀

        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
        strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作

        strategy.setRestControllerStyle(true); //restful api风格控制器
        strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符

        mpg.setStrategy(strategy);


        // 6、执行
        mpg.execute();

    }
}

2. 在service-ucenter模块,创建接口

UcenterMemberController:

   //根据用户id查询用户信息
    @PostMapping("getMemberInfoById{memberId}")
    public UcenterMemberVo getMemberInfoById(@PathVariable String memberId){
        UcenterMember member = memberService.getById(memberId);
        UcenterMemberVo memberVo = new UcenterMemberVo();
        BeanUtils.copyProperties(member, memberVo);

        return memberVo;
    }

3. 创建课程评论controller

  1. 在service-edu模块创建client,实现微服务调用
    VodClient:

     @PostMapping("/educenter/member/getMemberInfoById/{memberId}")
        public UcenterMemberVo getMemberInfoById(@PathVariable String memberId);
    

    VodFileDegradeFeignClient:

     @Override
        public UcenterMemberVo getMemberInfoById(String memberId) {
            return null;
        }
    
  2. 创建评论列表和添加评论接口
    CommentFrontController

@RestController
@CrossOrigin
@RequestMapping({"/eduservice/comment"})
public class CommentFrontController {

    @Autowired
    private EduCommentService commentService;

    @Autowired
    private VodClient vodClient;

    //根据课程id分页查询课程评论的方法
    @GetMapping("/getCommentPage/{page}/{limit}")
    public R getCommentPage(@PathVariable Long page, @PathVariable Long limit, String courseId) {
        Page<EduComment> commentPage = new Page<>(page, limit);

        QueryWrapper<EduComment> wrapper = new QueryWrapper<>();

        //判断课程id是否为空
        if (!StringUtils.isEmpty(courseId)){
            wrapper.eq("course_id",courseId);
        }
        //按最新排序
        wrapper.orderByDesc("gmt_create");

        //数据会被封装到commentPage中
        commentService.page(commentPage,wrapper);

        List<EduComment> commentList = commentPage.getRecords();
        long current = commentPage.getCurrent();//当前页
        long size = commentPage.getSize();//一页记录数
        long total = commentPage.getTotal();//总记录数
        long pages = commentPage.getPages();//总页数
        boolean hasPrevious = commentPage.hasPrevious();//是否有上页
        boolean hasNext = commentPage.hasNext();//是否有下页

        HashMap<String, Object> map = new HashMap<>();
        map.put("current",current);
        map.put("size",size);
        map.put("total",total);
        map.put("pages",pages);
        map.put("hasPrevious",hasPrevious);
        map.put("hasNext",hasNext);
        map.put("list",commentList);

        return R.ok().data(map);
    }

    //添加评论
    @PostMapping("/auth/addComment")
    public R addComment(HttpServletRequest request, @RequestBody EduComment eduComment){
        String memberId = JwtUtils.getMemberIdByJwtToken(request);
        //判断用户是否登录
        if (StringUtils.isEmpty(memberId)){
            throw new GuliException(20001,"请先登录");
        }
        eduComment.setMemberId(memberId);

        //远程调用ucenter根据用户id获取用户信息
        UcenterMemberVo memberVo = vodClient.getMemberInfoById(memberId);

        eduComment.setAvatar(memberVo.getAvatar());
        eduComment.setNickname(memberVo.getNickname());

        //保存评论
        commentService.save(eduComment);

        return R.ok();
    }

}

三、课程评论前端整合

1. 定义api

commonedu.js

import request from '@/utils/request'

export default {
    getPageList(page, limit, courseId) {
        return request({
            url: `/eduservice/comment/getCommentPage/${page}/${limit}`,
            method: 'get',
            params: courseId
        })
    },
    
    addComment(comment) {
        return request({
            url: `/eduservice/comment/auth/addComment`,
            method: 'post',
            data: comment
        })
    }
}

2. 调用自定义方法

<script>
import courseApi from "@/api/course"
import comment from "@/api/commonedu"

export default {
  //   asyncData({ params, error }) {
  //   return courseApi.getCourseInfo(params.id).then(response => {
  //     return { 
  //       courseWebVo: response.data.data.courseWebVo,
  //       chapterVideoList: response.data.data.chapterVideoList
  //     }
  //   })
  // },

  data() {
    return{
      chapterVideoList: [],
      courseWebVo: {
        courseId: ""
      },
      commentList: {},
      page: 1,
      limit: 4,
      total: 10,
      comment: {
        content: "",
        courseId: "",
        teacherId: "",
      },
      isbuyCourse: false,
    }
  },

  created() {
    this.courseWebVo.courseId = this.$route.params.id;
    //获取课程详细信息
    this.getCourseInfo();
    this.initComment();
  },


  methods: {
    //获取课程详细信息
    getCourseInfo() {
      courseApi.getCourseInfo(this.courseWebVo.courseId).then(response=> {
        this.chapterVideoList = response.data.data.chapterVideoList
        this.courseWebVo = response.data.data.courseWebVo
      })
    },

    initComment(){
      comment.getPageList(this.page, this.limit,this.courseWebVo.courseId)
        .then(response=> {
          this.commentList = response.data.data
        })
    },

    addComment() {
      this.comment.courseId = this.courseWebVo.courseId
      this.comment.teacherId = this.courseWebVo.teacherId
      comment.addComment(this.comment).then(response => {
        if (response.data.success) {
          this.$message({
            message: "评论成功",
            type: "success",
          });
          this.comment.content = "";
          this.initComment();
        }
      });
    },

    gotoPage(page) {
      comment.getPageList(page, this.limit, this.courseId).then((response) => {
        this.commentList = response.data.data
      })
    },

  }
};
</script>

3. 页面

 <div class="mt50 commentHtml">
            <div>
                <h6 class="c-c-content c-infor-title" id="i-art-comment">
                    <span class="commentTitle">课程评论</span>
                </h6>
                <section class="lh-bj-list pr mt20 replyhtml">
                    <ul>
                        <li class="unBr">
                            <aside class="noter-pic">
                                <img
                                    width="50"
                                    height="50"
                                    class="picImg"
                                    src="~/assets/img/avatar-boy.gif"
                                    />
                            </aside>
                            <div class="of">
                                <section class="n-reply-wrap">
                                    <fieldset>
                                        <textarea
                                                  name=""
                                                  v-model="comment.content"
                                                  placeholder="输入您要评论的文字"
                                                  id="commentContent"
                                                  ></textarea>
                                    </fieldset>
                                    <p class="of mt5 tar pl10 pr10">
                                        <span class="fl"
                                              ><tt
                                                  class="c-red commentContentmeg"
                                                  style="display: none"
                                                  ></tt
                                            ></span>
                                        <input
                                              type="button"
                                              @click="addComment()"
                                              value="回复"
                                              class="lh-reply-btn"
                                              />
                                    </p>
                                </section>
                            </div>
                        </li>
                    </ul>
                </section>
                <section class="">
                    <section class="question-list lh-bj-list pr">
                        <ul class="pr10">
                            <li v-for="comment in commentList.list" :key="comment.id">
                                <aside class="noter-pic">
                                    <img
                                        width="50"
                                        height="50"
                                        class="picImg"
                                        :src="comment.avatar"
                                        />
                                </aside>
                                <div class="of">
                                    <span class="fl">
                                        <font class="fsize12 c-blue">{{ comment.nickname }}</font>
                                        <font class="fsize12 c-999 ml5">评论:</font></span
                                        >
                                </div>
                                <div class="noter-txt mt5">
                                    <p>{{ comment.content }}</p>
                                </div>
                                <div class="of mt5">
                                    <span class="fr"
                                          ><font class="fsize12 c-999ml5">{{
                                        comment.gmtCreate
                                        }}</font></span
                                        >
                                </div>
                            </li>
                        </ul>
                    </section>
                </section>
                <!-- 公共分页 开始 -->
                <div class="paging">
                    <!-- undisable这个class是否存在,取决于数据属性hasPrevious -->
                    <a
                      :class="{ undisable: !commentList.hasPrevious }"
                      href="#"
                      title="首页"
                      @click.prevent="gotoPage(1)"
                      >首</a
                        >
                    <a
                      :class="{ undisable: !commentList.hasPrevious }"
                      href="#"
                      title="前一页"
                      @click.prevent="gotoPage(commentList.current - 1)"
                      >&lt;</a
                        >
                    <a
                      v-for="page in commentList.pages"
                      :key="page"
                      :class="{
                              current: commentList.current == page,
                              undisable: commentList.current == page,
                              }"
                      :title="'第' + page + '页'"
                      href="#"
                      @click.prevent="gotoPage(page)"
                      >{{ page }}</a
                        >
                    <a
                      :class="{ undisable: !commentList.hasNext }"
                      href="#"
                      title="后一页"
                      @click.prevent="gotoPage(commentList.current + 1)"
                      >&gt;</a
                        >
                    <a
                      :class="{ undisable: !commentList.hasNext }"
                      href="#"
                      title="末页"
                      @click.prevent="gotoPage(commentList.pages)"
                      >末</a
                        >
                    <div class="clear" />
                </div>
                <!-- 公共分页 结束 -->
            </div>
        </div>

4. 测试

在这里插入图片描述
 


课程支付功能需求描述

一. 课程支付说明

(1)课程分为免费课程和付费课程,如果是免费课程可以直接观看,如果是付费观看的课程,用户需下单支付后才可以观看。
在这里插入图片描述
 
(2) 如果是免费课程,在用户选择课程,进入到课程详情页面时候,直接显示 “立即观看”,用户点击立即观看,可以切换到播放列表进行视频播放。
在这里插入图片描述
 

二、付费课程流程

(1)如果是付费课程,在用户选择课程,进入到课程详情页面时候,会显示 “立即购买”。
在这里插入图片描述
 
(2) 点击“立即购买”,会生成课程的订单,跳转到订单页面。
在这里插入图片描述
 

(3) 点击“去支付”,会跳转到支付页面,生成微信扫描的二维码。

 
(4) 使用微信扫描支付后,会跳转回到课程详情页面,同时显示“立即观看”。
在这里插入图片描述
 


创建支付模块和开发订单接口

一、创建支付模块和准备

  1. 在service模块下创建子模块service_order
    在这里插入图片描述
     

  2. 创建支付相关的表
    在这里插入图片描述
     
    数据库表: t_ordert_pay_log

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');
  1. 使用代码生成器生成相关代码
public class CodeGenerator {

    @Test
    public void run() {

        // 1、创建代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 2、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir("D:\\IDEA\\guli_parent\\service\\service_order" + "/src/main/java"); //输出目录

        gc.setAuthor("jyu_zwy"); //作者名
        gc.setOpen(false); //生成后是否打开资源管理器
        gc.setFileOverride(false); //重新生成时文件是否覆盖

        gc.setServiceName("%sService");	//去掉Service接口的首字母I
        gc.setIdType(IdType.ID_WORKER_STR); //主键策略
        gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
        gc.setSwagger2(true);//开启Swagger2模式

        mpg.setGlobalConfig(gc);

        // 3、数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/guli?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("abc123");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 4、包配置
        PackageConfig pc = new PackageConfig();

        //生成包:com.atguigu.eduservice
        pc.setModuleName("eduorder"); //模块名
        pc.setParent("com.atguigu");

        //生成包:com.atguigu.controller
        pc.setController("controller");
        pc.setEntity("entity");
        pc.setService("service");
        pc.setMapper("mapper");
        mpg.setPackageInfo(pc);

        // 5、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("t_order", "t_pay_log");//根据数据库哪张表生成,有多张表就加逗号继续填写

        strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
        strategy.setTablePrefix("t" + "_"); //生成实体时去掉表前缀

        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
        strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作

        strategy.setRestControllerStyle(true); //restful api风格控制器
        strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符

        mpg.setStrategy(strategy);


        // 6、执行
        mpg.execute();

    }
}

在这里插入图片描述
 
4. 在service_order模块中引入依赖

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

  1. 编写application.properties配置文件
# 服务端口
server.port=8007

# 服务名
spring.application.name=service-order

# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456

# 返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8

# 配置mapper xml文件路径
mybatis-plus.mapper-locations=classpath:com/atguigu/eduorder/mapper.xml/*.xml

# mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

# nacos注册中心
spring.cloud.nacos.discovery.server-addr= localhost:8848

# 开启熔断机制
feign.hystrix.enabled=true

# 设置hystrix超时时间,默认1000ms
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000
  1. 启动类
@SpringBootApplication
@EnableDiscoveryClient
@ComponentScan(basePackages = {"com.atguigu"})
@MapperScan("com.atguigu.eduorder.mapper")
public class OrdersApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrdersApplication.class, args);
    }
}

二、开发创建订单接口

1. 编写订单controller

@RestController
@RequestMapping("/eduorder/order")
@CrossOrigin
public class OrderController {

    @Autowired
    private OrderService orderService;

    // 生成订单的方法
     @PostMapping("createOrder/{courseId}")
    public R saveOrder(@PathVariable String courseId, HttpServletRequest request) {
         //创建订单,返回订单号
         String orderNo = orderService.createOrders(courseId, JwtUtils.getMemberIdByJwtToken(request));
         return R.ok().data("orderId", orderNo);
     }
}

2. 远程调用、订单公共返回类Vo

在common模块中建立用于远程接口调用后返回给订单接口的统一返回类:

  • CourseWebVoOrder
    @Data
    public class CourseWebVoOrder {
        private static final long serialVersionUID = 1L;
        private String id;
    
        @ApiModelProperty(value = "课程标题")
        private String title;
    
        @ApiModelProperty(value = "课程销售价格,设置为0则可免费观看")
        private BigDecimal price;
    
        @ApiModelProperty(value = "总课时")
        private Integer lessonNum;
    
        @ApiModelProperty(value = "课程封面图片路径")
        private String cover;
    
        @ApiModelProperty(value = "销售数量")
        private Long buyCount;
    
        @ApiModelProperty(value = "浏览数量")
        private Long viewCount;
    
        @ApiModelProperty(value = "课程简介")
        private String description;
    
        @ApiModelProperty(value = "讲师ID")
        private String teacherId;
    
        @ApiModelProperty(value = "讲师姓名")
        private String teacherName;
    
        @ApiModelProperty(value = "讲师资历,一句话说明讲师")
        private String intro;
    
        @ApiModelProperty(value = "讲师头像")
        private String avatar;
    
        @ApiModelProperty(value = "课程类别ID")
        private String subjectLevelOneId;
    
        @ApiModelProperty(value = "类别名称")
        private String subjectLevelOne;
    
        @ApiModelProperty(value = "课程类别ID")
        private String subjectLevelTwoId;
    
        @ApiModelProperty(value = "类别名称")
        private String subjectLevelTwo;
    }
    
  • UcenterMemberOrder
    @Data
    @EqualsAndHashCode(callSuper = false)
    @Accessors(chain = true)
    @ApiModel(value="UcenterMember对象", description="会员表")
    public class UcenterMemberOrder implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        @ApiModelProperty(value = "会员id")
        @TableId(value = "id", type = IdType.ID_WORKER_STR)
        private String id;
    
        @ApiModelProperty(value = "微信openid")
        private String openid;
    
        @ApiModelProperty(value = "手机号")
        private String mobile;
    
        @ApiModelProperty(value = "密码")
        private String password;
    
        @ApiModelProperty(value = "昵称")
        private String nickname;
    
        @ApiModelProperty(value = "性别 1 女,2 男")
        private Integer sex;
    
        @ApiModelProperty(value = "年龄")
        private Integer age;
    
        @ApiModelProperty(value = "用户头像")
        private String avatar;
    
        @ApiModelProperty(value = "用户签名")
        private String sign;
    
        @ApiModelProperty(value = "是否禁用 1(true)已禁用,  0(false)未禁用")
        private Boolean isDisabled;
    
        @ApiModelProperty(value = "逻辑删除 1(true)已删除, 0(false)未删除")
        private Boolean isDeleted;
    
        @ApiModelProperty(value = "创建时间")
        @TableField(fill = FieldFill.INSERT)
        private Date gmtCreate;
    
        @ApiModelProperty(value = "更新时间")
        @TableField(fill = FieldFill.INSERT_UPDATE)
        private Date gmtModified;
    }
    

3. 在service_edu创建接口

CourseFrontController

  @PostMapping("getCourseInfoOrder/{id}")
    public CourseWebVoOrder getCourseInfoOrder(@PathVariable String id) {
        CourseWebVo courseInfo = courseService.getBaseCourseInfo(id);
        CourseWebVoOrder courseWebVoOrder = new CourseWebVoOrder();
        BeanUtils.copyProperties(courseInfo, courseWebVoOrder);
        return courseWebVoOrder;
    }

4. 在service_ucenter创建接口

UcenterMemberController

    //根据用户id获取用户信息【订单模块】
    @PostMapping("getUserInfoOrder/{id}")
    public UcenterMemberOrder getUserInfoOrder(@PathVariable String id) {
        UcenterMember member = new UcenterMember();
        UcenterMemberOrder ucenterMemberOrder = new UcenterMemberOrder();
        BeanUtils.copyProperties(member, ucenterMemberOrder);
        return ucenterMemberOrder;
    }

5. 编写订单service

(1) 在service_order模块创建接口,实现远程调用

  • EduClient:

    @Component
    @FeignClient(name = "service-edu")
    public interface EduClient {
       //根据课程id查询课程信息
       @PostMapping("/eduservice/coursefront/getCourseInfoOrder/{id}")
       public CourseWebVoOrder getCourseInfoOrder(@PathVariable("id") String id);
    }
    
  • UcenterClient

    @Component
    @FeignClient(name = "service-ucenter")
    public interface UcenterClient {
    
        //根据用户id获取用户信息【订单模块】
        @PostMapping("/educenter/member/getUserInfoOrder/{id}")
        public UcenterMemberOrder getUserInfoOrder(@PathVariable("id") String id);
    }
    

(2)在service_order模块编写创建订单service

  • OrderService

    public interface OrderService extends IService<Order> {
    
        // 生成订单的方法
        String createOrders(String courseId, String memberId);
    }
    
  • OrderServiceImpl

    @Service
    public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
    
        @Autowired
        private EduClient eduClient;
    
        @Autowired
        private UcenterClient ucenterClient;
    
        //生成订单的方法
        @Override
        public String createOrders(String courseId, String memberId) {
            //通过远程调用根据用户id获取用户信息
            UcenterMemberOrder userInfoOrder = ucenterClient.getUserInfoOrder(memberId);
    
            //通过远程调用根据课程id获取课程信息
            CourseWebVoOrder courseInfoOrder = eduClient.getCourseInfoOrder(courseId);
    
            //创建Order对象。向order对象里面设置需要数据
            Order order = new Order();
            order.setOrderNo(OrderNoUtil.getOrderNo()); //订单号
            order.setMobile(userInfoOrder.getMobile());
            order.setNickname(userInfoOrder.getNickname());
            order.setMemberId(memberId);
            order.setCourseCover(courseInfoOrder.getCover());
            order.setCourseId(courseId);
            order.setCourseTitle(courseInfoOrder.getTitle());
            order.setTeacherName(courseInfoOrder.getTeacherName());
            order.setTotalFee(courseInfoOrder.getPrice());
            order.setStatus(0);//支付状态:( 0:已支付,1:未支付 )
            order.setPayType(1);//支付类型: 1:微信 , 2:支付宝
    
            //返回订单号
            return order.getOrderNo();
        }
    }
    

三、开发获取订单接口

在订单controller创建根据id获取订单信息接口:

//2.根据订单id查询订单信息
  @GetMapping("getOrderInfo/{orderId}")
  public R getOrderInfo(@PathVariable String orderId) {
      QueryWrapper<Order> wrapper = new QueryWrapper<>();
      wrapper.eq("order_id", orderId);
      Order order = orderService.getOne(wrapper);
      return R.ok().data("item", order);
  }

开发微信支付接口

一、生成微信支付二维码

1. 编写controller

PayLogController

@RestController
@CrossOrigin
@RequestMapping("/eduorder/paylog")
public class PayLogController {

    @Autowired
    private PayLogService payLogService;

    //生成微信支付二维码接口
    //参数是订单号
    @GetMapping("createNative/{orderNo}")
    public R createNative(@PathVariable String orderNo) {
        //返回信息,包含二维码地址,还有其他需要的信息
        Map map = payLogService.createNative(orderNo);
        return R.ok().data(map);
    }
}

2. 编写service

  • PayLogService

    public interface PayLogService extends IService<PayLog> {
    
        //生成微信支付二维码接口
        Map createNative(String orderNo);
    }
    
  • PayLogServiceImpl

    @Service
    public class PayLogServiceImpl extends ServiceImpl<PayLogMapper, PayLog> implements PayLogService {
    
        @Autowired
        private OrderService orderService;
    
        //生成微信支付二维码接口
        @Override
        public Map createNative(String orderNo) {
    
            try {
                //1.根据订单号查询订单信息
                QueryWrapper<Order> wrapper = new QueryWrapper<>();
                wrapper.eq("order_no",orderNo);
                Order Order = orderService.getOne(wrapper);
    
                //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");
    
                //设置xml格式的参数
                //参数1:要转换为xml格式的map
                //参数2:商户的key,用于加密二维码中的信息
                client.setXmlParam(WXPayUtil.generateSignedXml(map,"T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));
                client.setHttps(true);//上面发送请求的是https。默认支持,需要设置为true支持
    
                //执行请求发送
                client.post();
    
                //4.得到发送请求返回结果
                //返回的结果是xml格式的
                String content = client.getContent();
    
                //把xml格式转换为map集合,他里面的数据不全
                Map<String, String> resultMap = WXPayUtil.xmlToMap(content);
    
                //最后返回数据的封装
                HashMap hashMap = new HashMap<>();
                hashMap.put("out_trade_no", orderNo);
                hashMap.put("course_id", Order.getCourseId());
                hashMap.put("total_fee", Order.getTotalFee());
                hashMap.put("result_code", resultMap.get("result_code")); //二维码操作状态码
                hashMap.put("code_url", resultMap.get("code_url")); //二维码地址
    
                //微信支付二维码2小时过期,可采取2小时未支付取消订单
                //redisTemplate.opsForValue().set(orderNo, hashMap, 120,TimeUnit.MINUTES);
    
                return hashMap;
    
            } catch (Exception e) {
                e.printStackTrace();
                throw new GuliException(20001, "生成二维码失败");
            }
        }
    }
    

二、获取支付状态接口

1. 编写controller

@RestController
@CrossOrigin
@RequestMapping("/eduorder/paylog")
public class PayLogController {

    @Autowired
    private PayLogService payLogService;

	........

    //查询订单支付状态
    //参数:订单号,根据订单号查询支付状态
    @GetMapping("queryPayStatus/{orderNo}")
    public R queryPayStatus(@PathVariable String orderNo) {
        Map<String, String> map = payLogService.queryPagStatus(orderNo);
        if (map == null) {
            return R.ok().message("支付出错了");
        }

        //如果返回map里面不为空,通过map获取订单状态
        if (map.get("trade_state").equals("SUCCESS")) { //支付成功
            //添加记录倒支付表,更新订单表订单状态
            payLogService.updateOrdersStatus(map);
            return R.ok().message("支付成功");
        }

        return R.ok().message("支付中");
    }
}

2. 编写service

  • PayLogService

    public interface PayLogService extends IService<PayLog> {
    
        //生成微信支付二维码接口
        Map createNative(String orderNo);
    
        //根据订单号查询支付状态
        Map<String, String> queryPagStatus(String orderNo);
    
        //向支付表添加记录,更新订单状态
        void updateOrdersStatus(Map<String, String> map);
    }
    
  • PayLogServiceImpl

    @Service
    public class PayLogServiceImpl extends ServiceImpl<PayLogMapper, PayLog> implements PayLogService {
    
        @Autowired
        private OrderService orderService;
    
    	......
       
        //根据订单号查询支付状态
        @Override
        public Map<String, String> queryPagStatus(String orderNo) {
            try {
                //1、封装参数
                Map m = new HashMap<>();
                m.put("appid", "wx74862e0dfcf69954");
                m.put("mch_id", "1558950191");
                m.put("out_trade_no", orderNo);
                m.put("nonce_str", WXPayUtil.generateNonceStr());
    
                //2、发送httpClient请求
                HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
                client.setHttps(true);
                client.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));//通过商户key加密
                client.post();
    
                //3、返回第三方的数据
                String xml = client.getContent();
                //4、转成Map
                Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
    
                //5、返回
                return resultMap;
            } catch (Exception e) {
                return null;
            }
        }
    
        //向支付表添加记录,更新订单状态
        @Override
        public void updateOrdersStatus(Map<String, String> map) {
            //获取前一步生成二维码中的订单号
            String orderNo = map.get("out_trade_no");
    
            //根据订单号,查询订单信息
            QueryWrapper<Order> wrapper = new QueryWrapper<>();
            wrapper.eq("order_no",orderNo);
            Order order = orderService.getOne(wrapper);
    
    
            //判断订单状态是否为1,为1就是支付过了
            if (order.getStatus().intValue()==1){return;}
    
            //更新订单表中的订单状态
            order.setStatus(1);//1代表已支付
            orderService.updateById(order);
    
            //向支付表里添加支付记录
            PayLog payLog = new PayLog();
            payLog.setOrderNo(orderNo); //支付订单号
            payLog.setPayTime(new Date()); //支付时间
            payLog.setPayType(1); //支付类型
            payLog.setTotalFee(order.getTotalFee()); //总金额(分)
            payLog.setTradeState(map.get("trade_state")); //支付状态
            payLog.setTransactionId(map.get("transaction_id")); //订单流水号
            payLog.setAttr(JSONObject.toJSONString(map));
    
            baseMapper.insert(payLog);
        }
    }
    

课程支付前端整合

一、页面样式修改

  1. 复制样式文件到assets
    在这里插入图片描述
     

  2. 修改default.vue页面

import '~/assets/css/reset.css'
import '~/assets/css/theme.css'
import '~/assets/css/global.css'
import '~/assets/css/web.css'
import '~/assets/css/base.css'
import '~/assets/css/activity_tab.css'
import '~/assets/css/bottom_rec.css'
import '~/assets/css/nice_select.css'
import '~/assets/css/order.css'
import '~/assets/css/swiper-3.3.1.min.css'
import "~/assets/css/pages-weixinpay.css"

二、课程支付前端

1. 在api文件夹下创建order.js文件

import request from '@/utils/request'

export default{

   //生成订单
   createOrders(courseId){
    return request({
        url: '/eduorder/order/createOrder/'+courseId,
        method: 'post'
      })
    },

    //根据订单id查询订单信息
    getOrdersInfo(id){
        return request({
            url: `/eduorder/order/getOrderInfo/${id}`,
            method: 'get'
        })
    },

    //生成二维码的方法
    createNatvie(orderNo) {
        return request({
        url: '/eduorder/paylog/createNative/'+orderNo,
        method: 'get'
        })
    },

    //查询订单状态的方法
    //生成二维码的方法
    queryPayStatus(orderNo) {
        return request({
        url: '/eduorder/paylog/queryPayStatus/'+orderNo,
        method: 'get'
        })
    }
}

2. 在课程详情页面中添加创建订单方法

在这里插入图片描述
 

//生成订单的方法
    createOrders(){
        ordersApi.createOrders(this.courseWebVo.courseId).then(response => {
            //获取返回订单号
            // response.data.data.orderId
            //跳转订单显示页面
            this.$router.push({path:'/orders/'+response.data.data.orderId})
        })
    },

3. 创建订单页面,显示订单信息

在pages下面创建order文件夹,创建_oid.vue页面
在_oid.vue页面调用方法,获取订单信息:

  • 页面部分
    <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 ordersApi from '@/api/orders'
    
    export default {
        asyncData({ params, error }) {
            return ordersApi.getOrdersInfo(params.oid)
                .then(response => {
                    return {
                        order: response.data.data.item
                    }
                })
        },
    
        methods: {
            //去支付
            toPay() {
                this.$router.push({path:'/pay/'+this.order.orderNo})
            }
        
        } 
    }
    </script> 
    

 

4. 创建支付页面,生成二维码完成支付

  • 页面部分

    <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 ordersApi from '@/api/orders'
    
    export default {
        //  asyncData({ params, error }) {
        //      return ordersApi.createNatvie(params.pid)
        //         .then(response => {
        //             return {
        //                   payObj: response.data.data
        //                 }
        //         })
        //  },
    
         created() {
            this.orderNo = this.$route.params.orderNo;
            //生成二维码
            this.createQRcode();
        },
    
         data() {
             return {
                orderNo: "",
                payObj: {},
                timer1: "",
             }
         },
    
         //每隔三秒调用一次查询订单状态的方法
         mounted() { //页面渲染之后执行
            this.timer1 = setInterval(() => {
                this.queryOrderStatus(this.payObj.out_trade_no)
            },3000);
         },
    
         methods:{
            //生成二维码
            createQRcode() {
                ordersApi.createNatvie(this.orderNo).then((resp) => {
                    this.payObj = resp.data.data;
                });
            },
    
             queryOrderStatus(orderNo) {
                 ordersApi.queryPayStatus(orderNo)
                    .then(response => {
                         if (response.data.success) {
                            //支付成功,清除定时器
                            clearInterval(this.timer1)
                            //提示
                            this.$message({
                                type: 'success',
                                message: '支付成功!'
                            })
                            //跳转回到课程详情页面
                            this.$router.push({path: '/course/' + this.payObj.course_id})
                         }
                    })
             }
         }
    }
        
    
    </script>
    

5. 拦截器

在这里插入图片描述
 

utils\request.js

// http response 拦截器
service.interceptors.response.use(
    response => {
        //debugger
        if (response.data.code == 28004) {
            console.log("response.data.resultCode是28004")
            // 返回 错误代码-1 清除ticket信息并跳转到登录页面
            //debugger
            window.location.href = "/login"
            return
        } else {
            if (response.data.code !== 20000) {
                //25000:订单支付中,不做任何提示
                if (response.data.code != 25000) {
                    Message({
                        message: response.data.message || 'error',
                        type: 'error',
                        duration: 5 * 1000
                    })
                }
            } else {
                return response;
            }
        }
    },
    error => {
        return Promise.reject(error.response) // 返回接口返回的错误信息
})

7. 测试

在这里插入图片描述
 
在这里插入图片描述
 

 
在这里插入图片描述
 
在这里插入图片描述


创作不易,如果有帮助到你,请给文章点个赞和收藏,让更多的人看到!!!
关注博主不迷路,内容持续更新中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/131852.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【观察】美达电器:以数字化重塑质量管理体系,构筑车企新“护城河”

在汽车行业&#xff0c;越来越多的企业走上数字化转型道路&#xff0c;运用数字化手段&#xff0c;从产品研发、生产制造、供应链管理等方面优化内部协同&#xff0c;从而降低管理成本&#xff0c;提升市场竞争力。美达电器(重庆)有限公司&#xff08;以下简称美达电器&#xf…

day17-缓冲流转换流序列化流打印流Properties

day17_JAVAOOP 课程目标 1. 【理解】什么是缓冲流 2. 【掌握】缓冲流的使用 3. 【理解】转换流 4. 【理解】序列化流 5. 【理解】打印流 6. 【掌握】Properties集合的使用缓冲流 ​ 前期我们学习了基本的一些流&#xff0c;作为IO流的入门&#xff0c;今天我们要见识一些更强…

babylon.js魔方建模

本文主要内容可能和babylon并无太紧密的关联&#xff0c; 主要是对旋转&#xff08; 空间想象力 &#xff09;的练习。 本来想写个魔方练练&#xff0c;就想着顺便练练baboly. 结果反正是最重要的交互逻辑没有实现。 标题已经说明了本文的主题是建模&#xff0c;也就是说&…

ArcGIS基础实验操作100例--实验29矢量数据空间校正

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验29 矢量数据空间校正 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;1&…

android中service实现原理分析

前言&#xff1a; 一开始的目标是解决各种各样的ANR问题的&#xff0c;我们知道&#xff0c;ANR总体上分有四种类型&#xff0c;这四种类型有三种是和四大组件相对应的&#xff0c;所以&#xff0c;如果想了解ANR发生的根因&#xff0c;对安卓四大组件的实现流程是必须要了解的…

Odoo 16 企业版手册 - 库存管理之产品管理

产品管理 记录与产品相关的每个方面对于有效维护库存至关重要。Odoo 库存模块使您可以在数据库中配置新产品&#xff0c;这些产品将有效跟踪和监控所有操作&#xff0c;以加强各自产品的库存管理。库存模块中的产品配置过程与销售和购买模块的流程几乎相似。您将在库存的主菜单…

一步一步学爬虫(4)数据存储之CSV文件存储

一步一步学爬虫&#xff08;4&#xff09;数据存储之CSV文件存储4.3 CSV文件存储4.3.1 写入4.3.2 读取4.3.3 总结4.3 CSV文件存储 CSV&#xff0c;全称Comma-Separated Values&#xff0c;中文叫做逗号分隔值或字符分隔值&#xff0c;其文件以纯文本形式存储表格数据。CSV文件…

java.lang.OutOfMemoryError: GC overhead limit exceeded问题分析及解决

一、错误重现 2022-12-29 10:12:07.210 ERROR 73511 --- [nio-8001-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.…

SQL刷题宝典-MySQL速通力扣困难题

&#x1f4e2;作者&#xff1a; 小小明-代码实体 &#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/as604049322 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 欢迎讨论&#xff01; 本手册目录&#xff1a; 文章目录前言Markdown导入数据库python脚…

奇安信 工业互联网安全发展与实践 报告 学习笔记一 欢迎扶正

声明 本文是学习2021工业互联网安全发展与实践分析报告. 下载地址而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 主要观点 工业系统安全漏洞数量增长显著放缓&#xff0c;但超高危漏洞数量却大幅增加。统计显示&#xff0c;2021年&#xff0c;国内外…

Linux 软件包管理器 yum

1.什么是软件包 在Linux下安装软件&#xff0c;一个通常的办法是下载到程序的源代码&#xff0c;并进行编译&#xff0c;得到可执行程序。但是这样太麻烦了&#xff0c;于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放在一个服务器上&…

再见2022

大家好&#xff0c;我是bigsai&#xff0c;好久不见。看了上一篇更新时间&#xff0c;大概已经停更近10个月(呜呜后面还会坚持的)&#xff0c;在2022的最后一天&#xff0c;这一篇也算是对这一年做个总结。期间也收到一些朋友的问候和鼓励&#xff0c;确实自己在读研期间的前两…

山东大学2022-2023非关系型数据库(Nosql)期末考试

写在前面的话&#xff1a; 今年线上开卷考试&#xff0c;Nosql考试软工&#xff08;限选课&#xff09;和大数据&#xff08;必修课&#xff09;是一套试题&#xff0c;因此大数据所学的许多内容考试并无涉及。考察点主要以学过的四类Nosql数据库的相关知识为主。 试题如下&…

引用量超1400的经典语义分割方法BiSeNet解读

今天给大家分享语义分割领域非常经典的一篇论文&#xff1a;BiSeNet&#xff0c;该论文发表在了ECCV2018上&#xff0c;引用量超过1400。 开源代码地址&#xff1a;https://github.com/ycszen/TorchSeg 1.动机 语义分割任务&#xff0c;即为图片的每个像素分配一个标签&#…

嵌入式 程序调试之gdb+gdbserver+vscode可视化调试

嵌入式 程序调试之gdbgdbservervscode可视化调试 一、简述 记--使用过visual studio的都知道&#xff0c;它的单步调试真的好用&#xff0c;可以直接在源码下断点&#xff0c;实时查看内存变量、寄存器等相关信息。嵌入式linux开发多用的是gdb, 都是命令行执行的&#xff0c;毕…

python特殊数据类型应用(1)字典类型

目录python中特殊数据类型应用&#xff08;1&#xff09;字典类型字典类型定义字典类型注意事项字典类型的访问python中特殊数据类型应用&#xff08;1&#xff09;字典类型 python作为最流行的几种开发语言之一&#xff0c;在数据类型上和传统的c、c和java等有很大的不同&…

Typora使用方法

自用&#xff0c;有错误请谅解 tpora破解版使用学习使用&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1Wj46k3iVIzr-7kwQstp9nQ 提取码&#xff1a;2sa8 来源教程网址&#xff1a;Typora一款 Markdown 编辑器和阅读器 记得更改图片位置&#xff0c;以后就是相对路径…

babel及其使用

什么是Babel&#xff1f; Babel 是一个工具链&#xff0c;由大量的工具包组成&#xff0c;接下来我们逐步了解。主要用于将 ECMAScript 2015 版本的代码转换为向后兼容的 JavaScript 语法&#xff0c;以便能够运行在当前和旧版本的浏览器或其他环境中。 核心库 babel/core B…

‘this’不能用于常量表达式错误(C++)【问题解决】

目录 一、报错问题 1、代码 test.h test.cpp 2、问题描述 二、网上解决思路 三、解决方案 【元旦快乐&#x1f339;&#xff0c;新年快乐&#x1f389;】 最近在编译程序时出现了“ ‘this’不能用于常量表达式错误(C )”的报错问题&#xff0c;查阅多位博主写的文章后&…

mysql 性能优化

mysql 调优可以从这个四个方面来看 1.性能监控 1.1 show profile for query n 查看具体的sql语句各阶段执行时间 show profiles; show profile for query n; 1.2 performance schema 监控mysql 整个服务器中发生的各种事件。 performance schema 表中的数据不会持久化的磁…