首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >教育平台项目后台管理系统:课程内容模块

教育平台项目后台管理系统:课程内容模块

作者头像
RendaZhang
发布2020-09-08 16:13:38
1.4K0
发布2020-09-08 16:13:38
举报
文章被收录于专栏:RendaRenda

开发流程

需求分析

配置课时(课程内容管理)模块,主要是对课程内容进行管理。

数据库表分析

course - 课程表

course_section - 课程章节表

course_lesson - 课时信息表

一个课程表对多个课程章节表,一个课程章节表对多个课时表。

实体类设计

Course 类与 Course_Section 类是一对多关系;Course_Section 类与 Course_Lesson 类是一对多关系。

在 Course 类中定义一个 List 集合,并指定 List 的泛型是 Course_Section 类型,表示 一个课程中可以包含多个章节。

在 Course_Section 类中,定义一个 Course 类型的属性,用来保存章节所对应的具体的课程信息。

在 Course_Section 类中定义一个 List 集合,并指定 List 的泛型是 Course_Lesson 类型,这样就可以表示一个章节中包含多个课时。

// Course 类:
...
  List<Course_Section> sectionList = new ArrayList<>();
...

// Course_Section 类:
...
  List<Course_Lesson> lessonList = new ArrayList<>();
  private Course course;
...

// Course_Lesson 类:
...
  private Course_Section course_section;
...
Dao 接口及实现类编写
/**
 * 课程内容管理 DAO 层接口
 * */
public interface CourseContentDao {
}

/**
 * 课程内容管理 DAO 层实现类
 * */
public class CourseContentDaoImpl implements CourseContentDao {
}
Service 接口及实现类编写
/**
 * 课程内容管理 Service 层接口
 * */
public interface CourseContentService {
}

/**
 * 课程内容管理 Service 层实现类
 * */
public class CourseContentServiceImpl implements CourseContentService {
}
`CourseContentServlet` 编写

CourseContentServlet 继承 BaseServlet

@WebServlet("/courseContent")
public class CourseContentServlet extends BaseServlet {
}

功能一:展示课程内容

需求分析

分析:要展示的内容是对应课程下的章节与课时信息

-- 查询 ID 为 1 的课程的章节与课时信息
SELECT 
    cs.`id`,
    cs.`section_name`,
    cl.`theme` '课时名称'
FROM course_section cs INNER JOIN course_lesson cl
ON cs.`id` = cl.`section_id` 
WHERE cs.`course_id` = ;

-- 在程序中尽量避免使用连接查询。可以将上面的 SQL 进行拆分,每一条 SQL 对应一个功能

-- 根据课程 ID 查询章节相关的内容
SELECT 
    id,
    course_id,
    section_name,
    description,
    order_num,
    `status`
FROM course_section WHERE course_id = ;

-- 根据章节 ID 查询课时相关的内容
SELECT
    id,
    course_id,
    section_id,
    theme,
    is_free,
    order_num,
    `status`
FROM course_lesson WHERE section_id = ;
DAO 层编写

编写两个方法

CourseContentDaoImpl

/**
 * 根据课程 ID 查询课程相关信息
 *
 * @param courseId
 */
@Override
public List<Course_Section> findSectionAndLessonByCourseId(int courseId) {
    try {
        // 创建 QueryRunner
        QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());

        // 编写 SQL
        String sql = "SELECT \n" +
                "id,\n" +
                "course_id,\n" +
                "section_name,\n" +
                "description,\n" +
                "order_num,\n" +
                "STATUS\n" +
                "FROM course_section WHERE course_id = ?";

        // 执行查询
        List<Course_Section> sectionList = qr.query(sql,
                new BeanListHandler<Course_Section>(Course_Section.class), courseId);

        // 根据章节 ID 查询课时信息
        for (Course_Section section : sectionList) {
            // 调用获取章节对应的课时方法,将课时数据封装到章节对象中
            section.setLessonList(findLessonBySectionId(section.getId()));
        }

        // 返回结果
        return sectionList;
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }
    return null;
}

/**
 * 根据章节 ID 查询章节相关的课时信息
 *
 * @param sectionId
 */
@Override
public List<Course_Lesson> findLessonBySectionId(int sectionId) {
    try {
        // 创建 QueryRunner
        QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());

        // 编写 SQL
        String sql = "SELECT \n" +
                "id,\n" +
                "course_id,\n" +
                "section_id,\n" +
                "theme,\n" +
                "duration,\n" +
                "is_free,\n" +
                "order_num,\n" +
                "STATUS\n" +
                "FROM course_lesson WHERE section_id = ?";

        // 执行查询
        return qr.query(sql, new BeanListHandler<Course_Lesson>(Course_Lesson.class), sectionId);
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }

    return null;
}

