天津储鑫盛钢材现货供应商 发表于 2024-10-24 18:18:40

学成在线实战

#1024步伐员节|征文#
https://i-blog.csdnimg.cn/direct/d504726c7fd74890b8ee2d9721554486.png
一、Bug修改

在实战之前,老师留了一个bug,这个bug出现的原因是因为在查询课程计划时,利用的是Inner join查询,以是当章节下面没有小节的时间,是查不出来数据的,只必要将其sql语句改为left join即可解决
二、实战前预备

1.排序设置不合理原因分析

在先前老师带我们做的添加课程计划中的设置排序这部门是有问题的,老师也说过这部门并不合理,必要我们本身调解。
原因在于:原先我们添加课程计划,设置排序时采用的是节点数量+1方式,如许有什么问题呢,举个例子:当我们添加的小节有四个,他们的orderby值为1、2、3、4,如果我们将2和3删除之后,在添加小节,那么新添加的小节orderby=2+1,那么它会排在原先的4之前而不是最后,会出现乱序问题,会导致乱序问题,这便是原因。
2.改进策略

我们通过查询同级之中orderby的max值并将其+1作为新增的排序规则即可。
(1)TeachplanMapper

/**
* 查询同一级节点中orderBy的最大值
* @param parentId 父节点id
* @param courseId 课程id
* @return
*/
Integer selectMaxOrderBy(@Param("parentId") Long parentId, @Param("courseId") Long courseId);


// TeacherMapper.xml
<!-- 查询同一级节点中orderBy的最大值 -->
<select id="selectMaxOrderBy" resultType="java.lang.Integer">
   select max(orderby)
   from teachplan
   where parentid=#{parentId} and course_id=#{courseId}
</select> (2)TeachplanServiceImpl

将原来的新增部门改为如下所示:
    /**
   * 新增/修改/保存课程计划
   * @param saveTeachplanDto 模型类
   */
    @Override
    public void saveTeachplan(SaveTeachplanDto saveTeachplanDto) {
      // 通过课程计划id判断是新增和修改
      Long teachplanId = saveTeachplanDto.getId();
      if (teachplanId == null) {
            // 新增
            Teachplan teachplan = new Teachplan();
            BeanUtils.copyProperties(saveTeachplanDto, teachplan);
            // 确定排序字段 - 找到同级节点个数,排序字段就是当前节点下的子节点数量加一 问题:当节点进行删除操作后,存在bug
            Long courseId = saveTeachplanDto.getCourseId();
            Long parentId = saveTeachplanDto.getParentid();
//            teachplan.setOrderby(getTeachplanCount(courseId, parentid) + 1);
            int count = getTeachplanCount(courseId, parentId);
            int maxOrderBy = 0; // 给个默认值,否则当章节之下无小节点时,会报空指针异常
            if (count != 0) { // 章节之下有小节点
                maxOrderBy = teachplanMapper.selectMaxOrderBy(parentId, courseId); // 根据当下的最大orderBy+1排序
            }
            teachplan.setOrderby(maxOrderBy + 1);

            teachplanMapper.insert(teachplan);
      } else {
            // 修改
            Teachplan teachplan = teachplanMapper.selectById(teachplanId);
            // 将参数复制到teachplan
            BeanUtils.copyProperties(saveTeachplanDto, teachplan);
            teachplanMapper.updateById(teachplan);
      }
    } 三、删除课程计划

1.接口定义

    /**
   * 删除课程计划
   * @param id 课程计划id
   */
    @ApiOperation("删除课程计划")
    @DeleteMapping("/teachplan/{id}")
    public void removeTeachplan(@PathVariable Long id) {
      teachplanService.removeTeachplan(id);
    } 2.service开发

