2.4-学成在线内容管理之项目实战

内容管理模块

文章目录

  • 内容管理模块
    • 9 项目实战
      • 9.1 实战环境
        • 9.1.1 实战流程
      • 9.2 删除课程计划
        • 9.2.1 需求分析
        • 9.2.2 接口定义
        • 9.2.3 接口开发
        • 9.2.4 接口测试
      • 9.3 课程计划排序
        • 9.3.1 需求分析
        • 9.3.2 接口定义
        • 9.3.3 接口开发
        • 9.3.4 接口测试
      • 9.4 师资管理
        • 9.4.1 需求分析
        • 9.4.2 接口定义
        • 9.4.3 接口开发
      • 9.4.4 接口测试
      • 9.5 删除课程
        • 9.5.1 需求分析
        • 9.5.2 接口定义
        • 9.5.3 接口开发
        • 9.5.4 接口测试

9 项目实战

9.1 实战环境

9.1.1 实战流程

项目实战是模拟企业实际开发的场景,自己参考文档独立完成开发任务,项目实战可以有效的培养自己面对需求进行分析与开发的能力。
这部分要完成的内容包括

添加课程、添加课程计划、添加师资信息
修改课程、修改课程计划、修改师资信息
删除课程、删除课程计划、删除师资信息
课程计划上移、下移功能

9.2 删除课程计划

9.2.1 需求分析

课程计划添加成功,如果课程还没有提交时可以删除课程计划。
2.4-学成在线内容管理之项目实战_第1张图片

删除第一级别的大章节时要求大章节下边没有小章节时方可删除。
删除第二级别的小章节的同时需要将teachplan_media表关联的信息也删除。

9.2.2 接口定义

删除课程计划的接口定义:
传入课程计划id进行删除操作。

Java
Request URL: /content/teachplan/246
Request Method: DELETE

如果失败返回:
{"errCode":"120409","errMessage":"课程计划信息还有子级信息,无法操作"}

如果成功:状态码200,不返回信息

9.2.3 接口开发

定义接口如下

@ApiOperation("课程计划删除")
@DeleteMapping("/content/teachplan/{teachplanId}")
public void deleteTeachplan(@PathVariable Long teachplanId) {
    
}

接口开发
定义删除课程计划的接口

void deleteTeachplan(Long teachplanId);

对应的接口实现

@Override
public void deleteTeachplan(Long teachplanId) {
    if (teachplanId == null)
        XueChengPlusException.cast("课程计划id为空");
    Teachplan teachplan = teachplanMapper.selectById(teachplanId);
    // 判断当前课程计划是章还是节
    Integer grade = teachplan.getGrade();
    // 当前课程计划为章
    if (grade == 1) {
        // 查询当前课程计划下是否有小节
        LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
        // select * from teachplan where parentid = {当前章计划id}
        queryWrapper.eq(Teachplan::getParentid, teachplanId);
        // 获取一下查询的条目数
        Integer count = teachplanMapper.selectCount(queryWrapper);
        // 如果当前章下还有小节,则抛异常
        if (count > 0)
            XueChengPlusException.cast("课程计划信息还有子级信息,无法操作");
        teachplanMapper.deleteById(teachplanId);
    } else {
        // 课程计划为节
        teachplanMapper.deleteById(teachplanId);
        LambdaQueryWrapper<TeachplanMedia> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TeachplanMedia::getTeachplanId, teachplanId);
        teachplanMediaMapper.delete(queryWrapper);
    }
}

完善Controller层接口

@ApiOperation("课程计划删除")
@DeleteMapping("/teachplan/{teachplanId}")
public void deleteTeachplan(@PathVariable Long teachplanId) {
    teachplanService.deleteTeachplan(teachplanId);
}
9.2.4 接口测试

首先使用httpclient工具进行测试

Java
### 删除课程计划
DELETE {{content_host}}/content/teachplan/43

分以下情况测试:
1、删除大章节,大章节下有小章节时不允许删除。
2、删除大章节,大单节下没有小章节时可以正常删除。
3、删除小章节,同时将关联的信息进行删除。

