资料
资料地址
后台管理系统目录 前台展示系统目录
1 - 构建工程篇 7 - 渲染前台篇
2 - 前后交互篇 8 - 前台登录篇
3 - 文件上传篇 9 - 前台课程篇
4 - 课程管理篇 10 - 前台支付篇
5 - 章节管理篇 11 - 统计分析篇
6 - 微服务治理 12 - 项目完结篇

文章目录

  • 一、讲师列表页
    • 1.1、后端接口
    • 1.2、前端展示
    • 1.3、分页功能
  • 二、讲师详情页
    • 2.1、后端接口
    • 2.2、前端展示
  • 三、课程列表页
    • 3.1、后端接口
    • 3.2、前端展示
  • 四、讲师详情页
    • 4.1、后端接口
    • 4.2、前端展示
  • 五、整合阿里云视频播放器
    • 5.1、后端接口
    • 5.2、前端展示
  • 六、课程评论功能
    • 6.1、数据库设计
    • 6.2、远程调用接口
    • 6.3、后端接口
    • 6.4、前端展示

一、讲师列表页

1.1、后端接口

1、控制层

@RestController
@CrossOrigin
@RequestMapping("eduservice/teacherFront")
public class TeacherFrontController {@AutowiredEduTeacherService eduTeacherService;@RequestMapping("/getTeacherFrontPageList/{page}/{limit}")public R getTeacherFrontPageList(@PathVariable Long limit, @PathVariable Long page) {Page<EduTeacher> teacherPage = new Page<>(page, limit);Map<String, Object> map = eduTeacherService.getTeacherFrontPageList(teacherPage);return R.ok().data(map);}
}

2、业务层

//前台系统分页查询讲师的方法
@Override
public Map<String, Object> getTeacherFrontPageList(Page<EduTeacher> teacherPage) {QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();wrapper.orderByAsc("gmt_create");//把分页数据封装到pageTeacher对象中baseMapper.selectPage(teacherPage, wrapper);//把分页的数据获取出来返回一个map集合HashMap<String, Object> map = new HashMap<>();//总记录数long total = teacherPage.getTotal();//当前页long current = teacherPage.getCurrent();//每页记录数long size = teacherPage.getSize();//查询到的对象List<EduTeacher> teacherList = teacherPage.getRecords();//总页数long pages = teacherPage.getPages();//是否有上一页boolean hasPrevious = teacherPage.hasPrevious();//是否有下一页boolean hasNext = teacherPage.hasNext();//将数据封装到map中返回map.put("total", total);map.put("current", current);map.put("size", size);map.put("list", teacherList);map.put("hasPrevious", hasPrevious);map.put("hasNext", hasNext);map.put("pages", pages);return map;
}

1.2、前端展示

1、api/teacher.js

import request from '@/utils/request'export default{getPageList(page, limit){return request({url:`/eduservice/teacherFront/getTeacherFrontPageList/${page}/${limit}`,method: 'get'})}
}

2、teacher/index.vue

<script>
import teacherAPI from "@/api/teacher";export default {//异步调用,进页面调用,且只会调一次//params:相当于之前的 this.$route.params.id 等价 params.id//error:错误信息asyncData({ params, error }) {return teacherAPI.getPageList(1, 8).then((response) => {//this.data = response.data.datareturn { data: response.data.data };});},data() {return {};},
};
</script>

3、页面

<div><!-- /无数据提示 开始--><section class="no-data-wrap" v-if="data.total == 0"><em class="icon30 no-data-ico">&nbsp;</em><span class="c-666 fsize14 ml10 vam">没有相关数据,小编正在努力整理 中...</span></section><!-- /无数据提示 结束--><article class="i-teacher-list" v-if="data.total > 0"><ul class="of"><li v-for="item in data.list" :key="item.id"><section class="i-teach-wrap"><div class="i-teach-pic"><a :href="'/teacher/'+item.id" :title="item.name" target="_blank"><img :src="item.avatar" :alt="item.name" /></a></div><div class="mt10 hLh30 txtOf tac"><a :href="'/teacher/'+item.id" :title="item.name" target="_blank" class="fsize18 c-666">{{ item.name }}</a></div><div class="hLh30 txtOf tac"><span class="fsize14 c-999">{{item.intro}}</span></div><div class="mt15 i-q-txt"><p class="c-999 f-fA">{{item.career}}</p></div></section></li></ul><div class="clear"></div></article>
</div>

4、展示


1.3、分页功能

1、js

methods: {//分页切换方法//参数是页码数gotoPage(page) {teacherAPI.getPageList(page, 4).then((resp) => {this.data = resp.data.data;});},
},

2、页面

<!-- 公共分页 开始 -->
<div><div class="paging"><!-- undisable这个class是否存在,取决于数据属性hasPrevious --><a :class="{ undisable: !data.hasPrevious }" href="#" title="首页" @click.prevent="gotoPage(1)">首页</a><a :class="{ undisable: !data.hasPrevious }" href="#" title="前一页" @click.prevent="gotoPage(data.current - 1)">&lt;</a><a v-for="page in data.pages" :key="page" :class="{ current: data.current == page, undisable: data.current == page,}" :title="'第' + page + '页'" href="#" @click.prevent="gotoPage(page)">{{ page }}</a><a :class="{ undisable: !data.hasNext }" href="#" title="后一页" @click.prevent="gotoPage(data.current + 1)">&gt;</a><a :class="{ undisable: !data.hasNext }" href="#" title="末页" @click.prevent="gotoPage(data.pages)">末页</a><div class="clear" /></div>
</div>
<!-- 公共分页 结束 -->

