此时已经完成第一个功能:填写课程基本信息,开始做第二个:创建课程大纲。
因为这一部分需要对Video做读取,所以需要创建Video的mapper service xml impl,全部先为空。
@Mapper
public interface VideoMapper extends BaseMapper<Video> {
}
public interface VideoService extends IService<Video> {
}
@Service
public class VideoServiceImpl extends ServiceImpl<VideoMapper, Video> implements VideoService {
}
实现课程章节的列表,增删改查功能
起手创建mapper和xml
@Mapper
public interface ChapterMapper extends BaseMapper<Chapter> {
}
创建service接口并且声明方法
public interface ChapterService extends IService<Chapter> {
//章节小结列表
List<ChapterVo> getNestedTreeList(Long courseId);
}
impl实现方法
@Service
public class ChapterServiceUImpl extends ServiceImpl<ChapterMapper, Chapter> implements ChapterService {
@Autowired
private ChapterMapper chapterMapper;
@Autowired
private VideoService videoService;
//章节小结列表封装
@Override
public List<ChapterVo> getNestedTreeList(Long courseId) {
List<ChapterVo> chapterVos = new ArrayList<>();
//获取章信息
LambdaQueryWrapper<Video> queryWrapperVideo = new LambdaQueryWrapper<>();
queryWrapperVideo.eq(Video::getCourseId,courseId);
//按照sort排序 sort一样的按照id排
queryWrapperVideo.orderByAsc(Video::getSort,Video::getId);
//将查询出的章节作为list合集
List<Chapter> chapters = chapterMapper.selectList(queryWrapperVideo);
//获取课时信息 要从Video表里查 故声明其service
LambdaQueryWrapper<Video> videoLambdaQueryWrapper = new LambdaQueryWrapper<>();
videoLambdaQueryWrapper.eq(Video::getCourseId,courseId);
videoLambdaQueryWrapper.orderByAsc(Video::getSort,Video::getId);
List<Video> videoList = videoService.list(videoLambdaQueryWrapper);
//填充Vo的数据 因为返回的是vo
for(int i=0;i<chapters.size();i++){
//首先取出里面的每个章节
Chapter chapter = chapters.get(i);
//创建一个vo对象 并加入要返回的list
ChapterVo chapterVo = new ChapterVo();
BeanUtils.copyProperties(chapter,chapterVo);
chapterVos.add(chapterVo);
//填充列表数据:video列表 一个章节含有多个视频
List<VideoVo> videoVoList = new ArrayList<>();
for(int j=0;j<videoList.size();j++){
Video video = videoList.get(j);
//emmm 对里面所有video进行判断 如果是这个章节的就进行操作...好弱智的逻辑
if(chapter.getId().equals(video.getChapterId())){
VideoVo videoVo = new VideoVo();
BeanUtils.copyProperties(video,videoVo);
videoVoList.add(videoVo);
}
}
//章节下的课时列表
chapterVo.setChildren(videoList);
}
return chapterVos;
}
}
编写章节controller,注意其增删改都可以直接调API实现,查询的时候因为要查列表展示到前端所以要自己写。
@RestController
@RequestMapping(value = "/admin/vod/chapter")
@CrossOrigin
public class ChapterController {
@Autowired
private ChapterService chapterService;
//获取章节小结列表
@ApiOperation("嵌套章节数据列表")
@GetMapping("getNestedTreeList/{courseId}")
public Result getNestedTreeList(
@ApiParam(value = "课程ID",required = true)
@PathVariable Long courseId) {
List<ChapterVo> nestedTreeList = chapterService.getNestedTreeList(courseId);
return Result.ok(nestedTreeList);
}
//添加章节
@PostMapping("save")
public Result save(@RequestBody Chapter chapter){
chapterService.save(chapter);
return Result.ok(null);
}
//修改-根据id查询
@GetMapping("get/{id}")
public Result get(@PathVariable Long id){
Chapter chapter = chapterService.getById(id);
return Result.ok(chapter);
}
//修改-实现查询
@PostMapping("update")
public Result update(@RequestBody Chapter chapter){
chapterService.updateById(chapter);
return Result.ok(null);
}
//删除章节
@DeleteMapping("remove/{id}")
public Result remove(@PathVariable Long id){
chapterService.removeById(id);
return Result.ok(null);
}
}
因为小节指的就是视频了,所以编写的为VideoController。
@Api(tags = "课程小结(课时)")
@RestController
@RequestMapping(value = "/admin/vod/video")
@CrossOrigin
public class VideoController {
@Autowired
private VideoService videoService;
//获取视频
@ApiOperation(value = "获取")
@GetMapping("get/{id}")
public Result get(@PathVariable Long id){
Video video = videoService.getById(id);
return Result.ok(video);
}
//新增视频
@ApiOperation(value = "新增")
@PostMapping("save")
public Result save(@RequestBody Video video){
videoService.save(video);
return Result.ok(null);
}
//修改视频
@ApiOperation(value = "修改")
@PutMapping("update")
public Result updateById(@RequestBody Video video) {
videoService.updateById(video);
return Result.ok(null);
}
//删除视频
@ApiOperation(value = "删除")
@DeleteMapping("remove/{id}")
public Result remove(@PathVariable Long id) {
videoService.removeById(id);
return Result.ok(null);
}
}
定义和后端交互的接口,首先定义chapter.js
import request from '@/utils/request'
const api_name = '/admin/vod/chapter'
export default {
getNestedTreeList(courseId) {
return request({
url: `${api_name}/getNestedTreeList/${courseId}`,
method: 'get'
})
},
removeById(id) {
return request({
url: `${api_name}/remove/${id}`,
method: 'delete'
})
},
save(chapter) {
return request({
url: `${api_name}/save`,
method: 'post',
data: chapter
})
},
getById(id) {
return request({
url: `${api_name}/get/${id}`,
method: 'get'
})
},
updateById(chapter) {
return request({
url: `${api_name}/update`,
method: 'put',
data: chapter
})
}
}
然后创建video.js
import request from '@/utils/request'
const api_name = '/admin/vod/video'
export default {
save(video) {
return request({
url: `${api_name}/save`,
method: 'post',
data: video
})
},
getById(id) {
return request({
url: `${api_name}/get/${id}`,
method: 'get'
})
},
updateById(video) {
return request({
url: `${api_name}/update`,
method: 'put',
data: video
})
},
removeById(id) {
return request({
url: `${api_name}/remove/${id}`,
method: 'delete'
})
}
}
然后编写章节的页面,在views/vod/course/components/Chapter/下填充index.vue组件和Form.vue组件,然后在同级的Video下添加Form.vue组件
代码实在太多了,还都是前端,懒得看了,也不放上来了。

