在线教育-谷粒学院学习笔记(六)

文章目录

    • 1 内容介绍
    • 2 课程大纲列表后端实现
    • 3 课程大纲列表前端实现
    • 4 修改课程基本信息
    • 5 课程章节操作
    • 6 课程小节操作
    • 7 课程信息确认
    • 8 课程最终发布

1 内容介绍

  • 课程大纲管理
    • 课程大纲列表显示
    • 章节、小节的添加、修改、删除
  • 课程信息确认
    • 编写sql语句实现
    • 课程最终发布

2 课程大纲列表后端实现

参考课程分类列表

1 创建实体类

创建章节、小节两个实体类,在章节实体类中使用list表示小节

@Data
public class VideoVo {
    private String id;
    private String title;
}
@Data
public class ChapterVo {
    private String id;
    private String title;
    // 章节包含很多小节
    private List<VideoVo> children = new ArrayList<>();
}

2 controller和service

controller

@RestController
@RequestMapping("/eduservice/chapter")
@CrossOrigin
public class EduChapterController {
    @Autowired
    private EduChapterService chapterService;
    // 课程大纲列表,根据课程id查章节、小节
    @GetMapping("getChapterVideo/{courseId}")
    public R getChapterVideo(@PathVariable String courseId) {
        List<ChapterVo> list = chapterService.getChapterVideoByCourseId(courseId);
        return R.ok().data("allChapterVideo", list);
    }
}

service

@Service
public class EduChapterServiceImpl extends ServiceImpl<EduChapterMapper, EduChapter> implements EduChapterService {

    @Autowired
    private EduVideoService videoService; // 注入小节的service
    // 课程大纲列表,根据课程id查章节、小节
    @Override
    public List<ChapterVo> getChapterVideoByCourseId(String courseId) {
        // 1.根据课程id查询课程里面所有的章节
        QueryWrapper<EduChapter> wrapperChapter = new QueryWrapper<>();
        wrapperChapter.eq("course_id", courseId);
        List<EduChapter> eduChapterList = baseMapper.selectList(wrapperChapter);
        // 2.根据课程id查询课程里面所有的小节
        QueryWrapper<EduVideo> wrapperVideo = new QueryWrapper<>();
        wrapperVideo.eq("course_id", courseId);
        List<EduVideo> eduVideoList = videoService.list(wrapperVideo);
        // 创建list集合,用于最终的数据封装 ChapterVo
        List<ChapterVo> finalList = new ArrayList<>();
        // 3.遍历查询章节list集合,进行封装
        for (EduChapter eduChapter: eduChapterList) {
            ChapterVo chapterVo = new ChapterVo();
            BeanUtils.copyProperties(eduChapter, chapterVo);
            finalList.add(chapterVo);
            // 创建list集合,用于封装章节中的小节VideoVo
            List<VideoVo> videoList = new ArrayList<>();
            // 4.遍历查询小节list集合,进行封装
            for (EduVideo eduVideo : eduVideoList) {
                // 判断小节的chapter_id与章节的id是否一样
                if (eduVideo.getChapterId().equals(eduChapter.getId())) {
                    VideoVo videoVo = new VideoVo();
                    BeanUtils.copyProperties(eduVideo, videoVo);
                    videoList.add(videoVo);
                }
            }
            // 小节list放到章节中
            chapterVo.setChildren(videoList);
        }
        return finalList;
    }
}

3 课程大纲列表前端实现

1 api/edu/chapter.js

import request from '@/utils/request'

export default {
  // 根据课程id获取章节、小节列表
  getAllChapterVideo(courseId) {
    return request({
      url: `/eduservice/chapter/getChapterVideo/${courseId}`,
      method: 'get'
    })
  }
}

2 chapter.vue


  • {{ chapter.title }}
    • {{ video.title }}