DAO 层测试

public class TestCourseContentDao {

    CourseContentDao contentDao = new CourseContentDaoImpl();

    /**
     * 测试 查询对应课程下的章节与课时
     */
    @Test
    public void testFindSectionAndLessonByCourseId(){
        List<Course_Section> list = contentDao.findSectionAndLessonByCourseId();
        // 遍历输出章节信息
        for (Course_Section courseSection : list) {
            System.out.println(courseSection.getId() + " = " + courseSection.getSection_name());

            List<Course_Lesson> lessonList = courseSection.getLessonList();
            // 遍历输出课时信息
            for (Course_Lesson courseLesson : lessonList) {
                System.out.println(courseLesson.getId() + " = " + courseLesson.getTheme() + " = "
                        + courseLesson.getSection_id());
            }
            System.out.println();
        }
    }
}
Service 层编写

CourseContentServiceImpl

CourseContentDao contentDao = new CourseContentDaoImpl();

/**
 * 根据课程 id 查询课程内容
 */
@Override
public List<Course_Section> findSectionAndLessonByCourseId(int courseId) {
    return contentDao.findSectionAndLessonByCourseId(courseId);
}
Servlet 编写

CourseContentServlet 中添加 findSectionAndLessonByCourseId 方法

/**
 * 展示对应课程的章节与课时信息
 */
public void findSectionAndLessonByCourseId(HttpServletRequest request, HttpServletResponse response) {
    try {
        // 获取参数
        String course_id = request.getParameter("course_id");

        // 业务处理
        CourseContentService contentService = new CourseContentServiceImpl();
        List<Course_Section> sectionList = contentService.findSectionAndLessonByCourseId(Integer.parseInt(course_id));

        // 返回结果
        response.getWriter().println(JSON.toJSONString(sectionList));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

接口测试:使用 Postman 根据接口文档进行测试

功能二:新建章节信息

需求分析

首先根据课程 ID 查询课程名称进行回显,然后获取输入的新的章节信息,执行保存章节数据。

Dao 层编写

CourseContentDaoImpl

...

/**
 * 添加章节时进行数据回显
 */
@Override
public Course findCourseByCourseId(int courseId) {
    try {
        // 创建 QueryRunner
        QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());

        // 编写 SQL
        String sql = "SELECT id, course_name FROM course WHERE id = ?";

        // 执行查询并返回结果
        return qr.query(sql, new BeanHandler<Course>(Course.class), courseId);
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }

    return null;
}

/**
 * 保存章节信息
 */
@Override
public int saveSection(Course_Section section) {
    try {
        // 创建 QueryRunner
        QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());

        // 编写 SQL
        String sql = "INSERT INTO course_section(\n" +
                "course_id, \n" +
                "section_name, \n" +
                "description, \n" +
                "order_num, \n" +
                "`status`, \n" +
                "create_time, \n" +
                "update_time)\n" +
                "VALUES(?, ?, ?, ?, ?, ?, ?);";

        // 准备参数
        Object[] params = {section.getCourse_id(), section.getSection_name(),
                section.getDescription(), section.getOrder_num(), section.getStatus(),
                section.getCreate_time(), section.getUpdate_time()};

        // 返回受影响的行数
        return qr.update(sql, params);
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }

    return ;
}

...

Dao 层测试 TestCourseContentDao

/**
 * 测试 根据课程 id 回显课程名称
 */
@Test
public void testFindCourseByCourseId() {
    Course course = contentDao.findCourseByCourseId();
    System.out.println(course.getId() + " " + course.getCourse_name());
}

/**
 * 测试 保存章节信息
 */
@Test
public void testSaveSection() {
    Course_Section section = new Course_Section();
    section.setCourse_id();
    section.setSection_name("章节名字");
    section.setDescription("章节描述");
    section.setOrder_num();
    // 更新时间
    String dateFormat = DateUtils.getDateFormat();
    section.setCreate_time(dateFormat);
    section.setUpdate_time(dateFormat);
    // 状态:0 隐藏,1 待更新,2 已发布
    section.setStatus();
    System.out.println(contentDao.saveSection(section));
}
Service 层编写

CourseContentServiceImpl

...

/**
 * 添加章节时进行数据回显
 */
@Override
public Course findCourseById(int courseId) {
    return contentDao.findCourseByCourseId(courseId);
}

/**
 * 保存章节信息
 */
@Override
public String saveSection(Course_Section section) {
    // 补全章节信息
    // 状态:0 隐藏,1 待更新,2 已发布
    section.setStatus();
    String date = DateUtils.getDateFormat();
    section.setCreate_time(date);
    section.setUpdate_time(date);

    // 调用 Dao 进行插入
    if (contentDao.saveSection(section) > ) {
        // 保存成功
        return StatusCode.SUCCESS.toString();
    } else {
        // 保存失败
        return StatusCode.FAIL.toString();
    }
}