9.3 课程计划排序

9.3.1 需求分析

课程计划新增后默认排在同级别最后,课程计划排序功能是可以灵活调整课程计划的显示顺序,如下图:
2.4-学成在线内容管理之项目实战_第2张图片

上移表示将课程计划向上移动。
下移表示将课程计划向下移动。
向上移动后和上边同级的课程计划交换位置,可以将两个课程计划的排序字段值进行交换。
向下移动后和下边同级的课程计划交换位置,可以将两个课程计划的排序字段值进行交换。

9.3.2 接口定义

接口示例如下:
向下移动:

Java
Request URL: http://localhost:8601/api/content/teachplan/movedown/43
Request Method: POST
参数1:movedown  为 移动类型,表示向下移动
参数243为课程计划id

向上移动:

Java
Request URL: http://localhost:8601/api/content/teachplan/moveup/43
Request Method: POST
参数1:moveup 为 移动类型,表示向上移动
参数243为课程计划id

每次移动传递两个参数:
1、移动类型: movedown和moveup
2、课程计划id

9.3.3 接口开发
void orderByTeachplan(String moveType, Long teachplanId);
@Transactional
@Override
public void orderByTeachplan(String moveType, Long teachplanId) {
    Teachplan teachplan = teachplanMapper.selectById(teachplanId);
    // 获取层级和当前orderby,章节移动和小节移动的处理方式不同
    Integer grade = teachplan.getGrade();
    Integer orderby = teachplan.getOrderby();
    // 章节移动是比较同一课程id下的orderby
    Long courseId = teachplan.getCourseId();
    // 小节移动是比较同一章节id下的orderby
    Long parentid = teachplan.getParentid();
    if ("moveup".equals(moveType)) {
        if (grade == 1) {
            // 章节上移,找到上一个章节的orderby,然后与其交换orderby
            // SELECT * FROM teachplan WHERE courseId = 117 AND grade = 1  AND orderby < 1 ORDER BY orderby DESC LIMIT 1
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getGrade, 1)
                    .eq(Teachplan::getCourseId, courseId)
                    .lt(Teachplan::getOrderby, orderby)
                    .orderByDesc(Teachplan::getOrderby)
                    .last("LIMIT 1");
            Teachplan tmp = teachplanMapper.selectOne(queryWrapper);
            exchangeOrderby(teachplan, tmp);
        } else if (grade == 2) {
            // 小节上移
            // SELECT * FROM teachplan WHERE parentId = 268 AND orderby < 5 ORDER BY orderby DESC LIMIT 1
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getParentid, parentid)
                    .lt(Teachplan::getOrderby, orderby)
                    .orderByDesc(Teachplan::getOrderby)
                    .last("LIMIT 1");
            Teachplan tmp = teachplanMapper.selectOne(queryWrapper);
            exchangeOrderby(teachplan, tmp);
        }

    } else if ("movedown".equals(moveType)) {
        if (grade == 1) {
            // 章节下移
            // SELECT * FROM teachplan WHERE courseId = 117 AND grade = 1 AND orderby > 1 ORDER BY orderby ASC LIMIT 1
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getCourseId, courseId)
                    .eq(Teachplan::getGrade, grade)
                    .gt(Teachplan::getOrderby, orderby)
                    .orderByAsc(Teachplan::getOrderby)
                    .last("LIMIT 1");
            Teachplan tmp = teachplanMapper.selectOne(queryWrapper);
            exchangeOrderby(teachplan, tmp);
        } else if (grade == 2) {
            // 小节下移
            // SELECT * FROM teachplan WHERE parentId = 268 AND orderby > 1 ORDER BY orderby ASC LIMIT 1
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getParentid, parentid)
                    .gt(Teachplan::getOrderby, orderby)
                    .orderByAsc(Teachplan::getOrderby)
                    .last("LIMIT 1");
            Teachplan tmp = teachplanMapper.selectOne(queryWrapper);
            exchangeOrderby(teachplan, tmp);
        }
    }
}