需求:
        删除第一级别的大章节时要求大章节下边没有小章节时方可删除。
        删除第二级别的小章节的同时必要将teachplan_media表关联的信息也删除。
    /**
   * 根据课程计划id,查询此节点下子节点的数量
   * @param parentId
   * @return
   */
    private int getSonCount(Long parentId) {
      LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
      queryWrapper = queryWrapper.eq(Teachplan::getParentid, parentId);
      return teachplanMapper.selectCount(queryWrapper);
    }
    /**
   * 删除课程计划
   * @param id 课程id
   */
    @Transactional
    @Override
    public void removeTeachplan(Long id) {
      // 1.根据id查出teachplan
      Teachplan teachplan = teachplanMapper.selectById(id);
      if (teachplan == null) { // 判断数据是否存在,避免空指针
            XueChengPlusException.cast(CommonError.OBJECT_NULL);
      }

      // 2.是大章节 - 判断有没有小章节,没有直接删;有则抛出自定义异常
      if (teachplan.getParentid() == 0) { // 是大章节
            // 查询有没有小章节
            int count = getSonCount(id);
            if (count > 0) { // 有小章节 不可删除
                XueChengPlusException.cast("课程计划信息还有子级信息,无法操作", "120409");
            }
            teachplanMapper.deleteById(id);
            return;
      }

      // 3.是小章节 - 删除小节与其对应在teachplan_media表中的数据
      teachplanMapper.deleteById(id);
      LambdaQueryWrapper<TeachplanMedia> mediaQueryWrapper = new LambdaQueryWrapper<>();
      mediaQueryWrapper = mediaQueryWrapper.eq(TeachplanMedia::getTeachplanId, id);
      teachplanMediaMapper.delete(mediaQueryWrapper);
    } 四、向上/向下移动课程计划

1.思路分析:

因为向上/向下两个方法的思路基本一致,因此在service中共用一个方法实现。
团体思路:先举行边界值判断,上移时如果为第一个大概下移时是最后一个,则无操作直接结束;如果不是边界值,那么找到当前teachplan相邻的上一个大概下一个teachplan举行orderBy值交换,实现上下移动。
详细思路:

[*]上移照旧下移:首先在controller中调用service的时间,我们多传一个flag用于标记是向上移动照旧向下移动。
[*]边界值判断:上移:查询与当前teachplan同级的节点的orderBy的最大值,如果当前的teachplan的orderBy是最小值,那么它就是第一个,则无操作直接返回;下移同理(orderBy为最大值)。
[*]找到与当前teachplan的相邻teachplan:根据前端所传的teachplanId,查出parientId与courseId,从而找出与当前teachplan同级的全部节点数据,按升序排列放入list集合,遍历集合找出当前teachplan的元素下标,即可获取次序排列后的相邻的上一个大概下一个teachplan数据。
2.接口定义

    /**
   * 向上移动课程计划
      * @param id 课程计划id
   */
    @ApiOperation("向上移动课程计划")
    @PostMapping("/teachplan/moveup/{id}")
    public void moveUpTeachplan(@PathVariable Long id) {
      teachplanService.moveDownOrUpTeachplan(id, true);
    }

    /**
   * 向下移动课程计划
   * @param id 课程计划id
   */
    @ApiOperation("向下移动课程计划")
    @PostMapping("/teachplan/movedown/{id}")
    public void moveDownTeachplan(@PathVariable Long id) {
      teachplanService.moveDownOrUpTeachplan(id, false);
    } 3.service开发

    @Transactional
    @Override
    public void moveDownOrUpTeachplan(Long id, boolean flag) {
      // 1.数据校验
      Teachplan teachplan = teachplanMapper.selectById(id);
      if (teachplan == null) { // 判断数据是否存在,避免空指针
            XueChengPlusException.cast(CommonError.OBJECT_NULL);
      }

      // 2.拿到当前节点同级数据的集合与它所对应的下标 - 用于获取顺序相邻的节点数据用于orderBy交换
      Map<String, Object> map = getListAndIndex(teachplan);
      List<Teachplan> teachplanList = (List<Teachplan>) map.get("list");
      int index = (int) map.get("index");

      // 3.上移或者下移
      if (flag) { // 上移
            int minOrderBy = teachplanMapper.selectMinOrderBy(teachplan.getParentid(), teachplan.getCourseId());
            if (teachplan.getOrderby() == minOrderBy) { // 是第一个,不做操作直接返回
                return;
            }
            Teachplan preTeachplan = teachplanList.get(index - 1); // 上一个节点
            exchangeOrderBy(teachplan, preTeachplan); // 交换orderBy
      } else {
            int maxOrderBy = teachplanMapper.selectMaxOrderBy(teachplan.getParentid(), teachplan.getCourseId());
            if (teachplan.getOrderby() == maxOrderBy) { // 是最后一个,不做操作直接返回
                return;
            }
            Teachplan nextTeachplan = teachplanList.get(index + 1); // 下一个节点
            exchangeOrderBy(teachplan, nextTeachplan); // 交换orderBy
      }
    }

    /**
   * 交换两个teachplan的orderBy
   * @param teachplan 当前节点
   * @param otherTeachplan 上一个或者下一个节点
   */
    public void exchangeOrderBy(Teachplan teachplan, Teachplan otherTeachplan) {
      Integer orderBy = teachplan.getOrderby();
      teachplan.setOrderby(otherTeachplan.getOrderby());
      otherTeachplan.setOrderby(orderBy);
      teachplanMapper.updateById(teachplan);
      teachplanMapper.updateById(otherTeachplan);
    }
    /**
   * 获取当前节点同级节点的list集合以及其元素下标 - 用于获取上一个或者下一个节点数据
   * @param teachplan 课程计划
   * @return Map<String, Object>
   */
    private Map<String, Object> getListAndIndex(Teachplan teachplan) {
      // 1.获取当前同级节点的list集合
      // 根据parengId与courseId通过orderBy字段排序获取当前级的所有List<Teachplan> 升序排序
      LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
      queryWrapper = queryWrapper
                .eq(Teachplan::getCourseId, teachplan.getCourseId())
                .eq(Teachplan::getParentid, teachplan.getParentid())
                .orderByAsc(Teachplan::getOrderby);
      List<Teachplan> teachplanList = teachplanMapper.selectList(queryWrapper);

      // 2.获取当前操作节点的元素下标 - 用于获取与其相邻的上一个或下一个元素
      // 根据list下标索引获取当前节点的下一个节点,再进行orderBy交换即可
      int index; // 记录当前
      for (index = 0; index < teachplanList.size(); index++) {
            if (teachplanList.get(index).getId().longValue() == teachplan.getId().longValue()) {
                break;
            }
      }

      // 3.封装数据返回
      Map<String, Object> map = new HashMap<>();
      map.put("list", teachplanList);
      map.put("index", index);
      return map;
    } 4.mapper开发

    /**
   * 查询同一级节点中orderBy的最大值
   * @param parentId 父节点id
   * @param courseId 课程id
   * @return
   */
    Integer selectMaxOrderBy(@Param("parentId") Long parentId, @Param("courseId") Long courseId);

    /**
   * 查询同一级节点中orderBy的最小值
   * @param parentId 父节点id
   * @param courseId 课程id
   * @return
   */
    Integer selectMinOrderBy(@Param("parentId") Long parentId, @Param("courseId") Long courseId);     <!-- 查询同一级节点中orderBy的最大值 -->
    <select id="selectMaxOrderBy" resultType="java.lang.Integer">
      select max(orderby)
      from teachplan
      where parentid=#{parentId} and course_id=#{courseId}
    </select>

    <!-- 查询同一级节点中orderBy的最小值 -->
    <select id="selectMinOrderBy" resultType="java.lang.Integer">
      select min(orderby)
      from teachplan
      where parentid=#{parentId} and course_id=#{courseId}
    </select> 五、师资管理