...
Servlet 编写
课程信息回显接口
/**
 * 回显章节对应的课程信息
 */
public void findCourseById(HttpServletRequest request , HttpServletResponse response){
    try {
        // 获取参数
        String courseId = request.getParameter("course_id");

        // 业务处理
        CourseContentService contentService = new CourseContentServiceImpl();
        Course course = contentService.findCourseById(Integer.parseInt(courseId));

        // 返回数据,将对象转换为 JSON,只转换需要的字段
        SimplePropertyPreFilter filter = new SimplePropertyPreFilter(Course.class,
                "id", "course_name");
        response.getWriter().println(JSON.toJSONString(course,filter));
    } catch (IOException e) {
        e.printStackTrace();
    }
}
保存章节信息接口

POST 请求方法常用的三种数据提交格式:

  • Content-Type : application/x-www-form-urlencoded 请求体中的数据会以普通表单形式(键值对)发送到后端。
  • Content-Type : application/json ; charset=utf-8 请求体中的数据会以 JSON 字符串的形式发送到后端。
  • Content-Type : multipart/form-data 多部件上传既可以上传键值对,也可以上传文件。

第二种 JSON 格式与第三种多部件上传都无法使用 getParameter() 方法获取数据。

根据接口文档描述:前台传输的是 JSON 格式的数据,使用 getParameter() 方法无法获取参数。

如果请求参数是 JSON 格式的数,可以通过 request.getReader() 这个方法获取一个流对象来进行 读取。

首先,在 BaseServlet 中创建一个方法用来获取 JSON 格式的数据:

/**
 * 如果 POST 请求格式为 application/json;charset=utf-8
 * 则在这个方法中使用流的方式获取到 POST 请求的数据
 */
public String getPostJSON(HttpServletRequest request){
    try {
        // 从 request 中获取字符缓冲输入流对象
        BufferedReader reader = request.getReader();

        // 创建 StringBuffer 用来保存读取出的数据
        StringBuffer sb = new StringBuffer();

        // 循环读取
        String line = null;
        while((line = reader.readLine()) != null){
            // 追加到 StringBuffer 中
            sb.append(line);
        }

        // 将读取到的内容转换为字符串并返回
        return sb.toString();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return null;
}

然后,修改 BaseServlet 中的 doPost 方法:

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // 要访问的方法名
    String methodName = null;

    // 获取 POST 请求的 Content-Type 类型
    String contentType = req.getHeader("Content-Type");

    // 判断传递的数据是不是 JSON 格式
    if("application/json;charset=utf-8".equals(contentType)){
        // 是 JSON 格式 调用 getPostJSON
        String postJSON = getPostJSON(req);
        // 将 JSON 格式的字符串转化为 map
        Map<String,Object> map = JSON.parseObject(postJSON, Map.class);
        // 从 map 集合中获取 methodName
        methodName = (String) map.get("methodName");
        // 将获取到的数据保存到 request 域对象中
        req.setAttribute("map", map);
    } else {
        methodName = req.getParameter("methodName");
    }

    // 判断并执行对应的方法
    if (methodName != null) {
        // 使用反射方式提升代码的可维护性
        try {
            // 获取字节码对象
            Class aClass = this.getClass();
            // 根据传入的方法名获取对应的方法对象
            Method method = aClass.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
            method.invoke(this, req, resp);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
            System.out.println("请求的功能不存在");
        }
    }
}

最后,编写接口代码,CourseContentServlet

/**
 * 保存 & 修改 章节信息
 */
public void saveOrUpdateSection(HttpServletRequest request, HttpServletResponse response){
    try {
        // 从 request 域对象中获取获取参数
        Map<String,Object> map = (Map) request.getAttribute("map");

        // 创建 Course_Section
        Course_Section section = new Course_Section();

        // 使用 BeanUtils 工具类,将 map 中的数据封装到 section
        BeanUtils.populate(section, map);

        // 业务处理并响应结果
        CourseContentService contentService = new CourseContentServiceImpl();
        response.getWriter().print(contentService.saveSection(section));
    } catch (IllegalAccessException | InvocationTargetException | IOException e) {
        e.printStackTrace();
    }
}

使用 Postman 测试接口:

  • 选择 POST 请求方式,设置 Content-Type = application/json
  • 选择 raw 发送 JSON 格式数据

功能三:章节信息修改

需求分析

选择章节,点击编辑,传递章节 id;根据章节 id 修改章节信息。

根据接口文档,没有要求编写回显接口,不需要后台根据章节 id 查询对应章节信息进行回显,所以回显操作由前端代码完成。

DAO 层编写

CourseContentDaoImpl

