1 内容介绍
- 名师列表、详情功能
- 课程列表、详情功能
- 整合阿里云视频播放
- 课程评论功能
2 名师列表功能
1 分页查询名师接口
controller
@RestController
@RequestMapping("/eduservice/teacherfront")
@CrossOrigin
public class TeacherFrontController {
@Autowired
private EduTeacherService teacherService;
// 1. 分页查询讲师
@GetMapping("getTeacherFrontList/{page}/{limit}")
public R getTeacherFrontList(@PathVariable long page, @PathVariable long limit) {
Page<EduTeacher> pageTeacher = new Page<>(page, limit);
Map<String, Object> map = teacherService.getTeacherFrontList(pageTeacher);
// 返回分页所有数据
return R.ok();
}
}
service
public Map<String, Object> getTeacherFrontList(Page<EduTeacher> pageParam) {
QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("id");
baseMapper.selectPage(pageParam, wrapper);
List<EduTeacher> 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
HashMap<String, Object> 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;
}
2 整合前端页面
查看评论p210 解决分页bug
- api创建js文件,定义接口地址
- 页面中引入,调用方法显示
export default {
// 异步调用
// params:相当于之前的 this$route.params.id==params.id
asyncData({ params, error }) {
return teacherApi.getTeacherList(1, 8).then(response => {
console.log(response.data.data)
return { data: response.data.data }
})
},
methods: {
// 分页切换方法
gotoPage(page) {
teacherApi.getTeacherList(page, 8)
.then(response => {
this.data = response.data.data
})
}
}
}
3 讲师详情功能
1 修改讲师列表页面超链接,改成讲师id
:href="'/teacher/'+teacher.id"
2 编写讲师详情接口
-
根据讲师id查询讲师基本信息
-
根据讲师id查询课程
@GetMapping("getTeacherFrontInfo/{teacherId}") public R getTeacherFrontInfo(@PathVariable String teacherId) { // 根据讲师id查询讲师基本信息 EduTeacher eduTeacher = teacherService.getById(teacherId); // 根据讲师id查询课程 QueryWrapper<EduCourse> wrapper = new QueryWrapper<>(); wrapper.eq("teacher_id", teacherId); List<EduCourse> courseList = courseService.list(wrapper); return R.ok().data("teacher", eduTeacher).data("courseList", courseList); }
3 前端页面调用
teacher/_id.vue
asyncData({ params, error }) {
// params.id获取路由中的id值
return teacherApi.getTeacherInfo(params.id)
.then(response => {
return {
teacher: response.data.data.teacher,
courseList: response.data.data.courseList
}
})
}
4 课程条件查询带分页
1 创建vo对象,实现
@ApiModel(value = "课程查询对象", description = "课程查询对象封装")
@Data
public class CourseFrontVo {
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 编写controller、service
controller
@PostMapping("getCourseFrontList/{page}/{limit}")
public R getCourseFrontList(@PathVariable long page, @PathVariable long limit,
@RequestBody(required = false)CourseFrontVo courseFrontVo) {
Page<EduCourse> pageCourse = new Page<>(page, limit);
Map<String, Object> map = courseService.getCourseFrontList(pageCourse, courseFrontVo);
// 返回分页所有数据
return R.ok().data(map);
}
service
public Map<String, Object> getCourseFrontList(Page<EduCourse> pageParam, CourseFrontVo courseFrontVo) {
QueryWrapper<EduCourse> 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.getSubjectParentId());
}
if (!StringUtils.isEmpty(courseFrontVo.getBuyCountSort())) { // 关注度
wrapper.orderByDesc("buy_count", courseFrontVo.getSubjectParentId());
}
if (!StringUtils.isEmpty(courseFrontVo.getGmtCreateSort())) { // 最新
wrapper.orderByDesc("gmt_create", courseFrontVo.getSubjectParentId());
}
if (!StringUtils.isEmpty(courseFrontVo.getPriceSort())) { // 价格
wrapper.orderByDesc("price", courseFrontVo.getSubjectParentId());
}
baseMapper.selectPage(pageParam, wrapper);
List<EduCourse> 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
HashMap<String, Object> 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;
}
3 前端整合
-
api/course.js中引入接口地址
// 条件查询带分页:课程列表 getCourseList(page, limit, searchObj) { return request({ url: `/eduservice/coursefront/getCourseFrontList/${page}/${limit}`, method: 'post', data: searchObj }) }, // 查询所有分类 getAllSubject() { return request({ url: `/eduservice/subject/getAllSubject`, method: 'get' }) }
-
在页面中调用
显示所有一级分类,点击某个一级分类,显示其对应的二级分类
// 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 < this.subjectNestedList.length; i++) { // 获取每个一级分类 const oneSubject = this.subjectNestedList[i] // 比较id是否相同 if (subjectParentId === oneSubject.id) { // 从一级分类里面获取对应的二级分类 this.subSubjectList = oneSubject.children } } }, // 5 点击某个二级分类实现查询 searchTwo(subjectId, index) { // index赋值 this.twoIndex = index this.searchObj.subjectId = subjectId this.gotoPage(1) }, // 6 根据销量排序 searchBuyCount() { // 设置对应变量值,为了样式生效 this.buyCountSort = '1' this.gmtCreateSort = '' this.priceSort = '' // 赋值 this.searchObj.buyCount = this.buyCountSort this.searchObj.gmtCreateSort = this.gmtCreateSort this.searchObj.priceSort = this.priceSort // 调用方法查询 this.gotoPage(1) },
5 课程详细接口
1 编写sql语句,根据课程id查询课程信息
课程基本信息、课程分类、课程描述、所属讲师
<!-- 2 根据课程id查询课程信息 -->
<select id="getBaseCourseInfo" resultType="com.mys.eduservice.entity.frontvo.CourseWebVo">
select ec.id,ec.title,ec.price,ec.lesson_num AS lessonNum,ec.cover,
ec.buy_count As buyCount,ec.view_count AS viewCount,
ecd.description,
et.id as teacherId,et.name as teacherName,et.intro,et.avatar,
es1.title as subjectLevelOne,
es2.title AS subjectLevelTwo
from edu_course ec LEFT OUTER JOIN edu_course_description ecd ON ec.id=ecd.id
LEFT OUTER JOIN edu_teacher et ON ec.teacher_id=et.id
LEFT OUTER JOIN edu_subject es1 ON ec.subject_parent_id=es1.id
LEFT OUTER JOIN edu_subject es2 ON ec.subject_id=es2.id
WHERE ec.id=#{courseId}
</select>
2 根据课程id查询章节、小节
// 2. 课程详情
@GetMapping("getFrontCourseInfo/{courseId}")
public R getFrontCourseInfo(@PathVariable 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);
}
6 整合前端视频播放
1 创建接口,根据视频id获取视频凭证
// 根据视频id获取视频凭证
@GetMapping("getPlayAuth/{id}")
public R getPlayAuth(@PathVariable String id) {
try {
// 创建初始化对象
DefaultAcsClient client = InitVodClient.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, "获取凭证失败");
}
}
2 点击某个小节,打开新的页面进行视频播放
修改超链接地址:<a :href="'/player/'+video.videoSourceId">
在pages创建文件夹和文件,使用动态路由的方式 /player/_vid.vue
细节:添加属性 com.mys.eduservice.entity.chapter.VideoVo
private String videoSourceId; // 视频id
player/_vid.vue
asyncData({ params, error }) {
return vod.getPlayAuth(params.vid)
.then(response => {
return {
playAuth: response.data.data.playAuth,
vid: params.vid
}
})
},
mounted() { // 页面渲染之后 created
// eslint-disable-next-line no-undef
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('播放器创建成功')
})
}