1.查询西席

1.1接口定义

https://i-blog.csdnimg.cn/direct/a7092cbddc6347548abf05426a122eed.png
根据相应结果的布局可知,返回值应为List<CourseTeacher> 
@Api(value = "课程计划教师编辑接口", tags = "课程计划教师编辑接口")
@RestController
public class CourseTeacherController {

    @Autowired
    private CourseTeacherService courseTeacherService;

    /**
   * 查询教师信息接口
   * @param id 课程id
   * @return List<CourseTeacher>
   */
    @ApiOperation("查询教师信息")
    @GetMapping("/courseTeacher/list/{id}")
    public List<CourseTeacher> getTeacherInfo(@PathVariable Long id) {
      List<CourseTeacher> list = courseTeacherService.getTeacherInfo(id);
      return list;
    }
} 2.2service开发

    /**
   * 查询课程教师
   * @param courseId 课程id
   * @return List<CourseTeacher>
   */
    @Override
    public List<CourseTeacher> getTeacherInfo(Long courseId) {
      LambdaQueryWrapper<CourseTeacher> queryWrapper = new LambdaQueryWrapper<>();
      queryWrapper = queryWrapper.eq(CourseTeacher::getCourseId, courseId);
      List<CourseTeacher> courseTeachers = courseTeacherMapper.selectList(queryWrapper);
      return courseTeachers;
    } 2.新增/修改西席