created() {
  // 获取路由的id值
  if (this.$route.params && this.$route.params.id) {
    this.courseId = this.$route.params.id
  }
  // 根据课程id查询章节和小节
  this.getChapterVideo()
},
methods: {
  // 根据课程id查询章节、小节列表
  getChapterVideo() {
    chapter.getAllChapterVideo(this.courseId)
      .then(response => {
        this.chapterVideoList = response.data.allChapterVideo
      })
  },

4 修改课程基本信息

  • 点击上一步,回到上一步,并做课程基本信息数据回显

  • 数据回显页面,修改数据库内容

1 后端接口

  • 根据课程id,查询课程基本信息接口
  • 修改课程信息接口

controller

// 根据课程id查询课程基本信息
@GetMapping("getCourseInfo/{courseId}")
public R getCourseInfo(@PathVariable String courseId) {
    CourseInfoVo courseInfoVo = courseService.getCourseInfo(courseId);
    return R.ok().data("courseInfoVo", courseInfoVo);
}

// 修改课程信息
@PostMapping("updateCourseInfo")
public R updateCourseInfo(@RequestBody CourseInfoVo courseInfoVo) {
    courseService.updateCourseInfo(courseInfoVo);
    return R.ok();
}

service

// 根据课程id查询课程基本信息
@Override
public CourseInfoVo getCourseInfo(String courseId) {
    // 1 查询课程表
    EduCourse eduCourse = baseMapper.selectById(courseId);
    CourseInfoVo courseInfoVo = new CourseInfoVo();
    BeanUtils.copyProperties(eduCourse, courseInfoVo);
    // 2 查询描述表
    EduCourseDescription courseDescription = courseDescriptionService.getById(courseId);
    courseInfoVo.setDescription(courseDescription.getDescription());
    return courseInfoVo;
}

// 修改课程信息
@Override
public void updateCourseInfo(CourseInfoVo courseInfoVo) {
    // 1 修改课程表
    EduCourse eduCourse = new EduCourse();
    BeanUtils.copyProperties(courseInfoVo, eduCourse);
    int update = baseMapper.updateById(eduCourse);
    if (update == 0) {
        throw new GuliException(20001, "修改课程信息失败");
    }
    // 2 修改描述表
    EduCourseDescription description = new EduCourseDescription();
    BeanUtils.copyProperties(courseInfoVo, description);
    courseDescriptionService.updateById(description);
}

2 前端实现

  • 定义接口的两个方法:api/edu/course.js

    // 3 根据课程id查询课程基本信息
    getCourseInfo(id) {
      return request({
        url: `/eduservice/course/getCourseInfo/${id}`,
        method: 'get'
      })
    },
    // 4 修改课程信息
    updateCourseInfo(courseInfoVo) {
      return request({
        url: '/eduservice/course/updateCourseInfo',
        method: 'post',
        data: courseInfoVo
      })
    }
    
  • 修改chapter.vue,跳转页面

    // 上一步
    previous() {
      this.$router.push({ path: '/course/info/' + this.courseId })
    },
    // 下一步
    next() {
      this.$router.push({ path: '/course/publish/' + this.courseId })
    }
    
  • 在info页面实现数据回显

    • 获取路由的课程id,调用根据id查询接口,数据显示
    // 获取路由id值
    if (this.$route.params && this.$route.params.id) {
      this.courseId = this.$route.params.id
      // 调用根据课程id查询
      this.getInfo()
    }
    
    // 7 根据课程id查询
    getInfo() {
      course.getCourseInfo(this.courseId)
        .then(response => {
          this.courseInfo = response.data.courseInfoVo
        })
    }
    
  • 下拉列表数据回显

    • 根据存储id和分类所有id进行比较,如果比较相同,让相同值进行数据回显

      
      <select>
      	<option selected>前端开发option>
      <select>
      
      created() {
        // 修改
        if (this.$route.params && this.$route.params.id) { // 获取路由id值
          this.courseId = this.$route.params.id
          // 调用根据课程id查询
          this.getInfo()
        } else { // 添加
          // 初始化所有讲师
          this.getListTeacher()
          // 初始化一级分类
          this.getOneSubject()
        }
      },
      
      // 7 根据课程id查询
      getInfo() {
        course.getCourseInfo(this.courseId)
          .then(response => {
            // courseInfo包含一级分类id和二级分类id
            this.courseInfo = response.data.courseInfoVo
            // 1)查询所有的分类,包含一级和二级
            subject.getSubjectList()
              .then(response => {
                // 2)获取所有一级分类
                this.subjectOneList = response.data.list
                // 3)遍历一级分类,获取二级分类
                for (const oneSubject of this.subjectOneList) {
                  if (this.courseInfo.subjectParentId === oneSubject.id) { // 当前一级分类id和所有一级分类id比较
                    this.subjectTwoList = oneSubject.children
                  }
                }
              })
            // 初始化所有讲师
            this.getListTeacher()
          })
      }
      
  • 添加、修改并保存

    // 添加课程
    addCourse() {
      course.addCourseInfo(this.courseInfo)
        .then(response => {
          // 提示信息
          this.$message({
            type: 'success',
            message: '添加课程信息成功'
          })
          // 跳转到下一步
          this.$router.push({ path: '/course/chapter/' + response.data.courseId })
        })
    },
    // 修改课程
    updateCourse() {
      course.updateCourseInfo(this.courseInfo)
        .then(response => {
          // 提示信息
          this.$message({
            type: 'success',
            message: '修改课程信息成功'
          })
          // 跳转到下一步
          this.$router.push({ path: '/course/chapter/' + this.courseId })
        })
    },
    // 6 保存
    saveOrUpdate() {
      // 判断添加还是修改
      // 没有id值,添加
      if (!this.courseInfo.id) {
        this.addCourse()
      } else {
        // 有id值,修改
        this.updateCourse()
      }
    },
    

5 课程章节操作

添加、修改、删除

1 添加按钮:添加章节

添加章节

2 点击 添加章节 按钮,弹出添加框,输入章节信息,点击保存添加



  
    
      
    
    
      
    
  
  

3 开发章节后端接口

  • 修改章节

  • 添加章节

  • 删除章节

    • 如果章节里面没有小节,直接删除
    • 如果章节里面有小节
      • 第一种:删除章节的时候,把里面的所有小节都删除
      • 第二种:不让其删除(√)

controller

// 添加章节
@PostMapping("addChapter")
public R addChapter(@RequestBody EduChapter eduChapter) {
    chapterService.save(eduChapter);
    return R.ok();
}

// 根据章节id查询
@GetMapping("getChapterInfo/{chapterId}")
public R getChapterInfo(@PathVariable String chapterId) {
    EduChapter eduChapter = chapterService.getById(chapterId);
    return R.ok().data("chapter", eduChapter);
}

// 修改章节
@PostMapping("updateChapter")
public R updateChapter(@RequestBody EduChapter eduChapter) {
    chapterService.updateById(eduChapter);
    return R.ok();
}

// 删除章节
@DeleteMapping("{chapterId}")
public R deleteChapter(@PathVariable String chapterId) {
    boolean flag = chapterService.deleteChapter(chapterId);
    return flag ? R.ok() : R.error();
}

service

// 删除章节
@Override
public boolean deleteChapter(String chapterId) {
    // 根据章节id查询小节表,如果能查到数据,不删除
    QueryWrapper<EduVideo> wrapper = new QueryWrapper<>();
    wrapper.eq("chapter_id", chapterId);
    int count = videoService.count(wrapper);
    if (count > 0) { // 有小节,不删除
        throw new GuliException(20001, "不能删除");
    } else { // 没有小节,删除
        int result = baseMapper.deleteById(chapterId);
        return result > 0;
    }
}

4 前端调用接口

chapter.js

// 添加章节
addChapter(chapter) {
  return request({
    url: `/eduservice/chapter/addChapter`,
    method: 'post',
    data: chapter
  })
},
// 根据id查询章节
getChapter(chapterId) {
  return request({
    url: `/eduservice/chapter/getChapterInfo/${chapterId}`,
    method: 'get'
  })
},
// 修改章节
updateChapter(chapter) {
  return request({
    url: `/eduservice/chapter/updateChapter`,
    method: 'post',
    data: chapter
  })
},
// 删除章节
deleteChapter(chapterId) {
  return request({
    url: `/eduservice/chapter/${chapterId}`,
    method: 'delete'
  })
}

chapter.vue

  • {{ chapter.title }} 编辑 删除

// 添加章节
addChapter() {
  // 设置课程id到chapter对象中
  this.chapter.courseId = this.courseId
  chapter.addChapter(this.chapter)
    .then(response => {
      // 1) 关闭弹窗
      this.dialogChapterFormVisible = false
      // 2) 提示信息
      this.$message({
        type: 'success',
        message: '添加章节成功'
      })
      // 3) 刷新页面
      this.getChapterVideo()
    })
},
// 修改章节
updateChapter() {
  chapter.updateChapter(this.chapter)
    .then(response => {
      // 1) 关闭弹窗
      this.dialogChapterFormVisible = false
      // 2) 提示信息
      this.$message({
        type: 'success',
        message: '修改章节成功'
      })
      // 3) 刷新页面
      this.getChapterVideo()
    })
},
// 保存
saveOrUpdate() {
  if (!this.chapter.id) {
    this.addChapter()
  } else {
    this.updateChapter()
  }
},
// 删除章节
removeChapter(chapterId) {
  // 1)弹出确认框
  this.$confirm('此操作将删除章节, 是否继续?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => { // 点击确认,执行then方法
    chapter.deleteChapter(chapterId)
      .then((response) => {
        // 提示信息
        this.$message({
          type: 'success',
          message: '删除成功!'
        })
        // 2) 刷新页面
        this.getChapterVideo()
      })
  })
},
// 修改章节弹框数据回显
openEditChapter(chapterId) {
  // 弹框
  this.dialogChapterFormVisible = true
  // 调用接口
  chapter.getChapter(chapterId)
    .then(response => {
      this.chapter = response.data.chapter
    })
}