/**
 * 交换两个Teachplan的orderby
 * @param teachplan 
 * @param tmp 
 */
private void exchangeOrderby(Teachplan teachplan, Teachplan tmp) {
    if (tmp == null)
        XueChengPlusException.cast("已经到头啦,不能再移啦");
    else {
        // 交换orderby,更新
        Integer orderby = teachplan.getOrderby();
        Integer tmpOrderby = tmp.getOrderby();
        teachplan.setOrderby(tmpOrderby);
        tmp.setOrderby(orderby);
        teachplanMapper.updateById(tmp);
        teachplanMapper.updateById(teachplan);
    }
}

controller

@Transactional
@Override
public void orderByTeachplan(String moveType, Long teachplanId) {
    Teachplan teachplan = teachplanMapper.selectById(teachplanId);
    // 获取层级和当前orderby,章节移动和小节移动的处理方式不同
    Integer grade = teachplan.getGrade();
    Integer orderby = teachplan.getOrderby();
    // 章节移动是比较同一课程id下的orderby
    Long courseId = teachplan.getCourseId();
    // 小节移动是比较同一章节id下的orderby
    Long parentid = teachplan.getParentid();
    if ("moveup".equals(moveType)) {
        if (grade == 1) {
            // 章节上移,找到上一个章节的orderby,然后与其交换orderby
            // SELECT * FROM teachplan WHERE courseId = 117 AND grade = 1  AND orderby < 1 ORDER BY orderby DESC LIMIT 1
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getGrade, 1)
                    .eq(Teachplan::getCourseId, courseId)
                    .lt(Teachplan::getOrderby, orderby)
                    .orderByDesc(Teachplan::getOrderby)
                    .last("LIMIT 1");
            Teachplan tmp = teachplanMapper.selectOne(queryWrapper);
            exchangeOrderby(teachplan, tmp);
        } else if (grade == 2) {
            // 小节上移
            // SELECT * FROM teachplan WHERE parentId = 268 AND orderby < 5 ORDER BY orderby DESC LIMIT 1
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getParentid, parentid)
                    .lt(Teachplan::getOrderby, orderby)
                    .orderByDesc(Teachplan::getOrderby)
                    .last("LIMIT 1");
            Teachplan tmp = teachplanMapper.selectOne(queryWrapper);
            exchangeOrderby(teachplan, tmp);
        }

    } else if ("movedown".equals(moveType)) {
        if (grade == 1) {
            // 章节下移
            // SELECT * FROM teachplan WHERE courseId = 117 AND grade = 1 AND orderby > 1 ORDER BY orderby ASC LIMIT 1
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getCourseId, courseId)
                    .eq(Teachplan::getGrade, grade)
                    .gt(Teachplan::getOrderby, orderby)
                    .orderByAsc(Teachplan::getOrderby)
                    .last("LIMIT 1");
            Teachplan tmp = teachplanMapper.selectOne(queryWrapper);
            exchangeOrderby(teachplan, tmp);
        } else if (grade == 2) {
            // 小节下移
            // SELECT * FROM teachplan WHERE parentId = 268 AND orderby > 1 ORDER BY orderby ASC LIMIT 1
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getParentid, parentid)
                    .gt(Teachplan::getOrderby, orderby)
                    .orderByAsc(Teachplan::getOrderby)
                    .last("LIMIT 1");
            Teachplan tmp = teachplanMapper.selectOne(queryWrapper);
            exchangeOrderby(teachplan, tmp);
        }
    }
}

/**
 * 交换两个Teachplan的orderby
 * @param teachplan 
 * @param tmp 
 */
private void exchangeOrderby(Teachplan teachplan, Teachplan tmp) {
    if (tmp == null)
        XueChengPlusException.cast("已经到头啦,不能再移啦");
    else {
        // 交换orderby,更新
        Integer orderby = teachplan.getOrderby();
        Integer tmpOrderby = tmp.getOrderby();
        teachplan.setOrderby(tmpOrderby);
        tmp.setOrderby(orderby);
        teachplanMapper.updateById(tmp);
        teachplanMapper.updateById(teachplan);
    }
}
9.3.4 接口测试

