SSM 单体框架 - 教育平台后台管理系统:课程模块

时间:2022-07-25
本文章向大家介绍SSM 单体框架 - 教育平台后台管理系统:课程模块,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

课程模块

课程模块功能分析

课程模块包含了多条件查询、 图片上传、 新建&修改课程、课程状态管理、课程内容展示、回显章节对应的课程信息、新建&修改章节信息、修改章节状态、 新建&修改课时信息等接口的编写。

课程管理

实现以下功能:

  • 多条件查询
  • 图片上传
  • 新建课程信息
  • 回显课程信息
  • 修改课程信息
  • 课程状态管理
  • 课程内容展示
  • 回显章节对应的课程信息
  • 新建&修改章节信息
  • 修改章节状态
  • 新建课时信息

课程模块表设计

创建数据库及表

数据库

  • ssm_lagou_edu

  • course 课程表
  • course_lesson 课时表
  • course_media 课程媒体表
  • course_section 章节表
  • menu
  • promotion_ad
  • promotion_space
  • resource
  • resource_category
  • role_menu_relation
  • role_resource_relation
  • roles
  • teacher
  • user
  • user_phone_verification
  • user_role_relation
  • user_weixin
表关系介绍
ER 图

一个课程表对多个章节表

一个章节表对多个课时表

一个课时表对一个课程媒体表

数据实体描述

课程表

CREATE TABLE `course` (
  `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'id',
  `course_name` VARCHAR(255) DEFAULT NULL COMMENT '课程名',
  `brief` VARCHAR(255) DEFAULT '' COMMENT '课程一句话简介',
  `price` DOUBLE(10,2) DEFAULT NULL COMMENT '原价',
  `price_tag` VARCHAR(255) DEFAULT '' COMMENT '原价标签',
  `discounts` DOUBLE(10,2) DEFAULT NULL COMMENT '优惠价',
  `discounts_tag` VARCHAR(255) DEFAULT NULL COMMENT '优惠标签',
  `course_description_mark_down` LONGTEXT COMMENT '描述markdown',
  `course_description` LONGTEXT COMMENT '课程描述',
  `course_img_url` VARCHAR(255) DEFAULT NULL COMMENT '课程分享图片url',
  `is_new` TINYINT(1) DEFAULT NULL COMMENT '是否新品',
  `is_new_des` VARCHAR(255) DEFAULT NULL COMMENT '广告语',
  `last_operator_id` INT(11) DEFAULT NULL COMMENT '最后操作者',
  `auto_online_time` DATETIME DEFAULT NULL COMMENT '自动上架时间',
  `create_time` DATETIME NOT NULL COMMENT '记录创建时间',
  `update_time` DATETIME NOT NULL COMMENT '更新时间',
  `is_del` TINYINT(1) DEFAULT '0' COMMENT '是否删除',
  `total_duration` INT(11) DEFAULT NULL COMMENT '总时长(分钟)',
  `course_list_img` VARCHAR(255) DEFAULT NULL COMMENT '课程列表展示图片',
  `status` INT(2) DEFAULT '0' COMMENT '课程状态,0-草稿,1-上架',
  `sort_num` INT(11) DEFAULT NULL COMMENT '课程排序,用于后台保存草稿时用到',
  `preview_first_field` VARCHAR(255) DEFAULT NULL COMMENT '课程预览第一个字段',
  `preview_second_field` VARCHAR(255) DEFAULT NULL COMMENT '课程预览第二个字段',
  `sales` INT(11) DEFAULT '0' COMMENT '销量',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=INNODB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8;

章节表

CREATE TABLE `course_section` (
  `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'id',
  `course_id` INT(11) DEFAULT NULL COMMENT '课程id',
  `section_name` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '章节名',
  `description` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '章节描述',
  `create_time` DATETIME NOT NULL COMMENT '记录创建时间',
  `update_time` DATETIME NOT NULL COMMENT '更新时间',
  `is_de` TINYINT(1) DEFAULT '0' COMMENT '是否删除',
  `order_num` INT(11) DEFAULT NULL COMMENT '排序字段',
  `status` INT(1) NOT NULL DEFAULT '0' COMMENT '状态,0:隐藏;1:待更新;2:已发布',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `course_id_index` (`course_id`) USING BTREE,
  KEY `idx_course_id` (`course_id`) USING BTREE
) ENGINE=INNODB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8;

