内容管理模块
文章目录
- 内容管理模块
- 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 需求分析
课程计划添加成功,如果课程还没有提交时可以删除课程计划。
删除第一级别的大章节时要求大章节下边没有小章节时方可删除。
删除第二级别的小章节的同时需要将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 需求分析
课程计划新增后默认排在同级别最后,课程计划排序功能是可以灵活调整课程计划的显示顺序,如下图:
上移表示将课程计划向上移动。
下移表示将课程计划向下移动。
向上移动后和上边同级的课程计划交换位置,可以将两个课程计划的排序字段值进行交换。
向下移动后和下边同级的课程计划交换位置,可以将两个课程计划的排序字段值进行交换。
9.3.2 接口定义
接口示例如下:
向下移动:
Java
Request URL: http://localhost:8601/api/content/teachplan/movedown/43
Request Method: POST
参数1:movedown 为 移动类型,表示向下移动
参数2:43为课程计划id
向上移动:
Java
Request URL: http://localhost:8601/api/content/teachplan/moveup/43
Request Method: POST
参数1:moveup 为 移动类型,表示向上移动
参数2:43为课程计划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 需求分析
在课程计划维护界面点击下一步进入师资管理界面:
点击添加教师打开添加界面,如下图,不用实现上传照片。
添加成功查询教师信息如下:
在这个界面可以删除老师,也可以点击编辑,修改教师信息:
注意: 只允许向机构自己的课程中添加老师、删除老师。 机构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 接口测试
找到一门课程进行删除,删除后从数据库确认课程基本信息、课程营销信息、课程计划、课程计划关联信息、课程师资是否删除成功。
当我们删除本机构课程时,会将课程对应的教师信息、课程计划、营销信息、课程基本信息均删除