/**
 * 修改章节信息
 */
@Override
public int updateSection(Course_Section section) {
    try {
        // 创建 QueryRunner
        QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());

        // 编写 SQL
        String sql = "UPDATE course_section SET \n" +
                "section_name = ?,\n" +
                "description = ?,\n" +
                "order_num = ?,\n" +
                "update_time = ?\n" +
                "WHERE id = ?";

        // 准备参数
        Object[] param = {section.getSection_name(), section.getDescription(),
                section.getOrder_num(), section.getUpdate_time(), section.getId()};

        // 执行修改操作
        return qr.update(sql, param);
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }

    return ;
}

Dao 层测试 TestCourseContentDao

/**
 * 测试 修改章节信息
 */
@Test
public void testUpdateSection() {
    Course_Section section = new Course_Section();
    section.setId();
    section.setSection_name("微服务架构-Renda");
    section.setDescription("微服务架构详解-Renda");
    section.setOrder_num();
    section.setUpdate_time(DateUtils.getDateFormat());

    System.out.println(contentDao.updateSection(section));
}
Service 层编写

CourseContentServiceImpl

/**
 * 修改章节信息
 *
 * @param section
 */
@Override
public String updateSection(Course_Section section) {
    // 补全章节信息
    String date = DateUtils.getDateFormat();
    section.setUpdate_time(date);

    // 调用 Dao 进行插入,根据修改是否成功,封装对应信息
    if (contentDao.updateSection(section) > ) {
        return StatusCode.SUCCESS.toString();
    } else {
        return StatusCode.FAIL.toString();
    }

}
Servlet 编写

保存章节信息和修改章节信息,访问的是同一个接口,所以在 CourseContentServletsaveOrUpdateSection 方法中进行一下判断:携带 id 就是修改章节操作;未携带 id 就是新增章节操作。

...

if (section.getId() != ) {
    // 修改操作
    response.getWriter().print(contentService.updateSection(section));
} else {
    // 保存操作
    response.getWriter().print(contentService.saveSection(section));
}

...

接口测试:根据接口文档,使用 Postman 进行测试。

功能四:章节状态管理

需求分析

根据选择的状态信息,发送对应的状态编号,进行修改 status 状态;0 隐藏,1 待更新,2 已发布。

DAO 层编写

CourseContentDaoImpl

/**
 * 修改章节的状态
 */
@Override
public int updateSectionStatus(int id, int status) {
    try {
        // 创建 QueryRunner
        QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());

        // 编写 SQL
        String sql = "UPDATE course_section SET `status` = ?, update_time = ? WHERE id = ?";

        // 准备参数
        Object[] param = {status, DateUtils.getDateFormat(), id};

        // 执行修改操作
        return qr.update(sql, param);
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }

    return ;
}

Dao 层测试 TestCourseContentDao

/**
 * 测试 修改章节状态
 */
@Test
public void testUpdateSectionStatus() {
    System.out.println(contentDao.updateSectionStatus(, ));
}
Service 层编写

CourseContentServiceImpl

/**
 * 修改章节的状态
 */
@Override
public String updateSectionStatus(int id, int status) {
    // 调用 Dao 修改状态,根据修改是否成功,封装对应信息
    if (contentDao.updateSectionStatus(id, status) > ){
        return StatusCode.SUCCESS.toString();
    } else {
        return StatusCode.FAIL.toString();
    }
}
Servlet 编写

CourseContentServlet

/**
 * 修改章节状态
 */
public void updateSectionStatus(HttpServletRequest request , HttpServletResponse response) {
    try {
        // 获取参数
        int id = Integer.parseInt(request.getParameter("id"));
        int status = Integer.parseInt(request.getParameter("status"));

        // 业务处理并返回结果数据
        CourseContentService contentService = new CourseContentServiceImpl();
        response.getWriter().println(contentService.updateSectionStatus(id, status));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

接口测试:根据接口文档,使用 Postman 进行测试。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Renda 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 开发流程
    • 需求分析
      • 数据库表分析
        • 实体类设计
          • Dao 接口及实现类编写
            • Service 接口及实现类编写
              • `CourseContentServlet` 编写
              • 功能一:展示课程内容
                • 需求分析
                  • DAO 层编写
                    • Service 层编写
                      • Servlet 编写
                      • 功能二:新建章节信息
                        • 需求分析
                          • Dao 层编写
                            • Service 层编写
                              • Servlet 编写
                              • 功能三:章节信息修改
                                • 需求分析
                                  • DAO 层编写
                                    • Service 层编写
                                      • Servlet 编写
                                      • 功能四:章节状态管理
                                        • 需求分析
                                          • DAO 层编写
                                            • Service 层编写
                                              • Servlet 编写
                                              领券
                                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档