编写CouseMapper
@Mapper
public interface CourseMapper extends BaseMapper<Course> {
//根据id获取课程发布信息
CoursePublishVo selectCoursePublishVoById(Long id);
}
这么久,第一次碰到xml文件可以写…感动。
subject_id是一级分类 subject_parent_id是二级分类
#{id}是方法传过来的id
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="vod.mapper.CourseMapper">
<select id="selectCoursePublishVoById" resultType="vo.vod.CoursePublishVo">
SELECT
c.id,
c.title,
c.cover,
c.lesson_num AS lessonNum,
c.price,
t.name AS teacherName,
s1.title AS subjectParentTitle,
s2.title AS subjectTitle
FROM course c
LEFT OUTER JOIN teacher t ON c.teacher_id=t.id
LEFT OUTER JOIN `subject` s1 ON c.subject_parent_id=s1.id
LEFT OUTER JOIN `subject` s2 ON c.subject_id=s2.id
WHERE c.id=#{id}
select>
mapper>
在Service里添加方法
//根据ID获取课程发布信息
CoursePublishVo getCoursePublishVo(Long id);
//根据ID发布课程
boolean publishCourseById(Long id);
在impl里实现这两个方法,很奇怪,其实新增的方法之前不是写过了吗…研究了一下,应该是补全了一下其他的字段…因为最后用的是update
//根据id获取课程发布信息
@Override
public CoursePublishVo getCoursePublishVo(Long id) {
return courseMapper.selectCoursePublishVoById(id);
}
//根据id发布课程
@Override
public boolean publishCourseById(Long id) {
Course course = new Course();
course.setId(id);
course.setPublishTime(new Date());
course.setStatus(1);
return this.updateById(course);
}
@ApiOperation("根据id获取课程发布信息")
@GetMapping("getCoursePublishVo/{id}")
public Result getCoursePublishVoById(
@ApiParam(value = "课程ID", required = true)
@PathVariable Long id){
CoursePublishVo coursePublishVo = courseService.getCoursePublishVo(id);
return Result.ok(coursePublishVo);
}
@ApiOperation("根据id发布课程")
@PutMapping("publishCourseById/{id}")
public Result publishCourseById(
@ApiParam(value = "课程ID", required = true)
@PathVariable Long id){
boolean result = courseService.publishCourseById(id);
return Result.ok(null);
}
原本mapper写在resource外面的话需要添加配置,但我这边半天不成功,直接把mapper移到resource里面就一劳永逸了。

首先在api的course.js里定义接口
//获取发布课程信息
getCoursePublishById(id) {
return request({
url: `${api_name}/getCoursePublishVo/${id}`,
method: 'get'
})
},
//发布课程
publishCourseById(id) {
return request({
url: `${api_name}/publishCourseById/${id}`,
method: 'put'
})
},
再编写view/vod/course/components/Publish.vue,直接开抄,懒得看了。


点完发布后咋跳404了,去改一下,跳回原来的数据列表。
将Publish.vue的这里的路由修改成/course/list路由

为了做前面的测试添加了好多课程,现在都删了吧。
需要删除的东西有很多:小节(video) 章节(chapter)章节描述(description)课程(Course)
//根据课程id删除章节
@Override
public void removeChapterByCourseId(Long id){
QueryWrapper<Chapter> wrapper = new QueryWrapper<>();
wrapper.eq("course_id",id);
chapterMapper.delete(wrapper);
}
@Override
public void removeVideoByCourseId(Long id) {
QueryWrapper<Video> wrapper = new QueryWrapper<>();
wrapper.eq("course_id",id);
baseMapper.delete(wrapper);
}
@Autowired
private VideoService videoService;
@Autowired
private ChapterService chapterService;
@Autowired
private CourseDescriptionService courseDescriptionService;
@Override
public void removeCourseById(Long id) {
//根据课程id删除小节
videoService.removeVideoByCourseId(id);
//根据课程id删除章节
chapterService.removeChapterByCourseId(id);
//根据课程id删除描述
courseDescriptionService.removeById(id);
//根据课程id删除课程
courseMapper.deleteById(id);
}
@ApiOperation(value = "删除课程")
@DeleteMapping("remove/{id}")
public Result remove(@PathVariable Long id){
courseService.removeCourseById(id);
return Result.ok(null);
}
在course.js里定义接口
removeById(id) {
return request({
url: `${api_name}/remove/${id}`,
method: 'delete'
})
},
在course里的list.vue里添加方法
// 根据id删除数据
removeById(id) {
this.$confirm('此操作将永久删除该课程,以及该课程下的章节和视频,是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return courseApi.removeById(id)
}).then(response => {
this.fetchData()
this.$message.success(response.message)
}).catch((response) => { // 失败
if (response === 'cancel') {
this.$message.info('取消删除')
}
})
}