二、讲师详情页

2.1、后端接口

编写接口:

  • 根据讲师id查询讲师信息
  • 根据讲师id查询讲师所讲课程
/*** 根据id查询讲师信息*/
@GetMapping("/getTeacherInfo/{id}")
public R getTeacherInfo(@PathVariable String id) {EduTeacher teacher = eduTeacherService.getById(id);QueryWrapper<EduCourse> wrapper = new QueryWrapper<>();wrapper.eq("teacher_id", id);List<EduCourse> courseList = eduCourseService.list(wrapper);return R.ok().data("teacher", teacher).data("courseList", courseList);
}


2.2、前端展示

1、api/teacher.js

import request from '@/utils/request'export default{// 根据ID查询讲师本身信息+课程信息getTeacherInfoByid(id){return request({url: `/eduservice/teacherFront/getTeacherInfo/${id}`,method: `get`})},
}

2、js

import teacherApi from '@/api/teacher'
export default {created() {this.teacherId = this.$route.params.idthis.getByid()},data() {return {teacher: {name: '',intro: '',career: '',level: '',},courseList: [],teacherId: '',}},methods: {getByid() {teacherApi.getTeacherInfoByid(this.teacherId).then(resp => {this.teacher = resp.data.data.teacherthis.courseList = resp.data.data.courseList})}},
};

3、页面

<template><div id="aCoursesList" class="bg-fa of"><!-- 讲师介绍 开始 --><section class="container"><header class="comm-title"><h2 class="fl tac"><span class="c-333">讲师介绍</span></h2></header><div class="t-infor-wrap"><!-- 讲师基本信息 --><section class="fl t-infor-box c-desc-content"><div class="mt20 ml20"><section class="t-infor-pic"><img :src="teacher.avatar" /></section><h3 class="hLh30"><span class="fsize24 c-333">{{teacher.name}}&nbsp;{{teacher.level ===1?'高级讲师':'首席讲师'}}</span></h3><section class="mt10"><span class="t-tag-bg">{{teacher.career}}</span></section><section class="t-infor-txt"><p class="mt20">{{teacher.intro}}</p></section><div class="clear"></div></div></section><div class="clear"></div></div><section class="mt30"><div><header class="comm-title all-teacher-title c-course-content"><h2 class="fl tac"><span class="c-333">主讲课程</span></h2><section class="c-tab-title"><a href="javascript: void(0)">&nbsp;</a></section></header><!-- /无数据提示 开始--><section class="no-data-wrap" v-if="courseList.length==0"><em class="icon30 no-data-ico">&nbsp;</em><span class="c-666 fsize14 ml10 vam">没有相关数据,小编正在努力整理 中...</span></section><!-- /无数据提示 结束--><article class="comm-course-list"><ul class="of"><li v-for="course in courseList" :key="course.id"><div class="cc-l-wrap"><section class="course-img"><img :src="course.cover" class="img-responsive" /><div class="cc-mask"><a :href="'/course/'+course.id" title="开始学习" target="_blank" class="comm- btn c-btn-1">开始学习</a></div></section><h3 class="hLh30 txtOf mt10"><a :href="'/course/'+course.id" :title="course.title" target="_blank" class="course-title fsize18 c-333">{{course.title}}</a></h3></div></li></ul><div class="clear"></div></article></div></section></section><!-- /讲师介绍 结束 --></div>
</template>

4、展示


三、课程列表页

3.1、后端接口

1、创建vo进行模糊查询

package com.laptoy.eduservice.entity.frontVo;@Data
public class CourseFrontVo implements Serializable {private static final long serialVersionUID = 1L;@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;}

2、控制层

@RestController
@CrossOrigin
@RequestMapping("eduservice/courseFront")
public class CourseFrontController {@AutowiredEduCourseService courseService;@PostMapping("/getFrontCourseList/{page}/{limit}")public R getFrontCourseList(@PathVariable Long limit, @PathVariable Long page,@RequestBody CourseFrontVo courseFrontVo) {Page<EduCourse> coursePage = new Page<>(page, limit);Map<String, Object> map = courseService.getFrontCourseList(coursePage, courseFrontVo);return R.ok().data(map);}}

3、业务层

