用什么播放器支持所有格式的视频播放mch文件?

Day 13(07.10)登录前端登录成功之后页面显示数据实现过程调用接口登录返回token字符串把第一步返回字符串放到cookie里面创建前端拦截器,判断cookie中是否有字符串,有的话把token字符串放到header(请求头)中根据token值调用接口,根据token获取用户信息,为了页面显示,把调用接口返回用户信息放到cookie里面从第4步cookie获取用户信息,在首页面显示用户信息具体操作 在api文件夹创建login.js文件 import request from '@/utils/request' export default { //登录 submitLoginUser(userInfo) { return request({ url: `/educenter/member/login`, method: 'post', data:userInfo }) }, //根据token值获取用户信息 getLoginUserInfo(){ return request({ url: `/educenter/member/getMenberInfo`, method: 'get' }) } } 在登录页面进行方法调用 下载插件 npm install js-cookie 调用过程 login.vue //登录的方法 //第一步 调用接口登录返回token字符串 submitLogin(){ loginApi.submitLoginUser(this.user) .then(response =>{ //第二步 字符串放到cookie里面 //第一个参数:cookie名称,第二个参数:参数的值,第三个参数:参数的作用范围 cookie.set('guli_token',response.data.token,{domain:'localhost'}) //第四步调用接口,根据token获取用户信息,为了页面显示 loginApi.getLoginUserInfo() .then( response =>{ //获取返回的用户信息,放到cookie中 cookie.set('guli_ucenter',response.data.userInfo,{domain:'localhost'}) }) }) }, 在request.js添加拦截器,用于传递token信息 //第三步 创建拦截器 http request 拦截器 service.interceptors.request.use( config => { //debugger //判断cookie里面是否有名称是guli_token的数据 if (cookie.get('guli_token')) { //把获取cookie值放到header里面 config.headers['token'] = cookie.get('guli_token'); } return config }, err => { return Promise.reject(err); }) default.vue页面显示登录之后的用户信息 created() {//第五步 this.showInfo() }, methods:{ //创建方法,从cookie获取用户信息 showInfo(){ //从cookie获取用户信息 var userStr = cookie.get("guli_ucenter"); //把字符串转成json对象形式 if (userStr) { this.loginInfo = JSON.parse(userStr) } } } 登录后的页面 退出功能//退出 logout(){ //清空cookie值 cookie.set('guli_ucenter', "", {domain: 'localhost'}) cookie.set('guli_token', "", {domain: 'localhost'}) //回到首页面 window.location.href = "/" } 微信扫码登录OAuth2是针对特定问题的一种解决方案,不是协议。主要解决:分布式系统间访问,开放系统间授权开放系统间授权用户名密码复制通用开发者key办法令牌分布式访问(单点登录)OAuth2解决方案:令牌机制,按照一定规则生成字符串,字符串包含用户信息微信扫码登录 在service_ucenter模块配置文件 # 微信开放平台 appid wx.open.app_id=wxed9954c01bb89b47 # 微信开放平台 appsecret wx.open.app_secret=a7482517235173ddb4083788de60b90e # 微信开放平台 重定向url wx.open.redirect_url=http://guli.shop/api/ucenter/wx/callback 创建类读取配置文件内容 @Component public class ConstantWxUtils implements InitializingBean { @Value("${wx.open.app_id}") private String appId; @Value("${wx.open.app_secret}") private String appSecret; @Value("${wx.open.redirect_url}") private String redirectUrl; public static String WX_OPEN_APP_ID; public static String WX_OPEN_APP_SECRET; public static String WX_OPEN_REDIRECT_URL; @Override public void afterPropertiesSet() throws Exception { WX_OPEN_APP_ID = appId; WX_OPEN_APP_SECRET = appSecret; WX_OPEN_REDIRECT_URL = redirectUrl; } } 生成微信二维码 直接请求微信提供的固定地址,向地址后面拼接参数 @CrossOrigin @Controller//注意这里没有配置 @RestController @RequestMapping("/api/ucenter/wx") public class WxApiController { //生成微信二维码 @GetMapping("login") public String getXxCode(){ //固定地址,后面拼接参数 //微信开放平台授权baseUrl, %s相当于占位符?,这个位置要传参数 String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" + "?appid=%s" + "&redirect_uri=%s" + "&response_type=code" + "&scope=snsapi_login" + "&state=%s" + "#wechat_redirect"; //对redirect_url进行URLEncoder编码 String redirectUrl=ConstantWxUtils.WX_OPEN_REDIRECT_URL; try{ redirectUrl= URLEncoder.encode(redirectUrl,"utf-8"); }catch (Exception e){ e.printStackTrace(); } //设置%s中的值 String url = String.format( baseUrl, ConstantWxUtils.WX_OPEN_APP_ID, ConstantWxUtils.WX_OPEN_REDIRECT_URL, "lujin"); //重定向到请求微信地址 return "redirect:"+url; } } 此时只是请求地址,不需要返回数据,所以用@Controller注解而不用@RestController注解 扫码之后跳转到本地方法 获取扫描人信息分析用到的技术点 httpclient,json转换工具(fastjson、gson、jackson) 扫描之后,执行本地callback方法,在callback获取两个值,在跳转的时候传递过来 state:原样传递 code:临时票据。类似于手机验证码,随机唯一值 拿第一步获取的code值,请求微信提供固定的地址,获取两个值 access_token:访问凭证 openid:每个微信唯一标识 拿第二步获取的两个值,再去请求一个微信提供的固定地址,最终获取到微信扫码人信息。 昵称、头像等 具体操作 引入依赖 org.apache.httpcomponents httpclient commons-io commons-io com.google.code.gson gson controller try{ //1 获取code值,临时票据,类似于验证码 //2 拿code值,请求微信提供固定的地址,获取两个值access_token,openid String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" + "?appid=%s" + "&secret=%s" + "&code=%s" + "&grant_type=authorization_code"; //拼接三个参数:id 秘钥 code String accessTokenUrl = String.format( baseAccessTokenUrl, ConstantWxUtils.WX_OPEN_APP_ID, ConstantWxUtils.WX_OPEN_APP_SECRET, code); //请求这个拼接好的地址,获取两个值access_token,openid //使用httpclient发送请求,得到返回结果 String accessTokenInfo = HttpClientUtils.get(accessTokenUrl); //从accessTokenInfo获取access_token,openid //将accessTokenInfo字符串转换成map集合,根据map里面的可以获取对应值 //使用gson Gson gson=new Gson(); HashMap mapAccessToken = gson.fromJson(accessTokenInfo, HashMap.class); String access_token=(String)mapAccessToken.get("access_token"); String openid=(String) mapAccessToken.get("openid"); //把扫码人信息添加到数据库 //判断数据库表是否存在相同扫码人信息,不存在,则添加,根据openid判断 UcenterMember member=memberService.getOpenIdMember(openid); if (member==null){ //3 拿得到的access_token,openid,再去请求一个微信提供的固定地址,最终获取到微信扫码人信息。 //访问微信的资源服务器,获取用户信息 String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" + "?access_token=%s" + "&openid=%s"; //拼接两个参数 String userInfoUrl = String.format( baseUserInfoUrl, access_token, openid ); //发送请求 String userInfo = HttpClientUtils.get(userInfoUrl); //获取返回userInfo字符串扫码人的信息 HashMap userInfoMap = gson.fromJson(userInfo, HashMap.class); String nickname = (String) userInfoMap.get("nickname");//昵称 String headimgurl = (String) userInfoMap.get("headimgurl");//头像 //添加 member=new UcenterMember(); member.setOpenid(openid); member.setAvatar(headimgurl); member.setNickname(nickname); memberService.save(member); } //解决跨域问题 //使用JWT根据member对象生成token字符串 String jwtToken = JwtUtils.getJwtToken(member.getId(), member.getNickname()); //最后: 返回首页面,通过路径传递token字符串 return "redirect:http://localhost:3000?token="+jwtToken; }catch (Exception e){ throw new GuliException(20001,"登录失败"); } service //根据id判断数据库中是否有此用户 @Override public UcenterMember getOpenIdMember(String openid) { QueryWrapper wrapper=new QueryWrapper<>(); wrapper.eq("openid",openid); UcenterMember member = baseMapper.selectOne(wrapper); return member; } 5.前端页面显示 在首页面路径中获取token字符串 把获取的token放到cookie里面 有前端拦截器,判断cookie是否有token,若有,把cookie中的token取出来,放到header里 调用后端接口,根据token值获取用户信息 代码 created() { //获取路径里面的token this.token = this.$route.query.token if (this.token) { this.wxLogin() } this.showInfo() }, methods:{ //微信登录显示方法 wxLogin() { if (this.token == '') return //把token存在cookie中、也可以放在localStorage中 cookie.set('guli_token', this.token, {domain: 'localhost'}) cookie.set('guli_ucenter', '', {domain: 'localhost'}) //调用接口,登录成功根据token获取用户信息 loginApi.getLoginUserInfo().then(response => { this.loginInfo = response.data.data.userInfo //将用户信息记录cookie cookie.set('guli_ucenter', this.loginInfo, {domain: 'localhost'}) }) }, //创建方法,从cookie获取用户信息 showInfo(){ //从cookie获取用户信息 var userStr = cookie.get("guli_ucenter"); //把字符串转成json对象形式 if (userStr) { this.loginInfo = JSON.parse(userStr) } }, //退出 logout(){ //清空cookie值 cookie.set('guli_ucenter', "", {domain: 'localhost'}) cookie.set('guli_token', "", {domain: 'localhost'}) //回到首页面 window.location.href = "/" } } Day 14(07.11)前台名师列表功能后端 分页查询名师接口 controller @RestController @RequestMapping("/eduservice/teacherfront") @CrossOrigin public class TeacherFrontController { @Autowired private EduTeacherService teacherService; //1 分页查询讲师的方法 @PostMapping("getTeacherFrontList/{page}/{limit}") public R getTeacherFrontList(@PathVariable long page,@PathVariable long limit){ Page pageTeacher = new Page<>(page,limit); Map map=teacherService.getTeacherFrontList(pageTeacher); //返回分页中的所有数据 return R.ok().data(map); } } service //1 分页查询讲师的方法 @Override public Map getTeacherFrontList(Page pageParam) { QueryWrapper wrapper=new QueryWrapper<>(); wrapper.orderByDesc("id"); //把分页数据封装到pageTeacher对象 baseMapper.selectPage(pageParam,wrapper); List records = pageParam.getRecords(); long current = pageParam.getCurrent(); long pages = pageParam.getPages(); long size = pageParam.getSize(); long total = pageParam.getTotal(); boolean hasNext = pageParam.hasNext();//是否有下一页 boolean hasPrevious = pageParam.hasPrevious();//是否有上一页 //把分页数据获取出来,放到map集合 Map map=new HashMap<>(); map.put("items", records); map.put("current", current); map.put("pages", pages); map.put("size", size); map.put("total", total); map.put("hasNext", hasNext); map.put("hasPrevious", hasPrevious); //返回map return map; swagger测试 前端 在api 创建teacher.js,定义接口地址 //分页查询讲师的方法 getTeacherList(page,limit) { return request({ url: `/eduservice/teacherfront/getTeacherFrontList/${page}/${limit}`, method: 'post' }) }, 在页面引入js文件,调用方法实现显示 //异步调用,调用一次 //params:相当于this.$toute.params.id 等价 params.id asyncData({ params, error }) { return teacher.getPageList(1, 8).then(response => { return { data: response.data.data } }); }, methods:{ //分页切换的方法 //参数是页码数 GotPage(page){ teacherApi.getTeacherList(page,8) .then(response =>{ this.data=response.data.data }) } } 名师详情功能后端 controller //2 讲师详情功能 @GetMapping("getTeacherFrontInfo/{teacherId}") public R getTeacherFrontInfo(@PathVariable String teacherId){ //1 根据讲师id查询讲师基本信息 EduTeacher eduTeacher=teacherService.getById(teacherId); //2 根据讲师id查询所有课程 QueryWrapper wrapper=new QueryWrapper<>(); wrapper.eq("teacher_id",teacherId); List courseList=courseService.list(wrapper); return R.ok().data("teacher",eduTeacher).data("courseList",courseList); } 前端 api/teacher.js //查询讲师详情的方法 getTeacherInfo(id) { return request({ url: `/eduservice/teacherfront/getTeacherFrontInfo/${id}`, method: 'get' }) }, pages/teacher/_id.vue asyncData({ params, error }) { return teacher.getTeacherInfo(params.id) .then(response => { return { teacher: response.data.data.teacher, courseList: response.data.data.courseList } }) } 课程列表功能后端 创建vo对象,封装条件数据 @Data public class CourseFrontVo { @ApiModelProperty(value = "课程名称") private String title; @ApiModelProperty(value = "讲师id") private String teacherId; @ApiModelProperty(value = "一级类别id") private String subjectParentId; @ApiModelProperty(value = "二级类别id") private String subjectId; @ApiModelProperty(value = "销量排序") private String buyCountSort; @ApiModelProperty(value = "最新时间排序") private String gmtCreateSort; @ApiModelProperty(value = "价格排序") private String priceSort; } controller //1 分页查询课程的方法 @PostMapping("getFrontCourseList/{page}/{limit}") public R getFrontCourseList(@PathVariable long page, @PathVariable long limit, @RequestBody(required = false) CourseFrontVo courseFrontVo){//required=false表示courseFrontVo可以为空 Page pageCourse = new Page<>(page,limit); Map map=courseService.getCourseFrontList(pageCourse,courseFrontVo); //返回分页中的所有数据 return R.ok().data(map); } service //1 分页查询课程的方法 @Override public Map getCourseFrontList(Page pageParam, CourseFrontVo courseFrontVo) { //2 根据讲师id查询所有课程 QueryWrapper wrapper=new QueryWrapper<>(); //判断条件值是否为空,不空拼接 if(!StringUtils.isEmpty(courseFrontVo.getSubjectParentId())){ //一级分类 wrapper.eq("subject_parent_id",courseFrontVo.getSubjectParentId()); } if(!StringUtils.isEmpty(courseFrontVo.getSubjectId())){ //二级分类 wrapper.eq("subject_id",courseFrontVo.getSubjectId()); } if(!StringUtils.isEmpty(courseFrontVo.getBuyCountSort())){ //关注度/销量 wrapper.orderByDesc("but_count"); } if (!StringUtils.isEmpty(courseFrontVo.getGmtCreateSort())) { //最新时间 wrapper.orderByDesc("gmt_create"); } if (!StringUtils.isEmpty(courseFrontVo.getPriceSort())) { //价格 wrapper.orderByDesc("price"); } baseMapper.selectPage(pageParam,wrapper); List records = pageParam.getRecords(); long current = pageParam.getCurrent(); long pages = pageParam.getPages(); long size = pageParam.getSize(); long total = pageParam.getTotal(); boolean hasNext = pageParam.hasNext(); boolean hasPrevious = pageParam.hasPrevious(); Map map = new HashMap(); map.put("items", records); map.put("current", current); map.put("pages", pages); map.put("size", size); map.put("total", total); map.put("hasNext", hasNext); map.put("hasPrevious", hasPrevious); return map; } 前端 定义api/course.js //分页查询课程的方法 getCourseList(page,limit) { return request({ url: `/eduservice/coursefront/getFrontCourseList/${page}/${limit}`, method: 'post', data:searchobj }) }, //查询所有分类的方法 getAllSubject() { return request({ url: `/eduservice/subject/getAllSubject`, method: 'get' }) }, 页面调用接口pages/course/index.vue created(){ //第一次查询 this.initCourseFirst() //一级分类显示 this.initSubject() }, methods:{ //1 查询第一页数据 initCourseFirst(){ courseApi.getCourseList(1,8,this.searchobj) .then(response =>{ this.data=response.data.data }) }, //2 查询所有一级分类(包含二级分类) initSubject(){ courseApi.getAllSubject() .then(response =>{ this.subjectNestedList=response.data.data.list }) }, //3 分页切换方法 gotoPage(page){ courseApi.getCourserList(page,8,this.searchobj) .then(response =>{ this.data=response.data.data }) } } 显示所有一级分类,点击某个一级分类,在下面显示对应二级分类 //4 点击某个一级分类,查询对应二级分类 searchOne(subjectParentId,index){ //把传递过来的index值赋值给oneIndex,为了active样式生效,显示选中效果 this.oneIndex=index this.twoIndex=-1 this.searchObj.subjectId="" this.subSubjectList=[] //把一级分类点击id值,赋值给searchObj this.searchObj.subjectParentId=subjectParentId //点击某个一级分类进行条件查询 this.gotoPage(1) //拿着点击的一级分类id和所有的一级分类id进行比较 //如果id相同,从一级分类中获取对应的二级分类 for(let i=0;i chapterVideoList = chapterService.getChapterVideoByCourseId(courseId); return R.ok().data("courseWeVo",courseWebVo).data("chapterVideoList",chapterVideoList); } service //1 根据课程id,编写SQL语句查询课程信息 @Override public CourseWebVo getBaseCourseInfo(String courseId) { return baseMapper.getBaseCourseInfo(courseId); } 在EduCourseMapper.xml中编写SQL语句,根据课程id查询课程信息 前端 api/course.js //课程详情的方法 getCourseInfo(id) { return request({ url: `/eduservice/coursefront/getFrontCourseInfo/${id}`, method: 'get' }) }, pages/course/_id.vue

{{courseWebVo.description}}

把HTML标签翻译 整合阿里云播放器视频播放 创建接口,根据视频id获取视频播放凭证 //根据视频id获取视频凭证 @GetMapping("getPlayAuth/{id}") public R getPlayAuth(@PathVariable String id) { try { //创建初始化对象 DefaultAcsClient client = InitVodCilent.initVodClient(ConstantVodUtils.ACCESS_KEY_ID, ConstantVodUtils.ACCESS_KEY_SECRET); //创建获取凭证request和response对象 GetVideoPlayAuthRequest request = new GetVideoPlayAuthRequest(); //向request设置视频id request.setVideoId(id); //调用方法得到凭证 GetVideoPlayAuthResponse response = client.getAcsResponse(request); String playAuth = response.getPlayAuth(); return R.ok().data("playAuth",playAuth); }catch(Exception e) { throw new GuliException(20001,"获取凭证失败"); } } 点击某个小节,打开新的页面进行播放视频 修改超链接地址 a :href="'/player/'+video.videoSourceId" target="_blank">//target在新页面打开 在pages创建文件夹和文件,使用动态路由方式 前端 创建api模块 api/vod.js,从后端获取播放凭证 import request from '@/utils/request' export default { getPlayAuth(vid) { return request({ url: `/eduvod/video/getPlayAuth/${id}`, method: 'get' }) } } 创建 pages/player/_vid.vue export default { layout: 'video',//应用video布局 asyncData({ params, error }) { return vod.getPlayAuth(params.vid) .then(response => { return { playAuth: response.data.data.playAuth, vid: params.vid } }) }, mounted() { //页面渲染之后执行 created new Aliplayer({ id: 'J_prismPlayer', vid: this.vid, // 视频id playauth: this.playAuth, // 播放凭证 encryptType: '1', // 如果播放加密视频,则需设置encryptType=1,非加密视频无需设置此项 width: '100%', height: '500px', // 以下可选设置 cover: 'http://guli.shop/photo/banner/1525939573202.jpg', // 封面 qualitySort: 'asc', // 清晰度排序 mediaType: 'video', // 返回音频还是视频 autoplay: false, // 自动播放 isLive: false, // 直播 rePlay: false, // 循环播放 preload: true, controlBarVisibility: 'hover', // 控制条的显示方式:鼠标悬停 useH5Prism: true, // 播放器类型:html5 }, function(player) { console.log('播放器创建成功') }) } } Day 15(07.12)课程评论功能分页查询评论列表 创建课程评论表 创建接口,创建两个方法 分页查询课程评论的方法 @RestController @RequestMapping("/eduservice/comment") @CrossOrigin public class CommentFrontController { @Autowired private CommentService commentService; @Autowired private UcenterClient ucenterClient; //根据课程id查询评论列表 @ApiOperation(value = "评论分页列表") @GetMapping("{page}/{limit}") public R index( @ApiParam(name = "page", value = "当前页码", required = true) @PathVariable Long page, @ApiParam(name = "limit", value = "每页记录数", required = true) @PathVariable Long limit, @ApiParam(name = "courseQuery", value = "查询对象", required = false) String courseId) { Page pageParam = new Page<>(page, limit); QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("course_id",courseId); commentService.page(pageParam,wrapper); List commentList = pageParam.getRecords(); Map map = new HashMap<>(); map.put("items", commentList); map.put("current", pageParam.getCurrent()); map.put("pages", pageParam.getPages()); map.put("size", pageParam.getSize()); map.put("total", pageParam.getTotal()); map.put("hasNext", pageParam.hasNext()); map.put("hasPrevious", pageParam.hasPrevious()); return R.ok().data(map); } 添加评论 要添加的数据 课程评论内容:输入内容,提交到接口 课程id、讲师id:进入详情页面根据课程id查询 用户id、用户昵称、用户头像:做评论之前必须先登录,从header获取token字符串(从request获取),根据token字符串获取用户id(使用jwt获取),根据用户id查询用户表,把需要的数据获取出来 添加评论在edu模块,远程调用UCenter模块获取用户信息,进行添加评论 @ApiOperation(value = "添加评论") @PostMapping("auth/save") public R save(@RequestBody Comment comment, HttpServletRequest request) { String memberId = JwtUtils.getMemberIdByJwtToken(request); if(StringUtils.isEmpty(memberId)) { return R.error().code(28004).message("请登录"); } comment.setMemberId(memberId); UcenterMemberPay ucenterInfo = ucenterClient.getUcenterPay(memberId); comment.setNickname(ucenterInfo.getNickname()); comment.setAvatar(ucenterInfo.getAvatar()); commentService.save(comment); return R.ok(); } } 课程支付功能 课程免费:不需要支付,直接播放。点击免费课程,进入详情页面,在课程大纲列表位置可以视频观看 课程收费:点击免费课程,进入详情页面,点击购买,生成订单,向订单表添加一条记录,点击支付,生成支付 二维码,使用微信扫描二维码进行支付,支付后向支付日志表添加支付记录,回到课程详情页面显示 立即观看,小节可以点击视频播放。 使用代码生成器生成代码接口 生成订单接口、根据订单id查询订单信息接口、生成微信支付二维码接口、查询订单支付状态接口 生成订单接口远程调用 nacos service_order生成订单接口需要课程信息和用户信息,需要远程调用service_edu的一个接口,该接口根据课程id返回课程信息,再远程调用service_ucenter模块的接口,该接口根据用户id,查询用户信息并返回。 service_order的controller @RestController @RequestMapping("/eduorder/order") @CrossOrigin public class OrderController { @Autowired private OrderService orderService; //1 生成订单方法 @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); } } 创建两个interface,指定调用服务名称和接口地址 EduClient接口 @Component @FeignClient("service-edu")//调用服务名字 public interface EduCLient { //根据课程id获取课程信息 @PostMapping("/eduservice/coursefront/getCourseInfoOrder/{id}")//调用接口的完整地址 public CourseWebVoOrder getCourseInfoOrder(@PathVariable("id") String id);//注解后面必须加一个参数 } UcenterClient接口 @Component @FeignClient("service-ucenter") public interface UcenterClient { //根据用户id获取用户信息 @PostMapping("/educenter/member/getUserInfoOrder/{id}") public UcenterMemberOrder getUserInfoOrder(@PathVariable("id") String id); } service_order的service @Autowired private EduCLient eduCLient; @Autowired UcenterClient ucenterClient; //1 生成订单方法 @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.setCourseId(courseID);//课程id order.setCourseTitle(courseInfoOrder.getTitle()); order.setCourseCover(courseInfoOrder.getCover()); order.setTeacherName(courseInfoOrder.getTeacherName()); order.setTotalFee(courseInfoOrder.getPrice()); order.setMemberId(memberId); order.setMobile(userInfoOrder.getMobile()); order.setNickname(userInfoOrder.getNickname()); order.setStatus(0);//支付状态,支付后为1 order.setPayType(1);//支付类型,微信1 baseMapper.insert(order); //返回订单号 return order.getOrderNo(); } service_ucenter的controller 需要创建一个公共的实体类,用来返回用户信息 //根据用户id获取用户信息 @PostMapping("getUserInfoOrder/{id}") public UcenterMemberOrder getUserInfoOrder(@PathVariable String id){ UcenterMember member=new UcenterMember(); //把member对象里面的值赋值给UCenterMemberOrder对象 UcenterMemberOrder ucenterMemberOrder=new UcenterMemberOrder(); BeanUtils.copyProperties(member,ucenterMemberOrder); return ucenterMemberOrder; } service_edu的controller //根据课程id获取课程信息 @PostMapping("getCourseInfoOrder/{id}") public CourseWebVoOrder getCourseInfoOrder(@PathVariable String id){ CourseWebVo courseInfo = courseService.getBaseCourseInfo(id); CourseWebVoOrder courseWebVoOrder=new CourseWebVoOrder(); BeanUtils.copyProperties(courseInfo,courseWebVoOrder); return courseWebVoOrder; } 根据订单id查询订单信息接口 controller //2 根据订单号查询订单信息 @GetMapping("getOrderInfo/{orderId}") public R getOrderInfo(@PathVariable String orderId){ QueryWrapper wrapper=new QueryWrapper<>(); wrapper.eq("order_no",orderId);//订单号 Order order=orderService.getOne(wrapper); return R.ok().data("item",order); } 整合生成订单页面(前端) api/orders.js //生成订单 createOrders(courseId) { return request({ url: '/eduorder/order/createOrder/'+courseId, method: 'post' }) }, //根据订单id查询订单信息 getOrdersInfo(id) { return request({ url: '/eduorder/order/getOrderInfo/'+id, method: 'get' }) }, 页面调用,在“立即购买”位置添加事件 //生成订单 createOrders() { ordersApi.createOrders(this.courseId) .then(response => { //获取返回订单号 //生成订单之后,跳转订单显示页面 this.$router.push({path:'/orders/'+response.data.data.orderId}) }) } } pages/order/_oid.vue syncData({ params, error }) { return ordersApi.getOrdersInfo(params.oid) .then(response => { return { order: response.data.data.item } }) }, 生成微信支付二维码接口 controller @RestController @RequestMapping("/eduorder/paylog") @CrossOrigin public class PayLogController { @Autowired private PayLogService payLogService; //生成微信支付二维码接口 //参数是订单号 @GetMapping("crateNative/{orderNo}") public R createNative(@PathVariable String orderNo){ //返回信息,包含二维码地址,还有其他信息 Map map=payLogService.createNative(orderNo); return R.ok().data(map); } } service @Autowired private OrderService orderService; //生成微信支付二维码接口 @Override public Map createNative(String orderNo) { try{ //1 根据订单号查询订单信息 QueryWrapper wrapper=new QueryWrapper<>(); wrapper.eq("order_no",orderNo); Order order = orderService.getOne(wrapper); //2 使用map设置生成二维码需要参数 Map m=new HashMap(); m.put("appid", "wx74862e0dfcf69954");//微信id m.put("mch_id", "1558950191");//商户号 m.put("nonce_str", WXPayUtil.generateNonceStr());//随机字符串,让每个二维码都不一样 m.put("body", order.getCourseTitle());//课程名称 m.put("out_trade_no", orderNo);//二维码唯一标志,订单号 m.put("total_fee", order.getTotalFee().multiply(new BigDecimal("100")).longValue()+"");//价格 m.put("spbill_create_ip", "127.0.0.1");//支付的IP地址 m.put("notify_url", "http://guli.shop/api/order/weixinPay/weixinNotify\n");//支付后回调地址 m.put("trade_type", "NATIVE");//生成二维码支付类型 //3 发送httpclient请求,传递参数xml个格式,微信支付提供的固定地址 HttpClient client=new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder"); //设置xml格式的参数 client.setXmlParam(WXPayUtil.generateSignedXml(m,"T6m9iK73b0kn9g5v426MKfHQH7X8rKwb")); client.setHttps(true); //执行post请求发送 client.post(); //4 得到发送请求返回结果 //返回内容,是使用xml格式返回 String xml = client.getContent(); //把xml格式转换成map集合,把map集合返回 Map resultMap=WXPayUtil.xmlToMap(xml); //最终返回数据的封装 Map map=new HashMap(); map.put("out_trade_no", orderNo); map.put("course_id", order.getCourseId()); map.put("total_fee", order.getTotalFee()); map.put("result_code", resultMap.get("result_code"));//返回二维码操作状态码 map.put("code_url", resultMap.get("code_url"));//二维码地址 return map; }catch (Exception e){ throw new GuliException(20001,"生成二维码失败"); } } 查询订单支付状态接口 controller //查询订单支付状态 //参数:订单号,根据订单号查询支付状态 @GetMapping("queryPayStatus/{orderNo}") public R queryPayStatus(@PathVariable String orderNo){ Map map=payLogService.queryPayStatus(orderNo); if (map==null){ return R.error().message("支付出错了"); } //如果返回map里面不为空,通过map查询订单状态 if (map.get("trade_state").equals("SUCCESS")){//支付成功 //添加记录到支付记录表,更新订单表订单状态 payLogService.updateOrderStatus(map); return R.ok().message("支付成功"); } return R.ok().code(25000).message("支付中"); } service //根据订单号查询订单支付状态 @Override public Map queryPayStatus(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.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb")); client.setHttps(true); client.post(); //3、得到请求返回内容 String xml = client.getContent(); Map resultMap = WXPayUtil.xmlToMap(xml); //6、转成Map再返回 return resultMap; } catch (Exception e) { e.printStackTrace(); } return null; } //向支付表中添加记录,更新订单状态 @Override public void updateOrderStatus(Map map) { //从map获取订单号 String orderNo=map.get("out_trade_no"); // 根据订单号查询订单信息 QueryWrapper wrapper=new QueryWrapper<>(); wrapper.eq("order_no",orderNo); Order order = orderService.getOne(wrapper); //更新订单表订单状态 if (order.getStatus()==1){ return; } order.setStatus(1);//1代表已支付 orderService.updateById(order); //向支付表添加支付记录 PayLog payLog=new PayLog(); payLog.setOrderNo(order.getOrderNo());//支付订单号 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);//插入到支付日志表 } 微信支付二维码页面(前端) api/orders.js //生成二维码的方法 createNatvie(orderNo) { return request({ url: '/eduorder/paylog/createNative/'+orderNo, method: 'get' }) }, //查询订单状态的方法 //生成二维码的方法 queryPayStatus(orderNo) { return request({ url: '/eduorder/paylog/queryPayStatus/'+orderNo, method: 'get' }) } 页面调用,在“去支付”位置添加事件 methods:{ //去支付 toPay() { this.$router.push({path:'/pay/'+this.order.orderNo}) } } pages/pay/_pid.vue syncData({ params, error }) { return ordersApi.getOrdersInfo(params.oid) .then(response => { return { order: response.data.data.item } }) }, data() { return { timer1:'' } }, //每隔三秒调用一次查询订单状态的方法 mounted() {//页面渲染之后执行 this.timer1 = setInterval(() => { this.queryOrderStatus(this.payObj.out_trade_no) },3000); }, methods:{ 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}) } }) } } 功能完善 如果课程是免费课程,按钮显示立即观看 如果课程是已经支付过,按钮显示立即观看 如果课程没有购买,或者不是免费课程,按钮显示立即购买 如何判断课程是否已经支付了根据课程id和用户id查询订单表,查询订单状态,如果状态为1就是支付了后端 创建接口,order模块的OrderController //根据课程id和用户id查询订单表中订单状态 @GetMapping("isBuyCourse/{courseId}/{memberId}") public boolean isBuyCourse(@PathVariable String courseId,@PathVariable String memberId){ QueryWrapper wrapper=new QueryWrapper<>(); wrapper.eq("course_id",courseId); wrapper.eq("member_id",memberId); wrapper.eq("status",1); int count = orderService.count(wrapper); if (count>0){ //能查询到,表示已经支付 return true; }else { return false; } } 在课程详情页面显示立即观看或立即购买,需修改课程详情查询接口,添加返回值,返回当前显示详情的课程是否已经被购买过了 创建interface,为了服务调用 @Component @FeignClient("service-order") public interface OrdersClient { //根据课程id和用户id查询订单表中订单状态 @GetMapping("eduorder/order/isBuyCourse/{courseId}/{memberId}") public boolean isBuyCourse(@PathVariable("courseId") String courseId, @PathVariable("memberId") String memberId); } 修改CourseFrontController //2 课程详情功能 @GetMapping("getFrontCourseInfo/{courseId}") public R getFrontCourseInfo(@PathVariable String courseId, HttpServletRequest request){ //1 根据课程id,编写SQL语句查询课程信息 CourseWebVo courseWebVo=courseService.getBaseCourseInfo(courseId); //2 根据课程id查询章节和小节 List chapterVideoList = chapterService.getChapterVideoByCourseId(courseId); //修改部分 //根据课程id和用户id查询当前课程是否已经支付过了 boolean buyCourse = ordersClient.isBuyCourse(courseId, JwtUtils.getMemberIdByJwtToken(request)); return R.ok().data("courseWeVo",courseWebVo).data("chapterVideoList",chapterVideoList).data("isBuy",buyCourse); } 前端 asyncData({ params, error }) { return {courseId: params.id} }, data() { return { courseWebVo: {}, chapterVideoList: [], isbuy: false, } }, created() {//在页面渲染之前执行 this.initCourseInfo() }, methods:{ //查询课程详情信息 initCourseInfo() { courseApi.getCourseInfo(this.courseId) .then(response => { this.courseWebVo=response.data.data.courseWebVo, this.chapterVideoList=response.data.data.chapterVideoList, this.isbuy=response.data.data.isBuy }) }, @GetMapping("eduorder/order/isBuyCourse/{courseId}/{memberId}") public boolean isBuyCourse(@PathVariable("courseId") String courseId, @PathVariable("memberId") String memberId); } ``` 修改CourseFrontController //2 课程详情功能 @GetMapping("getFrontCourseInfo/{courseId}") public R getFrontCourseInfo(@PathVariable String courseId, HttpServletRequest request){ //1 根据课程id,编写SQL语句查询课程信息 CourseWebVo courseWebVo=courseService.getBaseCourseInfo(courseId); //2 根据课程id查询章节和小节 List chapterVideoList = chapterService.getChapterVideoByCourseId(courseId); //修改部分 //根据课程id和用户id查询当前课程是否已经支付过了 boolean buyCourse = ordersClient.isBuyCourse(courseId, JwtUtils.getMemberIdByJwtToken(request)); return R.ok().data("courseWeVo",courseWebVo).data("chapterVideoList",chapterVideoList).data("isBuy",buyCourse); } 前端 asyncData({ params, error }) { return {courseId: params.id} }, data() { return { courseWebVo: {}, chapterVideoList: [], isbuy: false, } }, created() {//在页面渲染之前执行 this.initCourseInfo() }, methods:{ //查询课程详情信息 initCourseInfo() { courseApi.getCourseInfo(this.courseId) .then(response => { this.courseWebVo=response.data.data.courseWebVo, this.chapterVideoList=response.data.data.chapterVideoList, this.isbuy=response.data.data.isBuy }) }, }

我要回帖

更多关于 什么播放器支持所有格式的视频 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信