该功能可直接进行前后端联调,可以立即看到 效果。
1、向上移动测试
先找一个上边有课程计划的进行测试,向上移动后两个交换顺序。
再找最上边的课程计划向上移动,操作后位置不变因为已经在最上边了。
2、向下移动测试
先找一个下边有课程计划的进行测试,向下移动后两个交换顺序。
再找最下边的课程计划向下移动,操作后位置不变因为已经在最下边了。

9.4 师资管理

9.4.1 需求分析

在课程计划维护界面点击下一步进入师资管理界面:
2.4-学成在线内容管理之项目实战_第3张图片

点击添加教师打开添加界面,如下图,不用实现上传照片。
2.4-学成在线内容管理之项目实战_第4张图片

添加成功查询教师信息如下:
2.4-学成在线内容管理之项目实战_第5张图片

在这个界面可以删除老师,也可以点击编辑,修改教师信息:
2.4-学成在线内容管理之项目实战_第6张图片

注意: 只允许向机构自己的课程中添加老师、删除老师。 机构id统一使用:1232141425L

9.4.2 接口定义

1、查询教师接口请求示例

Java
get /courseTeacher/list/75
75为课程id,请求参数为课程id

响应结果
[{"id":23,"courseId":75,"teacherName":"张老师","position":"讲师","introduction":"张老师教师简介张老师教师简介张老师教师简介张老师教师简介","photograph":null,"createDate":null}]

2、添加教师请求示例

Java
post  /courseTeacher

请求参数:
{
  "courseId": 75,
  "teacherName": "王老师",
  "position": "教师职位",
  "introduction": "教师简介"
}
响应结果:
{"id":24,"courseId":75,"teacherName":"王老师","position":"教师职位","introduction":"教师简介","photograph":null,"createDate":null}

3、修改教师

Java
put /courseTeacher
请求参数:
{
  "id": 24,
  "courseId": 75,
  "teacherName": "王老师",
  "position": "教师职位",
  "introduction": "教师简介",
  "photograph": null,
  "createDate": null
}
响应:
{"id":24,"courseId":75,"teacherName":"王老师","position":"教师职位","introduction":"教师简介","photograph":null,"createDate":null}

4、删除教师

delete /ourseTeacher/course/75/26

75:课程id
26:教师id,即course_teacher表的主键
请求参数:课程id、教师id

响应:状态码200,不返回信息
9.4.3 接口开发

从接口示例中可以看到,新增和删除用的是同一个接口,判断请求是新增还是删除,是根据请求参数中是否传递了id来决定的
请求参数中没有id,则为新增教师
请求参数中有id,则为修改教师

@Slf4j
@RestController
@Api(value = "教师信息相关接口", tags = "教师信息相关接口")
public class CourseTeacherController {
    @Autowired
    private CourseTeacherService courseTeacherService;

    @ApiOperation("查询教师信息接口")
    @GetMapping("/courseTeacher/list/{courseId}")
    public List<CourseTeacher> getCourseTeacherList(@PathVariable Long courseId) {
        return null;
    }

    @ApiOperation("添加/修改教师信息接口")
    @PostMapping("/courseTeacher")
    public CourseTeacher saveCourseTeacher(@RequestBody CourseTeacher courseTeacher) {
        return null;
    }

    @ApiOperation("删除教师信息接口")
    @DeleteMapping("/courseTeacher/course/{courseId}/{teacherId}")
    public void deleteCourseTeacher(@PathVariable Long courseId, @PathVariable Long teacherId) {

    }
}
public interface CourseTeacherService {
    List<CourseTeacher> getCourseTeacherList(Long courseId);

    CourseTeacher saveCourseTeacher(CourseTeacher courseTeacher);

    void deleteCourseTeacher(Long courseId, Long teacherId);
}
@Slf4j
@Service
public class CourseTeacherServiceImpl implements CourseTeacherService {
    @Autowired
    private CourseTeacherMapper courseTeacherMapper;