@Override
public Map<String, Object> getFrontCourseList(Page<EduCourse> pageCourse, CourseFrontVo courseFrontVo) {String title = null;String subjectId = null;String subjectParentId = null;String gmtCreateSort = null;String buyCountSort = null;String priceSort = null;String teacherId = null;if (!StringUtils.isEmpty(courseFrontVo)) {title = courseFrontVo.getTitle();subjectId = courseFrontVo.getSubjectId();subjectParentId = courseFrontVo.getSubjectParentId();gmtCreateSort = courseFrontVo.getGmtCreateSort();buyCountSort = courseFrontVo.getBuyCountSort();priceSort = courseFrontVo.getPriceSort();teacherId = courseFrontVo.getTeacherId();}QueryWrapper<EduCourse> wrapper = new QueryWrapper<>();//判断条件值是否为空,不为空拼接条件if (!StringUtils.isEmpty(subjectParentId)) {//一级分类wrapper.eq("subject_parent_id", subjectParentId);}if (!StringUtils.isEmpty(subjectId)) {//二级分类wrapper.eq("subject_id", subjectId);}if (!StringUtils.isEmpty(buyCountSort)) {//关注度wrapper.orderByDesc("buy_count");}if (!StringUtils.isEmpty(priceSort)) {//价格wrapper.orderByDesc("price");}if (!StringUtils.isEmpty(gmtCreateSort)) {//最新,创建时间wrapper.orderByDesc("gmt_create");}baseMapper.selectPage(pageCourse, wrapper);long total = pageCourse.getTotal();//总记录数List<EduCourse> courseList = pageCourse.getRecords();//数据集合long size = pageCourse.getSize();//每页记录数long current = pageCourse.getCurrent();//当前页long pages = pageCourse.getPages();//总页数boolean hasPrevious = pageCourse.hasPrevious();//是否有上一页boolean hasNext = pageCourse.hasNext();//是否有下一页HashMap<String, Object> map = new HashMap<>();map.put("total", total);map.put("list", courseList);map.put("size", size);map.put("current", current);map.put("pages", pages);map.put("hasPrevious", hasPrevious);map.put("hasNext", hasNext);return map;
}

3.2、前端展示

1、api/course.js

import request from '@/utils/request'export default {//前台多条件分页查询getConditionPage(page, limit, searchObj) {return request({url: `/eduservice/courseFront/getFrontCourseList/${page}/${limit}`,method: 'post',data: searchObj})},//查询所有分类(一级分类、二级分类)的方法getAllSubject() {return request({url: `/eduservice/subject/getAllSubject`,method: 'get'})}
}

2、js