课时表

CREATE TABLE `course_lesson` (
  `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'id',
  `course_id` INT(11) NOT NULL COMMENT '课程id',
  `section_id` INT(11) NOT NULL DEFAULT '0' COMMENT '章节id',
  `theme` VARCHAR(255) NOT NULL COMMENT '课时主题',
  `duration` INT(11) NOT NULL DEFAULT '0' COMMENT '课时时长(分钟)',
  `is_free` TINYINT(1) NOT NULL DEFAULT '0' COMMENT '是否免费',
  `create_time` DATETIME NOT NULL COMMENT '记录创建时间',
  `update_time` DATETIME NOT NULL COMMENT '更新时间',
  `is_del` TINYINT(1) DEFAULT '0' COMMENT '是否删除',
  `order_num` INT(11) DEFAULT NULL COMMENT '排序字段',
  `status` INT(2) DEFAULT '0' COMMENT '课时状态,0-隐藏,1-未发布,2-已发布',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `course_id_index` (`course_id`,`section_id`) USING BTREE,
  KEY `idx_sectionId_orderNum` (`section_id`,`order_num`) USING BTREE
) ENGINE=INNODB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8 COMMENT='课程节内容';

课程媒体

CREATE TABLE `course_media` (
  `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '课程媒体主键ID',
  `course_id` INT(11) DEFAULT NULL COMMENT '课程Id',
  `section_id` INT(11) DEFAULT NULL COMMENT '章ID',
  `lesson_id` INT(11) DEFAULT NULL COMMENT '课时ID',
  `cover_image_url` VARCHAR(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '封面图URL',
  `duration` VARCHAR(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '时长(06:02)',
  `file_edk` VARCHAR(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '媒体资源文件对应的EDK',
  `file_size` DOUBLE(10,2) DEFAULT NULL COMMENT '文件大小MB',
  `file_name` VARCHAR(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '文件名称',
  `file_dk` VARCHAR(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '媒体资源文件对应的DK',
  `create_time` DATETIME NOT NULL COMMENT '创建时间',
  `update_time` DATETIME NOT NULL COMMENT '更新时间',
  `is_del` TINYINT(1) DEFAULT '0' COMMENT '是否删除,0未删除,1删除',
  `duration_num` INT(11) DEFAULT NULL COMMENT '时长,秒数(主要用于音频在H5控件中使用)',
  `file_id` VARCHAR(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '媒体资源文件ID',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `uniq_lessonid_channel_mediatype_idx` (`lesson_id`) USING BTREE
) ENGINE=INNODB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

课程模块接口实现

多条件课程列表查询

需求分析

根据课程名称及课程状态进行多条件查询

查看接口文档,进行编码
实体类 Course
public class Course {
    // 主键
    private int id;
    // 课程名称
    private String courseName;
    // 课程一句话简介
    private String brief;
    // 原价
    private double price;
    // 原价标签
    private String priceTag;
    // 优惠价
    private double discounts;
    // 优惠价标签
    private String discountsTag;
    // 课程内容 markdown
    private String courseDescriptionMarkDown;
    // 课程描述
    private String courseDescription;
    // 课程分享图片 url
    private String courseImgUrl;
    // 是否新品
    private int isNew;
    // 广告语
    private String isNewDes;
    // 最后操作者
    private int lastOperatorId;
    // 自动上架时间
    private Date autoOnlineTime;
    // 创建时间
    private Date createTime;
    // 更新时间
    private Date updateTime;
    // 是否删除
    private int isDel;
    // 总时长
    private int totalDuration;
    // 课程列表展示图片
    private String courseListImg;
    // 课程状态,0 - 草稿,1 - 上架
    private int status;
    // 课程排序
    private int sortNum;
    // 课程预览第一个字段
    private String previewFirstField;
    // 课程预览第二个字段
    private String previewSecondField;
    // 销量
    private int sales;
    // getter, setter, toString ...
}
`ResponseResult`

用于表现层返回响应信息

public class ResponseResult {
    private Boolean success;
    private Integer state;
    private String message;
    private Object content;
    // getter, setter, toString ...
}
实体类 `CourseVo`

View Object 表现层对象,主要用于表现层来接收参数的

public class CourseVO {
    // 主键
    private Integer id;
    // 课程名称
    private String courseName;
    // 课程一句话简介
    private String brief;
    // 原价
    private double price;
    // 原价标签
    private String priceTag;
    // 优惠价
    private double discounts;
    // 优惠价标签
    private String discountsTag;
    // 课程内容 markdown
    private String courseDescriptionMarkDown;
    // 课程描述
    private String courseDescription;
    // 课程分享图片 url
    private String courseImgUrl;
    // 是否新品
    private int isNew;
    // 广告语
    private String isNewDes;
    // 最后操作者
    private int lastOperatorId;
    // 是否删除
    private int isDel;
    // 总时长
    private int totalDuration;
    // 课程列表展示图片
    private String courseListImg;
    // 课程状态,0 - 草稿,1 - 上架
    private int status;
    // 课程排序
    private int sortNum;
    // 课程预览第一个字段
    private String previewFirstField;
    // 课程预览第二个字段
    private String previewSecondField;
    // 销量
    private int sales;
    // 讲师姓名
    private String teacherName;
    // 讲师职位
    private String position;
    // 讲师描述
    private String description;
    // getter, setter, toString ...
}
Dao层 `CourseMapper`
public interface CourseMapper {
    /**
     * 多条件课程列表查询
     */
    List<Course> findCourseByCondition(CourseVO courseVO);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.renda.dao.CourseMapper">

    <!--
        注意:status 在 mysql 是一个关键字,所以要加上反单引号来防止出现误判情况
    -->
    <select id="findCourseByCondition" parameterType="courseVo" resultType="course">
        select * from course
        <where>
            <if test="courseName != null and courseName != ''">
                and course_name like concat('%', #{courseName}, '%')
            </if>
            <if test="`status` != null and `status` != ''">
                and `status` = #{status}
            </if>
            <if test="true">
                and is_del != 1
            </if>
        </where>
    </select>

</mapper>
Service 层 `CourseService`
public interface CourseService {
    List<Course> findCourseByCondition(CourseVO courseVO);
}
@Service
public class CourseServiceImpl implements CourseService {
    @Autowired
    private CourseMapper courseMapper;

    @Override
    public List<Course> findCourseByCondition(CourseVO courseVO) {
        return courseMapper.findCourseByCondition(courseVO);
    }
}
Web层 `CourseController`
@RestController
@RequestMapping("/course")
public class CourseController {
    @Autowired
    private CourseService courseService;

    /**
     * 多条件课程列表查询
     */
    @RequestMapping("/findCourseByCondition")
    public ResponseResult findCourseByCondition(@RequestBody CourseVO courseVO) {
        // 调用 service
        List<Course> courseList = courseService.findCourseByCondition(courseVO);
        // 返回响应参数的 JSON 字符串
        return new ResponseResult(true, 200, "响应成功", courseList);
    }
}
Postman 测试接口

课程图片上传

需求分析

在新增课程页面需要进行图片上传,并回显图片信息

查看接口文档,进行编码
`springmvc.xml`
<!-- 配置文件解析器 -->
<!-- 此处 id 为固定写法,不能随便取名 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="1048576"/>
</bean>

Web 层 CourseController

@RequestMapping("/courseUpload")
public ResponseResult fileUpload(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException {
    // 1.判断接收到的上传文件是否为空
    if (file.isEmpty()) {
        throw new RuntimeException();
    }

    // 2.获取项目部署路径
    // D:apache-tomcat-8.5.55webappsssm-web
    String realPath = request.getServletContext().getRealPath("/");
    // D:apache-tomcat-8.5.56webapps
    String substring = realPath.substring(0, realPath.indexOf("ssm_web"));

    // 3.生成新文件名
    String originalFilename = file.getOriginalFilename();
    String newFileName = "test";
    if (originalFilename != null) {
        newFileName = System.currentTimeMillis() + originalFilename.substring(originalFilename.lastIndexOf("."));
    }

    // 4.文件上传
    String uploadPath = substring + "upload\";
    File filePath = new File(uploadPath, newFileName);
    // 如果目录不存在就创建目录
    if (!filePath.getParentFile().exists()) {
        if (filePath.getParentFile().mkdirs()) {
            System.out.println("目录已经被创建:" + filePath);
        } else {
            System.out.println("创建目录失败");
        }
    }
    // 图片进行上传
    file.transferTo(filePath);

    // 5. 将文件名和文件路径返回,进行响应
    HashMap<Object, Object> map = new HashMap<>();
    map.put("fileName", newFileName);
    map.put("filePath", "http://localhost:8080/upload/" + newFileName);

    // 返回响应参数
    return new ResponseResult(true, 200, "图片上传成功", map);
}
Postman 测试接口

首先确保配置的 Tomcat 服务器的 Artifact 为 ssm-web:war,设置好图片 Tomcat 服务器保存图片的路径为 %MAVEN_HOME%webappsupload

然后 Postman 测试时,选择 Body 的 form-data,并选择 key 为 file 属性。

新建课程信息

需求分析

填写好新增课程信息以及关联的讲师信息后,点击保存,将表单信息保存到数据库中

查看接口文档,进行编码
Dao 层 `CourseMapper`
void saveCourse(Course course);

void saveTeacher(Teacher teacher);

CourseMapper.xml

<!--
        新增课程信息
        使用 selectKey 获取添加成功记录返回的 ID 值赋值给 Course 实体中 ID 属性
     -->
<insert id="saveCourse" parameterType="course">
    <selectKey resultType="int" order="AFTER" keyProperty="id">
        select LAST_INSERT_ID()
    </selectKey>
    INSERT INTO course(
    course_name,
    brief,
    preview_first_field,
    preview_second_field,
    course_img_url,
    course_list_img,
    sort_num,
    price,
    discounts,
    sales,
    discounts_tag,
    course_description_mark_down,
    create_time,
    update_time
    ) VALUES (
    #{courseName},#{brief},#{previewFirstField},#{previewSecondField},
    #{courseImgUrl},#{courseListImg},#{sortNum},#{price},#{discounts},
    #{sales},#{discountsTag},#{courseDescriptionMarkDown},#{createTime},
    #{updateTime}
    )
</insert>

<!-- 新增讲师信息 -->
<insert id="saveTeacher" parameterType="teacher">
    INSERT INTO teacher(
    course_id,
    teacher_name,
    `position`,
    description,
    create_time,
    update_time
    ) VALUES (#{courseId},#{teacherName},#{position},#{description},#{createTime},#{updateTime});
</insert>
Service 层 `CourseService`
void saveCourseOrTeacher(CourseVO courseVO) throws InvocationTargetException, IllegalAccessException;
@Override
public void saveCourseOrTeacher(CourseVO courseVO) throws InvocationTargetException, IllegalAccessException {
    // 1.封装课程信息
    Course course = new Course();
    BeanUtils.copyProperties(course, courseVO);
    // 补全课程信息
    Date date = new Date();
    course.setCreateTime(date);
    course.setUpdateTime(date);
    // 保存课程
    courseMapper.saveCourse(course);
    // 获取新插入数据的 id 值
    int courseId = course.getId();

    // 2.封装讲师信息
    Teacher teacher = new Teacher();
    BeanUtils.copyProperties(teacher, courseVO);
    // 补全讲师信息
    teacher.setCreateTime(date);
    teacher.setUpdateTime(date);
    teacher.setIsDel(0);
    teacher.setCourseId(courseId);
    // 保存讲师信息
    courseMapper.saveTeacher(teacher);
}
Web 层 `CourseController`
@RequestMapping("/saveOrUpdateCourse")
public ResponseResult saveOrUpdateCourse(@RequestBody CourseVO courseVO) throws InvocationTargetException, IllegalAccessException {
    courseService.saveCourseOrTeacher(courseVO);
    return new ResponseResult(true, 200, "响应成功", null);
}
Postman 测试接口

回显课程信息

需求分析

点击编辑按钮,回显课程信息以及其关联的讲师信息

查看接口文档,进行编码
Dao 层 `CourseMapper`
CourseVO findCourseById(Integer id);

CourseMapper.xml

<select id="findCourseById" parameterType="int" resultType="courseVO">
    SELECT
      c.*,
      t.`teacher_name` `teacher_name`,
      t.`position` `position`,
      t.`description` `description`
    FROM
      course c
      LEFT JOIN teacher t
        ON c.`id` = t.`course_id`
    WHERE c.`id` = #{id}
</select>
Service 层:`CourseService`
CourseVO findCourseById(Integer id);
@Override
public CourseVO findCourseById(Integer id) {
    return courseMapper.findCourseById(id);
}
Web 层 `CourseController`
@RequestMapping("/findCourseById")
public ResponseResult findCourseById(Integer id){
    CourseVO courseVO = courseService.findCourseById(id);
    return new ResponseResult(true, 200, "根据ID查询课程信息成功", courseVO);
}
Postman 测试接口

修改课程信息

需求分析

点击保存按钮,将修改后的课程信息保存到数据库中

查看接口文档,进行编码
Dao 层 CourseMapper
void updateTeacher(Teacher teacher);

CourseMapper.xml

<!-- 更新课程信息 -->
<update id="updateCourse" parameterType="course">
    UPDATE course
    <trim prefix="SET" suffixOverrides=",">
        <if test="courseName != null and courseName != ''">
            course_name = #{courseName},
        </if>
        <if test="brief != null and brief != ''">
            brief = #{brief},
        </if>
        <if test="previewFirstField != null and previewFirstField != ''">
            preview_first_field=#{previewFirstField},
        </if>
        <if test="previewSecondField != null and previewSecondField != ''">
            preview_second_field=#{previewSecondField},
        </if>
        <if test="courseImgUrl != null and courseImgUrl != ''">
            course_img_url=#{courseImgUrl},
        </if>
        <if test="courseListImg != null and courseListImg != ''">
            course_list_img=#{courseListImg},
        </if>
        <if test="sortNum != null and sortNum != ''">
            sort_num=#{sortNum},
        </if>
        <if test="price != null and price != ''">
            price=#{price},
        </if>
        <if test="discounts != null and discounts != ''">
            discounts=#{discounts},
        </if>
        <if test="sales != null and sales != '' or sales==0">
            sales=#{sales},
        </if>
        <if test="discountsTag != null and discountsTag != ''">
            discounts_tag=#{discountsTag},
        </if>
        <if test="courseDescriptionMarkDown != null and courseDescriptionMarkDown != ''">
            course_description_mark_down=#{courseDescriptionMarkDown},
        </if>
        <if test="updateTime != null">
            update_time=#{updateTime},
        </if>
    </trim>
</update>

<!-- 更新讲师信息 -->
<update id="updateTeacher" parameterType="teacher">
    UPDATE teacher
    <trim prefix="SET" suffixOverrides=",">
        <if test="teacherName != null and teacherName != ''">
            teacher_name = #{teacherName},
        </if>
        <if test="position != null and position != ''">
            position = #{position},
        </if>
        <if test="description != null and description != ''">
            description = #{description},
        </if>
        <if test="updateTime != null">
            update_time=#{updateTime}
        </if>
    </trim>
    <where>
        <if test="courseId != null and courseId != ''">course_id = #{courseId}</if>
    </where>
</update>
Service 层 CourseService
void updateCourseOrTeacher(CourseVO courseVO) throws InvocationTargetException, IllegalAccessException;
@Override
public void updateCourseOrTeacher(CourseVO courseVO) throws InvocationTargetException, IllegalAccessException {
    // 封装课程信息
    Course course = new Course();
    BeanUtils.copyProperties(course, courseVO);
    // 补全信息
    Date date = new Date();
    course.setUpdateTime(date);
    // 更新课程信息
    courseMapper.updateCourse(course);

    // 封装讲师信息
    Teacher teacher = new Teacher();
    BeanUtils.copyProperties(teacher, courseVO);
    // 补全信息
    teacher.setCourseId(course.getId());
    teacher.setUpdateTime(date);
    // 更新讲师信息
    courseMapper.updateTeacher(teacher);
}
Web 层 CourseController
@RequestMapping("/saveOrUpdateCourse")
public ResponseResult saveOrUpdateCourse(@RequestBody CourseVO courseVO) throws InvocationTargetException, IllegalAccessException {
    if (courseVO.getId() == null) {
        // 新增操作
        courseService.saveCourseOrTeacher(courseVO);
        return new ResponseResult(true, 200, "新增成功", null);
    } else {
        // 修改操作
        courseService.updateCourseOrTeacher(courseVO);
        return new ResponseResult(true, 200, "修改成功", null);
    }
}
Postman 测试接口

课程状态管理

需求分析

在课程列表展示页面中,可以通过点击上架 / 下架按钮,修改课程状态

查看接口文档,进行编码
Dao 层 CourseMapper
void updateCourseStatus(Course course);

CourseMapper.xml

<update id="updateCourseStatus" parameterType="course">
    update `course` set `status` = #{status}, `update_time` = #{updateTime} where `id` = #{id}
</update>
Service 层 CourseService
void updateCourseStatus(int courseId, int status);
@Override
public void updateCourseStatus(int courseId, int status) {
    // 封装数据
    Course course = new Course();
    course.setId(courseId);
    course.setStatus(status);
    course.setUpdateTime(new Date());
    // 调用 mapper
    courseMapper.updateCourseStatus(course);
}
Web 层 CourseController
@RequestMapping("/updateCourseStatus")
public ResponseResult updateCourseStatus(Integer id, Integer status) {
    // 调用 service,传递参数,完成课程状态的变更
    courseService.updateCourseStatus(id, status);
    // 响应数据
    HashMap<Object, Object> map = new HashMap<>();
    map.put("status", status);
    return new ResponseResult(true, 200, "课程状态变更成功", map);
}
Postman 测试接口

课程内容展示

需求分析

需求:点击内容管理,展示课程对应的课程内容(课程内容包含了章节和课时)

查看接口文档,进行编码

CourseSection 章节

public class CourseSection {
    // id
    private Integer id;
    // 课程 id
    private int courseId;
    // 章节名
    private String sectionName;
    // 章节描述
    private String description;
    // 创建时间
    private Date createTime;
    // 更新时间
    private Date updateTime;
    // 是否删除
    private int isDe;
    // 排序
    private int orderNum;
    // 状态
    private int status;
    // 课时集合
    private List<CourseLesson> lessonList;
    // getter, setter ...
}

CourseLesson 课时

public class CourseLesson {
    // 主键
    private Integer id;
    // 课程 id
    private int courseId;
    // 章节 id
    private int sectionId;
    // 课时主题
    private String theme;
    // 课时时长
    private int duration;
    // 是否免费
    private int isFree;
    // 创建时间
    private Date createTime;
    // 修改时间
    private Date updateTime;
    // 是否删除
    private int isDel;
    // 排序
    private int orderNum;
    // 状态
    private int status;
    // getter, setter ...
}
Dao 层 CourseContentMapper
public interface CourseContentMapper {
    List<CourseSection> findSectionAndLessonByCourseId(Integer courseId);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.renda.dao.CourseContentMapper">
    <resultMap id="SectionAndLessonResultMap" type="courseSection">
        <id property="id" column="id"/>
        <result property="courseId" column="course_id"/>
        <result property="sectionName" column="section_name"/>
        <result property="description" column="description"/>
        <result property="createTime" column="create_time"/>
        <result property="updateTime" column="update_time"/>
        <result property="isDe" column="is_de"/>
        <result property="orderNum" column="order_num"/>
        <collection property="lessonList" ofType="courseLesson">
            <id property="id" column="lesson_id"/>
            <result property="courseId" column="course_id"/>
            <result property="sectionId" column="section_id"/>
            <result property="theme" column="theme"/>
            <result property="duration" column="duration"/>
            <result property="isFree" column="is_free"/>
            <result property="orderNum" column="order_num"/>
            <result property="status" column="status"/>
        </collection>
    </resultMap>
    <!-- 根据课程 ID 查询课程内容(章节 - 课时) -->
    <select id="findSectionAndLessonByCourseId" parameterType="int" resultMap="SectionAndLessonResultMap">
        SELECT
          cs.*,
          cl.id lesson_id,
          cl.course_id,
          cl.section_id,
          cl.theme,
          cl.duration,
          cl.create_time,
          cl.update_time,
          cl.is_del,
          cl.order_num,
          cl.`status`
        FROM
          course_section cs
          LEFT JOIN course_lesson cl
            ON cl.section_id = cs.id
        WHERE cs.course_id = #{id}
         ORDER BY cs.order_num;
    </select>
</mapper>
Service 层 CourseContentService
public interface CourseContentService {
    List<CourseSection> findSectionAndLessonByCourseId(Integer courseId);
}
@Service
public class CourseContentServiceImpl implements CourseContentService {
    @Autowired
    private CourseContentMapper courseContentMapper;

    @Override
    public List<CourseSection> findSectionAndLessonByCourseId(Integer courseId) {
        return courseContentMapper.findSectionAndLessonByCourseId(courseId);
    }
}
Web 层 CourseContentController
@RestController
@RequestMapping("/courseContent")
public class CourseContentController {
    @Autowired
    private CourseContentService courseContentService;

    @RequestMapping("/findSectionAndLesson")
    public ResponseResult findSectionAndLessonByCourseId(Integer courseId) {
        List<CourseSection> list = courseContentService.findSectionAndLessonByCourseId(courseId);
        return new ResponseResult(true, 200, "章节及课时内容查询成功", list);
    }
}
Postman 测试接口

回显章节对应的课程信息

需求分析

在课程内容界面回显课程信息

查看接口文档,进行编码
Dao 层 CourseContentMapper
Course findCourseByCourseId(int courseId);
<select id="findCourseByCourseId" parameterType="int" resultType="course">
    SELECT id, course_name FROM course WHERE id = #{courseId}
</select>
Service 层 CourseContentService
Course findCourseByCourseId(int courseId);
@Override
public Course findCourseByCourseId(int courseId) {
    return courseContentMapper.findCourseByCourseId(courseId);
}
Web 层 CourseContentController
@RequestMapping("/findCourseByCourseId")
public ResponseResult findCourseByCourseId(Integer courseId){
    Course course = courseContentService.findCourseByCourseId(courseId);
    return new ResponseResult(true, 200, "查询课程信息成功", course);
}
Postman 测试接口

新建章节信息

需求分析

在课程内容展示页面中,可以通过点击添加阶段按钮,添加章节信息

查看接口文档,进行编码
Dao 层 CourseContentMapper
void saveSection(CourseSection courseSection);
<insert id="saveSection" parameterType="CourseSection">
    INSERT INTO course_section (
      course_id,
      section_name,
      description,
      order_num,
      `status`,
      create_time,
      update_time
    )
    VALUES
      (#{courseId},#{sectionName},#{description},#{orderNum},
       #{status},#{createTime},#{updateTime});
</insert>
Service 层 CourseContentService
void saveSection(CourseSection courseSection);
@Override
public void saveSection(CourseSection courseSection) {
    // 补全信息
    Date date = new Date();
    courseSection.setCreateTime(date);
    courseSection.setUpdateTime(date);
    // 调用 dao 方法
    courseContentMapper.saveSection(courseSection);
}
Web 层 CourseContentController
@RequestMapping("/saveOrUpdateSection")
public ResponseResult saveOrUpdateSection(@RequestBody CourseSection courseSection) {
    courseContentService.saveSection(courseSection);
    return new ResponseResult(true, 200, "新增章节成功", null);
}
Postman 测试接口

修改章节信息

需求分析

点击确定按钮,将修改后的章节信息保存到数据库中

查看接口文档,进行编码
Dao 层 CourseContentMapper
void updateSection(CourseSection courseSection);
<update id="updateSection" parameterType="courseSection">
    UPDATE course_section
    <trim prefix="SET" suffixOverrides=",">
        <if test="sectionName != null and sectionName != ''">
            section_name = #{sectionName},
        </if>

        <if test="description != null and description != ''">
            description = #{description},
        </if>

        <if test="orderNum != null and orderNum != '' or orderNum == 0">
            order_num = #{orderNum},
        </if>

        <if test="updateTime != null">
            update_time = #{updateTime},
        </if>
    </trim>
    <where>
        <if test="id != null and id != ''">
            id = #{id}
        </if>
    </where>
</update>
Service 层 CourseContentService
void updateSection(CourseSection courseSection);
@Override
public void updateSection(CourseSection courseSection) {
    // 补全信息
    courseSection.setUpdateTime(new Date());
    // 调用 dao 方法
    courseContentMapper.updateSection(courseSection);
}
Web 层 CourseContentController
@RequestMapping("/saveOrUpdateSection")
public ResponseResult saveOrUpdateSection(@RequestBody CourseSection courseSection) {
    // 判断是否携带了章节 ID
    if (courseSection.getId() == null) {
        // 新增
        courseContentService.saveSection(courseSection);
        return new ResponseResult(true, 200, "新增章节成功", null);
    } else {
        // 更新
        courseContentService.updateSection(courseSection);
        return new ResponseResult(true, 200, "更新章节成功", null);
    }
}
Postman 测试接口

修改章节状态

需求分析

点击修改章节状态按钮,将当前章节信息的状态进行修改

查看接口文档,进行编码
Dao 层 CourseContentMapper
void updateSectionStatus(CourseSection courseSection);

CourseContentMapper.xml

<update id="updateSectionStatus" parameterType="courseSection">
    UPDATE course_section SET `status` = #{status}, update_time = #{updateTime} WHERE id = #{id}
</update>
Service 层 CourseContentService
void updateSectionStatus(int id, int status);
@Override
public void updateSectionStatus(int id, int status) {
    // 封装数据
    CourseSection courseSection = new CourseSection();
    courseSection.setStatus(status);
    courseSection.setUpdateTime(new Date());
    courseSection.setId(id);
    // 调用 mapper
    courseContentMapper.updateSectionStatus(courseSection);
}
Web 层 CourseContentController
@RequestMapping("/updateSectionStatus")
public ResponseResult updateSectionStatus(int id, int status) {
    courseContentService.updateSectionStatus(id, status);
    // 数据响应
    HashMap<Object, Object> map = new HashMap<>();
    map.put("status", status);
    return new ResponseResult(true, 200, "修改章节状态成功", map);
}
Postman 测试接口

新建课时信息

需求分析

点击添加阶段按钮,将弹出页面填写的章节信息保存到数据库中

查看接口文档,进行编码

Dao 层 CourseContentMapper
void saveLesson(CourseLesson courseLesson);

CourseContentMapper.xml

<insert id="saveLesson" parameterType="courseLesson">
    INSERT INTO course_lesson (
    course_id,
    section_id,
    theme,
    duration,
    is_free,
    order_num,
    `status`,
    create_time,
    update_time
    )
    VALUES
    (#{courseId},#{sectionId},#{theme},#{duration},#{isFree},#{orderNum},
    #{status},#{createTime},#{updateTime});
</insert>
Service 层 CourseContentService
void saveLesson(CourseLesson courseLesson);
@Override
public void saveLesson(CourseLesson courseLesson) {
    // 补全信息
    Date date = new Date();
    courseLesson.setCreateTime(date);
    courseLesson.setUpdateTime(date);
    // 调用 dao 方法
    courseContentMapper.saveLesson(courseLesson);
}
Web 层 CourseContentController
@RequestMapping("/saveOrUpdateLesson")
public ResponseResult saveOrUpdateLesson(@RequestBody CourseLesson courseLesson) {
    courseContentService.saveLesson(courseLesson);
    return new ResponseResult(true, 200, "新增课时成功", null);
}
Postman 测试接口

修改课时信息

需求分析

点击确定按钮,将修改后的课时信息保存到数据库中

查看接口文档,进行编码

Dao 层 CourseContentMapper
void updateLesson(CourseLesson courseLesson);

CourseContentMapper.xml

<update id="updateLesson" parameterType="courseLesson">
    UPDATE course_lesson
    <trim prefix="SET" suffixOverrides=",">
        <if test="theme != null and theme != ''">
            theme = #{theme},
        </if>

        <if test="duration != null and duration != ''">
            duration = #{duration},
        </if>

        <if test="`isFree` != null and `isFree` != ''">
            is_free = #{isFree},
        </if>

        <if test="orderNum != null and orderNum != '' or orderNum == 0">
            order_num = #{orderNum},
        </if>

        <if test="updateTime != null">
            update_time = #{updateTime},
        </if>
    </trim>
    <where>
        <if test="id != null and id != ''">
            id = #{id}
        </if>
    </where>
</update>
Service 层 CourseContentService
void updateLesson(CourseLesson courseLesson);
@Override
public void updateLesson(CourseLesson courseLesson) {
    // 补全信息
    courseLesson.setUpdateTime(new Date());
    // 调用 dao 方法
    courseContentMapper.updateLesson(courseLesson);
}
Web 层 CourseContentController
@RequestMapping("/saveOrUpdateLesson")
public ResponseResult saveOrUpdateLesson(@RequestBody CourseLesson courseLesson) {
    // 判断是否携带了课时 ID
    if (courseLesson.getId() == null) {
        // 新增
        courseContentService.saveLesson(courseLesson);
        return new ResponseResult(true, 200, "新增课时成功", null);
    } else {
        // 更新
        courseContentService.updateLesson(courseLesson);
        return new ResponseResult(true, 200, "修改课时成功", null);
    }
}
Postman 测试接口