6 课程小节操作

7 课程信息确认

1 概述

封面、课程名称、课程价格、课程分类、课程简介、课程讲师…

这些数据需要查询多张表,一般通过手写sql实现

多表连接查询:内连接、左外连接、右外连接

select ec.id,ec.title,ec.price,ec.lesson_num,
ecd.description,
et.`name`,
es1.title as oneSubject,
es2.title AS twoSubject
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='1555079243711434754'

2 controller、service、mapper

controller

// 根据课程id查询课程确认信息
@GetMapping("getPublishCourseInfo/{id}")
public R getPublishCourseInfo(@PathVariable String id) {
    CoursePublishVo coursePublishVo = courseService.publishCourseInfo(id);
    return R.ok().data("publishCourse", coursePublishVo);
}

service

@Override
public CoursePublishVo publishCourseInfo(String id) {
    CoursePublishVo publishCourseInfo = baseMapper.getPublishCourseInfo(id);
    return publishCourseInfo;
}

mapper

public interface EduCourseMapper extends BaseMapper<EduCourse> {

    public CoursePublishVo getPublishCourseInfo(String courseId);

}

<select id="getPublishCourseInfo" resultType="com.mys.eduservice.entity.vo.CoursePublishVo">
    select ec.id,ec.title,ec.price,ec.lesson_num AS lessonNum,ec.cover,
           ecd.description,
           et.`name` as teacherName,
           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>