    @Override
    public List<CourseTeacher> getCourseTeacherList(Long courseId) {
        // SELECT * FROM course_teacher WHERE course_id = 117
        LambdaQueryWrapper<CourseTeacher> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseTeacher::getCourseId, courseId);
        List<CourseTeacher> courseTeachers = courseTeacherMapper.selectList(queryWrapper);
        return courseTeachers;
    }

    @Transactional
    @Override
    public CourseTeacher saveCourseTeacher(CourseTeacher courseTeacher) {
        Long id = courseTeacher.getId();
        if (id == null) {
            // id为null,新增教师
            CourseTeacher teacher = new CourseTeacher();
            BeanUtils.copyProperties(courseTeacher, teacher);
            teacher.setCreateDate(LocalDateTime.now());
            int flag = courseTeacherMapper.insert(teacher);
            if (flag <= 0)
                XueChengPlusException.cast("新增失败");
            return getCourseTeacher(teacher);
        } else {
            // id不为null,修改教师
            CourseTeacher teacher = courseTeacherMapper.selectById(id);
            BeanUtils.copyProperties(courseTeacher, teacher);
            int flag = courseTeacherMapper.updateById(teacher);
            if (flag <= 0)
                XueChengPlusException.cast("修改失败");
            return getCourseTeacher(teacher);
        }
    }

    @Override
    public void deleteCourseTeacher(Long courseId, Long teacherId) {
        LambdaQueryWrapper<CourseTeacher> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseTeacher::getId, teacherId);
        queryWrapper.eq(CourseTeacher::getCourseId, courseId);
        int flag = courseTeacherMapper.delete(queryWrapper);
        if (flag < 0)
            XueChengPlusException.cast("删除失败");
    }

    public CourseTeacher getCourseTeacher(CourseTeacher courseTeacher) {
        return courseTeacherMapper.selectById(courseTeacher.getId());
    }
}

9.4.4 接口测试

1、添加教师
2、查询教师
3、修改教师
4、删除教师

9.5 删除课程

9.5.1 需求分析

课程的审核状态为未提交时方可删除。
删除课程需要删除课程相关的基本信息、营销信息、课程计划、课程教师信息。

9.5.2 接口定义

删除课程接口

Java
delete  /course/87
87为课程id
请求参数:课程id
响应:状态码200,不返回信息
9.5.3 接口开发
@ApiOperation("删除课程")
@DeleteMapping("/course/{courseId}")
public void deleteCourse(@PathVariable Long courseId) {
    Long companyId = 1232141425L;
    courseBaseInfoService.delectCourse(companyId,courseId);
}
void delectCourse(Long companyId, Long courseId);
@Transactional
@Override
public void delectCourse(Long companyId, Long courseId) {
    CourseBase courseBase = courseBaseMapper.selectById(courseId);
    if (!companyId.equals(courseBase.getCompanyId()))
        XueChengPlusException.cast("只允许删除本机构的课程");
    // 删除课程教师信息
    LambdaQueryWrapper<CourseTeacher> teacherLambdaQueryWrapper = new LambdaQueryWrapper<>();
    teacherLambdaQueryWrapper.eq(CourseTeacher::getCourseId, courseId);
    courseTeacherMapper.delete(teacherLambdaQueryWrapper);
    // 删除课程计划
    LambdaQueryWrapper<Teachplan> teachplanLambdaQueryWrapper = new LambdaQueryWrapper<>();
    teachplanLambdaQueryWrapper.eq(Teachplan::getCourseId, courseId);
    teachplanMapper.delete(teachplanLambdaQueryWrapper);
    // 删除营销信息
    courseMarketMapper.deleteById(courseId);
    // 删除课程基本信息
    courseBaseMapper.deleteById(courseId);
}
9.5.4 接口测试

找到一门课程进行删除,删除后从数据库确认课程基本信息、课程营销信息、课程计划、课程计划关联信息、课程师资是否删除成功。
当我们删除本机构课程时,会将课程对应的教师信息、课程计划、营销信息、课程基本信息均删除

你可能感兴趣的:(#,学成在线课件笔记,微服务,spring,boot,sql,java)