<script>
import courseApi from "@/api/course";
export default {data() {return {page: 1, //当前页data: {}, //课程列表oneSubjects: [], // 一级分类列表subSubjectList: [], // 二级分类列表searchObj: {}, // 查询表单对象oneIndex: -1,twoIndex: -1,buyCountSort: "",gmtCreateSort: "",priceSort: "",index: 0};},methods: {// 1.1、初始化课程initCourseFirst() {courseApi.getConditionPage(1, 4, this.searchObj).then((resp) => {this.data = resp.data.data;});},// 1.2、初始化一级分类initSubject() {courseApi.getAllSubject().then((resp) => {this.oneSubjects = resp.data.data.data;});},// 2、分页切换方法gotoPage(page) {courseApi.getConditionPage(page, 4, this.searchObj).then((resp) => {this.data = resp.data.data;});},// 3.1、点击某个一级分类,查询对应的二级分类seacherOne(subjectParentId, index) {this.oneIndex = index;this.twoIndex = -1;// 1)把一级分类点击的id值,赋值给searchObj,以便于进行模糊查询this.searchObj.subjectParentId = subjectParentId;// 2)点击某个一级分类进行条件查询,此时给查询条件赋值了一级分类idthis.gotoPage(1);// 3)查出所有一级分类id并与传入的id作比较,如果相同则查出该id对应的所有二级分类for (let i = 0; i < this.oneSubjects.length; i++) {var oneSubject = this.oneSubjects[i];if (oneSubject.id == subjectParentId) {this.subSubjectList = oneSubject.children;}}// 4)查询完毕清空一级分类idthis.searchObj.subjectParentId = "";},// 3.2、点击某个二级分类实现查询searchTwo(subjectId, index) {// 把index赋值,为了样式生效this.twoIndex = index;// 1)把二级分类点击id值,赋给searchObjthis.searchObj.subjectId = subjectId;// 2)点击某个二级分类进行调节查询this.gotoPage(1);// 查询完毕清空二级分类idthis.searchObj.subjectId = "";},// 4.1、根据价格进行排序searchPrice() {//设置对应变量值,为了样式生效this.buyCountSort = ''this.gmtCreateSort = ''this.priceSort = '1'//把值赋值到searchObj中this.searchObj.buyCountSort = this.buyCountSortthis.searchObj.priceSort = this.priceSortthis.searchObj.gmtCreateSort = this.gmtCreateSort//调用方法查询this.gotoPage(1)},// 4.2、根据最新进行排序searchGmtCreate() {//设置对应变量值,为了样式生效this.buyCountSort = ''this.gmtCreateSort = '1'this.priceSort = ''//把值赋值到searchObj中this.searchObj.buyCountSort = this.buyCountSortthis.searchObj.priceSort = this.priceSortthis.searchObj.gmtCreateSort = this.gmtCreateSort//调用方法查询this.gotoPage(1)},// 4.3、根据销量排序searchBuyCount() {//设置对应变量值,为了样式生效this.buyCountSort = '1'this.gmtCreateSort = ''this.priceSort = ''//把值赋值到searchObj中this.searchObj.buyCountSort = this.buyCountSortthis.searchObj.priceSort = this.priceSortthis.searchObj.gmtCreateSort = this.gmtCreateSort//调用方法查询this.gotoPage(1)},// 5、显示全部showAll(){this.subSubjectList = [];this.gotoPage(1)}},created() {// 查询所有课程this.initCourseFirst();// 查询所有一级分类this.initSubject();},
};
</script>
<style scoped>
.active {background: rgb(111, 199, 111);
}
.hide {display: none;
}
.show {display: block;
}
</style>

3、页面

<template><div id="aCoursesList" class="bg-fa of"><!-- /课程列表 开始 --><section class="container"><!-- 导航头 开始 --><header class="comm-title"><h2 class="fl tac"><span class="c-333">全部课程</span></h2></header><!-- 导航头 结束 --><section class="c-sort-box"><!-- 课程类别导航 开始--><section class="c-s-dl"><!-- 一级分类导航 --><dl><dt><span class="c-999 fsize14">课程类别</span></dt><dd class="c-s-dl-li"><ul class="clearfix"><li><a title="全部" href="#" @click="showAll">全部</a></li><li v-for="oneSubject in oneSubjects" :key="oneSubject.id" :class="{active:oneIndex==index}"><a :title="oneSubject.title" @click="seacherOne(oneSubject.id, index)" href="#">{{ oneSubject.title }}</a></li></ul></dd></dl><!-- 二级分类导航 --><dl><dt><span class="c-999 fsize14"></span></dt><dd class="c-s-dl-li"><ul class="clearfix"><li v-for="subject in subSubjectList" :key="subject.id" :class="{active:twoIndex==index}"><a :title="subject.title" @click="searchTwo(subject.id, index)" href="#">{{ subject.title }}</a></li></ul></dd></dl><div class="clear"></div></section><!-- 课程类别导航 结束--><!-- 销量导航 开始--><div class="js-wrap"><section class="fr"><span class="c-ccc"><i class="c-master f-fM">1</i>/<i class="c-666 f-fM">1</i></span></section><section class="fl"><ol class="js-tap clearfix"><li :class="{ 'current bg-orange': buyCountSort != '' }"><a title="销量" href="javascript:void(0);" @click="searchBuyCount()">销量<span :class="{ hide: buyCountSort == '' }">↓</span></a></li><li :class="{ 'current bg-orange': gmtCreateSort != '' }"><a title="最新" href="javascript:void(0);" @click="searchGmtCreate()">最新<span :class="{ hide: gmtCreateSort == '' }">↓</span></a></li><li :class="{ 'current bg-orange': priceSort != '' }"><a title="价格" href="javascript:void(0);" @click="searchPrice()">价格&nbsp;<span :class="{ hide: priceSort == '' }">↓</span></a></li></ol></section></div><!-- 销量导航 结束--><!-- 内容数据 开始--><div class="mt40"><!-- /无数据提示 开始--><section class="no-data-wrap" v-if="data.total == 0"><em class="icon30 no-data-ico">&nbsp;</em><span class="c-666 fsize14 ml10 vam">没有相关数据,小编正在努力整理 中...</span></section><!-- /无数据提示 结束--><!-- 遍历课程数据 开始 --><article class="comm-course-list" v-if="data.total > 0"><ul class="of" id="bna"><li v-for="item in data.list" :key="item.id"><div class="cc-l-wrap"><section class="course-img"><img :src="item.cover" class="img-responsive" :alt="item.title" /><div class="cc-mask"><a href="/course/1" title="开始学习" class="comm-btn c- btn-1">开始学习</a></div></section><h3 class="hLh30 txtOf mt10"><a href="/course/1" :title="item.title" class="course-title fsize18 c-333">{{ item.title }}</a></h3><section class="mt10 hLh20 of"><span class="fr jgTag bg-green" v-if="Number(item.price) === 0"><i class="c-fff fsize12 f-fA">免费</i></span><span class="fl jgAttr c-ccc f-fA"><i class="c-999 f-fA">9634人学习</i> | <i class="c-999 f-fA">9634评论</i></span></section></div></li></ul><div class="clear"></div></article><!-- 遍历课程数据 结束 --></div><!-- 内容数据 结束--><!-- 公共分页 开始 --><div><div class="paging"><!-- undisable这个class是否存在,取决于数据属性hasPrevious --><a :class="{ undisable: !data.hasPrevious }" href="#" title="首页" @click.prevent="gotoPage(1)">首</a><a :class="{ undisable: !data.hasPrevious }" href="#" title="前一页" @click.prevent="gotoPage(data.current - 1)">&lt;</a><a v-for="page in data.pages" :key="page" :class="{ current: data.current == page, undisable: data.current == page,}" :title="'第' + page + '页'" href="#" @click.prevent="gotoPage(page)">{{ page }}</a><a :class="{ undisable: !data.hasNext }" href="#" title="后一页" @click.prevent="gotoPage(data.current + 1)">&gt;</a><a :class="{ undisable: !data.hasNext }" href="#" title="末页" @click.prevent="gotoPage(data.pages)">末</a><div class="clear" /></div></div><!-- 公共分页 结束 --></section></section><!-- /课程列表 结束 --></div>
</template>





四、讲师详情页

4.1、后端接口

1、编写sql语句,根据课程id查询课程信息

  • 课程基本信息
  • 课程分类
  • 课程描述
  • 所属讲师

2、根据课程id查询章节和小节


1、courseWebVo

@Data
public class CourseWebVo {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;
}

2、控制层

// 2、课程详情页
@GetMapping("/getFrontCourseInfo/{courseId}")
public R getFrontCourseInfo(@PathVariable("courseId") String courseId) {// 根据课程id编写sql语句查询课程信息CourseWebVo courseWebVo = courseService.getBaseCourseInfo(courseId);// 根据课程id查询章节和小节List<ChapterVo> chapterVideoList  = chapterService.getChapterVideoByCourseId(courseId);return R.ok().data("courseWebVo",courseWebVo).data("chapterVideoList",chapterVideoList);
}

3、业务层

@Override
public CourseWebVo getBaseCourseInfo(String courseId) {return baseMapper.getBaseCourseInfo(courseId);
}

4、dao

<!--前台根据课程id,查询课程基础信息-->
<select id="getBaseCourseInfo" resultType="com.laptoy.eduservice.entity.frontVo.CourseWebVo">SELECT ec.id,ec.title,ec.cover,ec.lesson_num as lessonNum,ec.price,ec.cover,ec.buy_count  as buyCount,ec.view_count as viewCount,esd.description,s1.title      as subjectLevelOne,s2.title      AS subjectLevelTwo,s1.id         as subjectLevelOneId,s2.id         as subjectLevelTwoId,t.name        AS teacherName,t.id          as teacherId,t.avatar,t.introFROM edu_course ecLEFT JOIN edu_teacher t ON ec.teacher_id = t.idLEFT JOIN edu_course_description esd on ec.id = esd.idLEFT JOIN edu_subject s1 ON ec.subject_parent_id = s1.idLEFT JOIN edu_subject s2 ON ec.subject_id = s2.idWHERE ec.id = #{id}
</select>

4.2、前端展示

按课程id进行跳转查询

1、api

//根据课程id查询
getFrontCourseInfo(courseId){return request({url: `/eduservice/courseFront/getFrontCourseInfo/${courseId}`,method: 'get'})
}

2、js - course/_id.vue

<script>
import courseApi from "@/api/course";
export default {data() {return {chapterList: [],course: {courseId: "",},};},created() {this.course.courseId = this.$route.params.id;this.getCourseInfo();},methods: {// 获取课程详细信息getCourseInfo() {courseApi.getFrontCourseInfo(this.course.courseId).then((resp) => {this.chapterList = resp.data.data.chapterVideoList;this.course = resp.data.data.courseWebVo;});},},};
</script>

3、页面

<template><div id="aCoursesList" class="bg-fa of"><!-- /课程详情 开始 --><section class="container"><!-- 回退导航栏 开始 --><section class="path-wrap txtOf hLh30"><a href="/" title class="c-999 fsize14">首页</a>\<a href="/course" title class="c-999 fsize14">{{course.subjectLevelOne}}</a>\<span class="c-333 fsize14">{{ course.subjectLevelTwo }}</span></section><!-- 回退导航栏 结束 --><div><!-- 课程大图左侧 封面 --><article class="c-v-pic-wrap" style="height: 357px"><section class="p-h-video-box" id="videoPlay"><img :src="course.cover" :alt="course.title" class="dis c-v-pic" height="355px" width="630px" /></section></article><!-- 课程大图中侧 细节 --><aside class="c-attr-wrap"><section class="ml20 mr15"><h2 class="hLh30 txtOf mt15"><span class="c-fff fsize24">{{ course.title }}</span></h2><section class="c-attr-jg"><span class="c-fff">价格:</span><b class="c-yellow" style="font-size: 24px">¥{{ course.price }}</b></section><section class="c-attr-mt c-attr-undis"><span class="c-fff fsize14">主讲: {{ course.teacherName }}&nbsp;&nbsp;&nbsp;</span></section><section class="c-attr-mt of"><span class="ml10 vam"><em class="icon18 scIcon"></em><a class="c-fff vam" title="收藏" href="#">收藏</a></span></section><section class="c-attr-mt"><a href="#" title="立即观看" class="comm-btn c-btn-3">立 即 观 看</a></section></section></aside><!-- 课程大图右侧 详情 --><aside class="thr-attr-box"><ol class="thr-attr-ol clearfix"><li><p>&nbsp;</p><aside><span class="c-fff f-fM">销量</span><br /><h6 class="c-fff f-fM mt10">{{ course.buyCount }}</h6></aside></li><li><p>&nbsp;</p><aside><span class="c-fff f-fM">课时数</span><br /><h6 class="c-fff f-fM mt10">{{ course.lessonNum }}</h6></aside></li><li><p>&nbsp;</p><aside><span class="c-fff f-fM">浏览数</span><br /><h6 class="c-fff f-fM mt10">{{ course.viewCount }}</h6></aside></li></ol></aside><div class="clear"></div></div><!-- 课程描述 大纲 讲师 --><div class="mt20 c-infor-box"><article class="fl col-7"><section class="mr30"><div class="i-box"><div><section id="c-i-tabTitle" class="c-infor-tabTitle c-tab- title"><a name="c-i" class="current" title="课程详情">课 程 详 情</a></section></div> <!-- 课程描述及大纲 --><article class="ml10 mr10 pt20"><!-- 课程描述 --><div><h6 class="c-i-content c-infor-title"><span>课程介绍</span></h6><div class="course-txt-body-wrap"><section class="course-txt-body"><p v-html="course.description">{{ course.description }}</p></section></div></div><!-- 课程大纲 章节小节 --><div class="mt50"><h6 class="c-g-content c-infor-title"><span>课程大纲</span></h6><section class="mt20"><div class="lh-menu-wrap"><menu id="lh-menu" class="lh-menu mt10 mr10"><ul><!-- 文件目录 --><li class="lh-menu-stair" v-for="chapter in chapterList" :key="chapter.id"><a href="javascript: void(0)" :title="chapter.title" class="current-1"><em class="lh-menu-i-1 icon18 mr10"></em>{{chapter.title}}</a><ol class="lh-menu-ol" style="display: block"><li class="lh-menu-second ml30" v-for="video in chapter.children" :key="video.id"><a href="#" title><span class="fr" v-if="video.free=== true"><i class="free-icon vam mr10">免费试听</i></span><em class="lh-menu-i-2 icon16 mr5">&nbsp;</em>{{video.title}}</a></li></ol></li></ul></menu></div></section></div><!-- /课程大纲 --></article></div></section></article><!-- 课程讲师 开始 --><aside class="fl col-3"><div class="i-box"><div><section class="c-infor-tabTitle c-tab-title"><a title href="javascript:void(0)">主讲讲师</a></section><section class="stud-act-list"><ul style="height: auto"><li><div class="u-face"><a href="#"><img :src="course.avatar" width="50" height="50" alt /></a></div><section class="hLh30 txtOf"><a class="c-333 fsize16 fl" href="#">{{course.teacherName}}</a></section><section class="hLh20 txtOf"><span class="c-999">{{course.intro}}</span></section></li></ul></section></div></div></aside><!-- 课程讲师 结束 --><div class="clear"></div></div></section><!-- /课程详情 结束 --></div>
</template>



五、整合阿里云视频播放器

5.1、后端接口

1、VodController

//根据视频id获取视频凭证
@GetMapping("/getPlayAuth/{id}")
public R getPlayAuth(@PathVariable String id) {try {String playAuth = vodService.getPlayAuth(id);return R.ok().data("playAuth", playAuth);} catch (Exception e) {e.printStackTrace();throw new LaptoyException(20001, "获取视频凭证失败");}
}

2、业务层

@Value("${aliyun.vod.file.keyid}")
private String accessKeyId;@Value("${aliyun.vod.file.keysecret}")
private String accessKeySecret;// 根据视频id获取视频凭证
@Override
public String getPlayAuth(String id) {String accesskeyId = accessKeyId;String accesskeySecret = accessKeySecret;try {//创建初始化对象DefaultAcsClient cl = InitObject.initVodClient(accesskeyId, accesskeySecret);//创建获取视频地址request对象和response对象GetVideoPlayAuthRequest request = new GetVideoPlayAuthRequest();//向request对象设置视频id值request.setVideoId(id);GetVideoPlayAuthResponse response = cl.getAcsResponse(request);//获取视频播放凭证return response.getPlayAuth();} catch (ClientException e) {e.printStackTrace();throw new LaptoyException(20001, "获取视频凭证失败");}
}
//初始化类
public class InitObject {public static DefaultAcsClient initVodClient(String accessKeyId, String accessKeySecret) throws ClientException {String regionId = "cn-shanghai";  // 点播服务接入区域DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);DefaultAcsClient client = new DefaultAcsClient(profile);return client;}
}


5.2、前端展示

1、修改超链接地址

2、在pages创建文件夹player,下级创建文件_vid.vue

3、videoVo添加

4、新建播放器布局 /layout/video.vue

<template><div class="guli-player"><div class="head"><a href="#" title="谷粒学院"><img class="logo" src="~/assets/img/logo.png" lt="谷粒学院"></a></div><div class="body"><div class="content"><nuxt/></div></div></div>
</template>
<script>
export default {}
</script><style>
html,body{height:100%;
}
</style><style scoped>
.head {height: 50px;position: absolute;top: 0;left: 0;width: 100%;
}.head .logo{height: 50px;margin-left: 10px;
}.body {position: absolute;top: 50px;left: 0;right: 0;bottom: 0;overflow: hidden;
}
</style>

5、vod.js

import request from '@/utils/request'export default {//根据视频id,获取视频凭证getPlayAuthById(vid) {return request({url: `/eduvod/video/getPlayAuth/${vid}`,method: 'get'})}
}

6、页面 _vid.vue

<template><div><!-- 阿里云视频播放器样式 --><link rel="stylesheet" href="https://g.alicdn.com/de/prismplayer/2.8.1/skins/default/aliplayer-min.css" /><!-- 阿里云视频播放器脚本 --><script charset="utf-8" type="text/javascript" src="https://g.alicdn.com/de/prismplayer/2.8.1/aliplayer-min.js" /><!-- 定义播放器dom --><div id="J_prismPlayer" class="prism-player" /></div>
</template>

7、js

<script>
import vodApi from "@/api/vod";
export default {layout: "video", //应用video布局// 异步数据请求asyncData({ params }) {return vodApi.getPlayAuthById(params.vid).then((response) => {return {playAuth: response.data.data.playAuth,vid: params.vid,};});},mounted() {//页面渲染之后  creatednew Aliplayer({id: "J_prismPlayer",vid: this.vid, // 视频idplayauth: this.playAuth, // 播放凭证encryptType: "1", // 如果播放加密视频,则需设置encryptType=1,非加密视频无需设置此项width: "100%",height: "500px",// 以下可选设置cover: "https://img-blog.csdnimg.cn/e3a9d8d7355f4e3db2407fbdd9fbe7df.png", // 封面qualitySort: "asc", // 清晰度排序mediaType: "video", // 返回音频还是视频autoplay: false, // 自动播放isLive: false, // 直播rePlay: false, // 循环播放preload: true,controlBarVisibility: "hover", // 控制条的显示方式:鼠标悬停useH5Prism: true, // 播放器类型:html5},function (player) {console.log("播放器创建成功");});},
};
</script>


六、课程评论功能

6.1、数据库设计

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');

6.2、远程调用接口

在service-ucenter模块,创建远程调用接口(识别用户信息),根据登录的用户进行发布评论并存储在edu模块的评论表中

1、创建vo存储信息 - com.laptoy.commonutils.vo.UcenterMemberVo

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value = "UcenterMember对象", description = "会员表")
public class UcenterMemberVo 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;
}

2、UcenterMemberController

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

3、edu模块

远程调用接口(自行对应)

@Component
@FeignClient(name = "service-ucenter", fallback = UcenterClientImpl.class)
public interface UcenterClient {@PostMapping("/ucenter/member/getMemberInfoById/{memberId}")UcenterMemberVo getMemberInfoById(@PathVariable String memberId);}

熔断器

@Component
public class UcenterClientImpl implements UcenterClient {@Overridepublic UcenterMemberVo getMemberInfoById(String memberId) {return null;}
}

6.3、后端接口

1、使用代码生成器生成

gc.setOutputDir("D:\\MyCode\\IdeaCode\\project\\gulicollege\\guli_parent\\service\\service_edu" + "/src/main/java"); //输出目录pc.setModuleName("eduservice"); //模块名strategy.setInclude("edu_comment");//根据数据库哪张表生成,有多张表就加逗号继续填写

EduComment填充@TableField注解

@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建时间")
private Date gmtCreate;@TableField(fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新时间")
private Date gmtModified;

2、控制层

@CrossOrigin
@RestController
@RequestMapping("/eduservice/comment")
public class EduCommentController {@Autowiredprivate EduCommentService commentService;//根据课程id_分页查询课程评论的方法@GetMapping("/getCommentPage/{page}/{limit}")public R getCommentPage(@PathVariable Long page, @PathVariable Long limit, String courseId) {Page<EduComment> commentPage = new Page<>(page, limit);Map<String,Object> map = commentService.getCommentPage(commentPage,limit,courseId);return R.ok().data(map);}//添加评论@PostMapping("/auth/addComment")public R addComment(HttpServletRequest request, @RequestBody EduComment eduComment) {commentService.addComment(request,eduComment);return R.ok();}
}

3、业务层

@Service
public class EduCommentServiceImpl extends ServiceImpl<EduCommentMapper, EduComment> implements EduCommentService {@Autowiredprivate UcenterClient ucenterClient;@Overridepublic void addComment(HttpServletRequest request, EduComment eduComment) {String memberId = JwtUtils.getMemberIdByJwtToken(request);//判断用户是否登录if (StringUtils.isEmpty(memberId)) {throw new LaptoyException(20001, "请先登录");}eduComment.setMemberId(memberId);//远程调用ucenter根据用户id获取用户信息UcenterMemberVo memberVo = ucenterClient.getMemberInfoById(memberId);if (memberVo == null) {throw new LaptoyException(20001, "远程调用失败,请检测会员服务");}eduComment.setAvatar(memberVo.getAvatar());eduComment.setNickname(memberVo.getNickname());//保存评论this.save(eduComment);}@Overridepublic Map<String, Object> getCommentPage(Page<EduComment> commentPage, Long limit, String courseId) {QueryWrapper<EduComment> wrapper = new QueryWrapper<>();//判断课程id是否为空if (!StringUtils.isEmpty(courseId)) {wrapper.eq("course_id", courseId);}//按最新排序wrapper.orderByDesc("gmt_create");//数据会被封装到commentPage中this.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 map;}
}

6.4、前端展示

1、comment.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、html - 放在course/_id.vue的下面

<!-- /课程评论 开始 -->
<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 data.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: !data.hasPrevious }" href="#" title="首页" @click.prevent="gotoPage(1)">首</a><a :class="{ undisable: !data.hasPrevious }" href="#" title="前一页" @click.prevent="gotoPage(data.current - 1)">&lt;</a><a v-for="page in data.pages" :key="page" :class="{current: data.current == page,undisable: data.current == page,}" :title="'第' + page + '页'" href="#" @click.prevent="gotoPage(page)">{{ page }}</a><a :class="{ undisable: !data.hasNext }" href="#" title="后一页" @click.prevent="gotoPage(data.current + 1)">&gt;</a><a :class="{ undisable: !data.hasNext }" href="#" title="末页" @click.prevent="gotoPage(data.pages)">末</a><div class="clear" /></div><!-- 公共分页 结束 --></div>
</div>
<!-- /课程评论 结束 -->

3、js

<script>
import courseApi from "@/api/course";
import comment from "@/api/comment";
export default {methods: {// 获取课程详细信息getCourseInfo() {courseApi.getFrontCourseInfo(this.course.courseId).then((resp) => {this.chapterList = resp.data.data.chapterVideoList;this.course = resp.data.data.courseWebVo;this.course.courseId = resp.data.data.courseWebVo.id;});},// 初始化评论initComment() {comment.getPageList(this.page, this.limit, this.course.courseId).then((response) => {this.data = response.data.data;console.log(response.data.data);});},addComment() {this.comment.courseId = this.course.courseId;this.comment.teacherId = this.course.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.data = response.data.data;});},},data() {return {chapterList: [],course: {courseId: "",},data: {},page: 1,limit: 4,total: 10,comment: {content: "",courseId: "",teacherId: "",},isbuyCourse: false,};},created() {this.course.courseId = this.$route.params.id;this.getCourseInfo();this.initComment();},
};
</script>



2022年最新《谷粒学院开发教程》:9 - 前台课程模块相关推荐

  1. 2022年最新《谷粒学院开发教程》:5 - 章节管理

    资料 资料地址 后台管理系统目录 前台展示系统目录 1 - 构建工程篇 7 - 渲染前台篇 2 - 前后交互篇 8 - 前台登录篇 3 - 文件上传篇 9 - 前台课程篇 4 - 课程管理篇 10 - ...

  2. 2022年最新《谷粒学院开发教程》:4 - 课程管理

    资料 资料地址 后台管理系统目录 前台展示系统目录 1 - 构建工程篇 7 - 渲染前台篇 2 - 前后交互篇 8 - 前台登录篇 3 - 文件上传篇 9 - 前台课程篇 4 - 课程管理篇 10 - ...

  3. 2022年最新Java后端开发技术架构总结

    做了十年的Java开发和项目管理,和大家介绍一下我总结的一两年用得比较多的Java框架(包括软件.中间件),以及相关开发.测试.运维.项目管理.技术支持等. 2022年最新Java后端开发技术架构总结 ...

  4. 来自damon的zencart二次开发教程-2.2登录模块分析

    我们在制作zencart的模板时,经常会遇到需要将zencart的登陆页面与注册账户页面分离的情况(在 默认情况下,点击"Login"按钮会进入登陆页面与注册账号页面,登录zenc ...

  5. iPhone开发教程 UI基础课程(58课时)

    qianqianlianmeng iPhone开发教程 UI基础课程(58课时) 第一章   iPhone开发入门 UI基础课程 第一章 iPhone开发入门 1.1 iOS概述和架构         ...

  6. 《『若水新闻』客户端开发教程》——01.课程介绍

    内容介绍 2011年,若水工作室制作了<Android开发从零开始>系列课程,感谢大家的鼓励和支持.为了进一步提高Android开发培训水平,2012年若水工作室又倾心制作的项目实战视频『 ...

  7. 2022年最新《谷粒商城开发教程》:1 - 构建工程篇

    Java工程师的进阶之路 代码地址 2 - vue 简要笔记 3 - 商品服务-API-三级分类 4 - 商品服务-API-品牌管理 5 - 商品服务-API-属性分组 目录 前言 一.项目架构 二. ...

  8. 2022年最新《谷粒商城开发教程》:2 - vue 简要笔记

    Java工程师的进阶之路 代码地址 1 - 构建工程篇 2 - vue 简要笔记 3 - 商品服务-API-三级分类 4 - 商品服务-API-品牌管理 5 - 商品服务-API-属性分组 目录 一. ...

  9. 【作废】Inventor 二次开发学习指南入门到精通(含Inventor最新二次开发教程下载)

    (由于AU中国已关闭,很多链接失效,而且有些内容需要更新.特作废此文,另外撰写一篇新的) 年初我曾撰写了一篇文章,登载到我同事的博客,以及AU中国.我想这篇作为本博客的第一篇正式技术文章,应该是最合适 ...

最新文章

  1. end-to-end 的神经网络
  2. 服务器上安装运行fastqc
  3. Python3 流程控制语句
  4. 格子大法与换入换出分析
  5. ROC和AUC介绍以及如何计算AUC(转载+自己重新排版整理)
  6. oidc_使用Java EE和OIDC构建Java REST API
  7. 玩客云刷armbian后根目录扩展
  8. 常量指针、指针常量以及指向常量的指针常量
  9. php随机访问文章,zblog PHP调用热门文章、随机文章和热评文章代码
  10. xp硬盘上安装ubuntu12.04双系统
  11. python爬虫怎么赚钱-《python爬虫怎么挣钱》 - 微赚接单平台
  12. NI CompactRIO嵌入式系统开发流程总结
  13. 时间管理之-----《暗时间》-刘未鹏
  14. python cryptography key加密_python加密解密库cryptography使用openSSL生成的密匙加密解密...
  15. [URL ]pixiv.net p站用户账号注销网页网址(电脑web版)
  16. 直播带货那么火,测试人员如何对直播类产品的直播质量进行测试呢?
  17. 21世纪将是汉语拼音充分发挥威力的时代
  18. 知识付费小程序源码可开激励广告流量主+虚拟资源变现+附带视频教程
  19. speedoffice(PPT)插入的图片如何自动适合幻灯片页面大小呢?
  20. carla学习笔记(九)

热门文章

  1. JS验证字符串的长度(区分中英文)
  2. 今天大量安卓应用发生闪退,原来是它搞的鬼
  3. stm32快速查阅手册-长期总结
  4. 新享科技签约京微齐力,UniPro全方位助力国产FPGA研发管理
  5. mat格式转换成csv格式
  6. MySQL中关于insert语句速度的优化
  7. 使用LRP(Layer-wise relevance propagation)对模型进行解释
  8. openlayer4中,地图通过extent缩放至范围。
  9. centos安装KDE桌面
  10. 信息安全基础—对称/非对称密码图文详解