3 测试报错与解决

问题:项目中创建mapper接口,编写xml文件写sql语句,执行出错:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.mys.eduservice.mapper.EduCourseMapper.getPublishCourseInfo

错误原因:由maven默认加载机制造成的,maven加载时,把java文件夹里面.java文件进行编译,其他类型文件不会加载

解决办法:

  • 复制xml到target目录

  • 把xml文件放到resources目录

  • 推荐:通过配置实现

    • pom.xml

      <build>
          <resources>
              <resource>
                  <directory>src/main/javadirectory>
                  <includes>
                      <include>**/*.xmlinclude>
                  includes>
                  <filtering>falsefiltering>
              resource>
          resources>
      build>
      
    • application.properties

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

4 前端实现:显示查询的课程确认信息

api/edu/course.js

// 5 课程确认信息的显示
getPublishCourseInfo(id) {
  return request({
    url: `/eduservice/course/getPublishCourseInfo/${id}`,
    method: 'get'
  })
}

publish.vue

created() {
  // 1 获取路由课程id
  if (this.$route.params && this.$route.params.id) {
    this.courseId = this.$route.params.id
    // 2 调用接口方法,根据课程id查询
    this.getPublishCourseId()
  }
},
// 根据课程id查询确认发布信息
getPublishCourseId() {
  course.getPublishCourseInfo(this.courseId)
    .then(response => {
      this.publishCourse = response.data.publishCourse
      // 提示信息
      this.$message({
        type: 'success',
        message: '查询课程发布确认信息成功'
      })
    })
}

8 课程最终发布

修改课程的status状态是Normal-已发布

controller

// 课程最终发布:修改课程状态
@PostMapping("publishCourse/{id}")
public R publishCourse(@PathVariable String id) {
    EduCourse eduCourse = new EduCourse();
    eduCourse.setId(id);
    eduCourse.setStatus("Normal");
    courseService.updateById(eduCourse);
    return R.ok();
}

publish.vue

// 发布
publish() {
  // 调用发布方法
  course.publishCourse(this.courseId)
    .then(response => {
      // 提示信息
      this.$message({
        type: 'success',
        message: '发布成功'
      })
      // 跳转到课程列表
      this.$router.push({ path: '/course/list' })
    })
},

你可能感兴趣的:(在线教育,学习,java,spring)