老师的文档上写的新增和修改的哀求方式不一样,应该是两个接口,但是现实前端照旧用的一个接口,因此新增和修改共用一个接口。
2.1接口定义

    /**
   * 新增/修改教师接口
   * @param courseTeacher 模型类
   * @return CourseTeacher
   */
    @ApiOperation("新增/修改教师")
    @PostMapping("/courseTeacher")
    public CourseTeacher saveCourseTeacher(@RequestBody CourseTeacher courseTeacher) {
      // TODO 当前登录机构ID
      Long companyId = 1232141425L;
      return courseTeacherService.saveCourseTeacher(companyId, courseTeacher);
    } 2.2service开发

    /**
   * 新增/修改教师接口
   * @param courseTeacher 模型类
   * @return CourseTeacher
   */
    @Override
    public CourseTeacher saveCourseTeacher(Long companyId, CourseTeacher courseTeacher) {
      // 1.判断当前登录机构是否为本课程机构
      CourseBase courseBase = courseBaseMapper.selectById(courseTeacher.getCourseId());
      if (ObjectUtils.isEmpty(courseBase)) { // 判断对象是否为空
            XueChengPlusException.cast(CommonError.OBJECT_NULL);
      }
      if (companyId.longValue() != courseBase.getCompanyId().longValue()) { // 机构不一致
            XueChengPlusException.cast("不能操作其它机构课程");
      }

      // 2.新增/修改教师信息
      Long courseTeacherId = courseTeacher.getId();
      if (courseTeacherId == null) { // 新增
            courseTeacher.setCreateDate(LocalDateTime.now());
            int insert = courseTeacherMapper.insert(courseTeacher);
            if (insert <= 0) {
                XueChengPlusException.cast(CommonError.UNKOWN_ERROR);
            }
      } else { // 修改
            int update = courseTeacherMapper.updateById(courseTeacher);
            if (update <= 0) {
                XueChengPlusException.cast(CommonError.UNKOWN_ERROR);
            }
      }

      return courseTeacher;
    } 3.删除西席信息

3.1接口定义

    /**
   * 删除教师信息
   * @param courseId 课程id
   * @param id 教师id
   */
    @ApiOperation("删除教师")
    @DeleteMapping("/courseTeacher/course/{courseId}/{id}")
    public void removeCourseTeacher(@PathVariable Long courseId, @PathVariable Long id) {
      // TODO 当前登录机构ID
      Long companyId = 1232141425L;
      courseTeacherService.removeCourseTeacher(courseId, id, companyId);
    } 3.2service开发

    /**
   * 删除教师信息
   * @param courseId 课程id
   * @param id       教师id
   */
    @Override
    public void removeCourseTeacher(Long courseId, Long id, Long companyId) {
      // 1.判断是否为当前登录机构
      CourseBase courseBase = courseBaseMapper.selectById(courseId);
      if (ObjectUtils.isEmpty(courseBase)) { // 判断对象是否为空
            XueChengPlusException.cast(CommonError.OBJECT_NULL);
      }
      if (companyId.longValue() != courseBase.getCompanyId().longValue()) { // 机构不一致
            XueChengPlusException.cast("不能操作其它机构课程");
      }

      // 2.删除本课程中此教师信息
      courseTeacherMapper.deleteById(id);
    } 六、删除课程

留意:这部门是写在CourseBaseInfoController的不要写错辣!!!!!
1.接口开发

    /**
   * 删除课程:基本信息、营销信息、课程计划、课程教师信息
   * @param id
   */
    @ApiOperation("删除课程")
    @DeleteMapping("/course/{id}")
    public void removeCourseBase(@PathVariable Long id) {
      // TODO 获取用户所属机构id
      Long companyId = 1232141425L;
      courseBaseInfoService.deleteCourseBase(companyId, id);
    } 2.service开发

    /**
   * 删除课程:基本信息、营销信息、课程计划、课程教师信息
   * @param companyId 机构id
   * @param courseId 课程id
   */
    @Transactional
    @Override
    public void deleteCourseBase(Long companyId, Long courseId) {
      // 1.机构校验
      CourseBase courseBase = courseBaseMapper.selectById(courseId);
      if (courseBase == null) {
            XueChengPlusException.cast("课程不存在");
      }
      if (!companyId.equals(courseBase.getCompanyId())) {
            XueChengPlusException.cast("本机构只能操作本机构的课程");
      }

      // 2.删除基本信息
      courseBaseMapper.deleteById(courseId);

      // 3.删除对应的营销信息
      courseMarketMapper.deleteById(courseId);

      // 4.删除对应的所有课程计划
      LambdaQueryWrapper<Teachplan> teachplanWrapper = new LambdaQueryWrapper<>();
      teachplanWrapper = teachplanWrapper.eq(Teachplan::getCourseId, courseId);
      teachplanMapper.delete(teachplanWrapper);

      // 5.删除对应的课程教师信息
      LambdaQueryWrapper<CourseTeacher> courseTeacherWrapper = new LambdaQueryWrapper<>();
      courseTeacherWrapper = courseTeacherWrapper.eq(CourseTeacher::getCourseId, courseId);
      courseTeacherMapper.delete(courseTeacherWrapper);
    } 如果有必要改进的地方,请品评区留言哦

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 学成在线实战