学成在线实战

#1024程序员节|征文#

一、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 teachplanwhere parentid=#{parentId} and course_id=#{courseId}
</select>

(2)TeachplanServiceImpl

将原来的新增部分改为如下所示:

    /*** 新增/修改/保存课程计划* @param saveTeachplanDto 模型类*/@Overridepublic void saveTeachplan(SaveTeachplanDto saveTeachplanDto) {// 通过课程计划id判断是新增和修改Long teachplanId = saveTeachplanDto.getId();if (teachplanId == null) {// 新增Teachplan teachplan = new Teachplan();BeanUtils.copyProperties(saveTeachplanDto, teachplan);// 确定排序字段 - 找到同级节点个数,排序字段就是当前节点下的子节点数量加一 问题:当节点进行删除操作后,存在bugLong 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);// 将参数复制到teachplanBeanUtils.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@Overridepublic void removeTeachplan(Long id) {// 1.根据id查出teachplanTeachplan 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值交换,实现上下移动。

具体思路:

  1. 上移还是下移:首先在controller中调用service的时候,我们多传一个flag用于标记是向上移动还是向下移动。
  2. 边界值判断:上移:查询与当前teachplan同级的节点的orderBy的最大值,如果当前的teachplan的orderBy是最小值,那么它就是第一个,则无操作直接返回;下移同理(orderBy为最大值)。
  3. 找到与当前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@Overridepublic 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 teachplanwhere parentid=#{parentId} and course_id=#{courseId}</select><!-- 查询同一级节点中orderBy的最小值 --><select id="selectMinOrderBy" resultType="java.lang.Integer">select min(orderby)from teachplanwhere parentid=#{parentId} and course_id=#{courseId}</select>

五、师资管理

1.查询教师

1.1接口定义

根据响应结果的结构可知,返回值应为List<CourseTeacher> 

@Api(value = "课程计划教师编辑接口", tags = "课程计划教师编辑接口")
@RestController
public class CourseTeacherController {@Autowiredprivate 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>*/@Overridepublic 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 当前登录机构IDLong companyId = 1232141425L;return courseTeacherService.saveCourseTeacher(companyId, courseTeacher);}

2.2service开发

    /*** 新增/修改教师接口* @param courseTeacher 模型类* @return CourseTeacher*/@Overridepublic 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 当前登录机构IDLong companyId = 1232141425L;courseTeacherService.removeCourseTeacher(courseId, id, companyId);}

3.2service开发

    /*** 删除教师信息* @param courseId 课程id* @param id       教师id*/@Overridepublic 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 获取用户所属机构idLong companyId = 1232141425L;courseBaseInfoService.deleteCourseBase(companyId, id);}

2.service开发

    /*** 删除课程:基本信息、营销信息、课程计划、课程教师信息* @param companyId 机构id* @param courseId 课程id*/@Transactional@Overridepublic 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);}

如果有需要改进的地方,请评论区留言哦

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/57659.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PHP企业门店订货通进销存系统小程序源码

订货通进销存系统&#xff0c;企业运营好帮手&#xff01; &#x1f4e6; 开篇&#xff1a;告别繁琐&#xff0c;企业运营新选择 嘿&#xff0c;各位企业主和创业者们&#xff01;今天我要给大家介绍一款超实用的企业运营神器——“订货通进销存系统”。在这个数字化时代&…

YOLOv5_DeepSORT实现电动自行车头盔佩戴检测系统

获取更多完整项目代码数据集&#xff0c;点此加入免费社区群 &#xff1a; 首页-置顶必看 文档说明 本文档是毕业设计——基于深度学习的电动自行车头盔佩戴检测系统的开发环境配置说明文档&#xff0c;该文档包括运行环境说明以及基本环境配置两大部分。在程序运行前请认真查…

零售行业的数字化营销转型之路

一方面&#xff0c;市场竞争激烈&#xff0c;电商平台、新兴品牌和跨界对手带来巨大压力。另一方面&#xff0c;消费者需求变化迅速&#xff0c;更加追求个性化、多元化和便捷化的购物体验&#xff0c;同时传统零售企业还面临着高成本压力&#xff0c;如租金、人力和库存等。 然…

Rsync数据复制/备份服务应用

文章目录 1. rsync概述1.1 什么是Rsync1.2 rsync的功能1.3 rsync 的功能特性1.4 Rsync 增量复制原理1.5 生产场景架构集群备份方案 2. Rsync工作方式介绍与实践2.1 本地数据传输模式2.1.1 本地数据传输模式语法2.1.2 本地数据传输模式实践 2.2 远程Shell 数据传输模式2.2.1 远程…

数据结构练习题5(链表和栈)

1环形链表 II 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测…

全面指南:中国人工智能大模型技术创新与应用

近期&#xff0c;中国人工智能协会发布了《中国人工智能大模型技术白皮书》&#xff0c;涵盖了大模型发展历程、关键技术、困难及挑战以及未来发展的展望。 在此本文总结了下白皮书的主要内容&#xff0c;并附上白皮书~ 目录第 1 章 大模型技术概述 ........................…

基础数据结构——队列(双端队列,优先级队列,阻塞队列)

双端队列、队列、栈对比 定义特点队列一端删除&#xff08;头&#xff09;另一端添加&#xff08;尾&#xff09;First In First Out栈一端删除和添加&#xff08;顶&#xff09;Last In First Out双端队列两端都可以删除、添加优先级队列优先级高者先出队延时队列根据延时时间…

微信小程序地图功能开发:绘制多边形和标记点

在微信小程序中&#xff0c;地图功能是一个常见的需求&#xff0c;尤其是在需要展示地理位置、导航指引或区域覆盖的应用中。本文将通过一个实际的微信小程序地图组件示例&#xff0c;介绍如何在地图上绘制多边形区域和标记点&#xff0c;以及如何响应用户的点击事件。 项目背景…

V2X介绍

文章目录 什么是V2XV2X的发展史早期的DSRC后起之秀C-V2XC-V2X 和DSRC 两者的对比 什么是V2X 所谓V2X&#xff0c;与流行的B2B、B2C如出一辙&#xff0c;意为vehicle to everything&#xff0c;即车对外界的信息交换。车联网通过整合全球定位系统&#xff08;GPS&#xff09;导…

实操 maxkey对接三方文档

实操 maxkey 对接三方文档 概述前置准备&#xff1a;MaxKey 安装与配置&#xff1a;第三方系统准备网络环境 对接三方配置oauth2协议对接导入jar包&#xff08;调接口&#xff09;权限加回调重定向获取token处理业务 api对接三方获取api凭证配置 MaxKey更新代码 概述 最近在搞m…

【华为HCIP实战课程十六】OSPF虚链路Vlink,网络工程师

一、vlink续 区域内部的路由优于区域之间的路由,区域之间优于外部路由,外部路由类型1优于外部类型2 只有同一级别的路由才会对比cost <R3>tracert 11.1.1.1 traceroute to 11.1.1.1(11.1.1.1), max hops: 30 ,packet length: 40,press CTRL_C to break 1 10.1.35.5 …

three融合GIS创建地球模型(二)

创建一个地球模型通常涉及到使用纹理贴图来给球体添加地球表面的图像。在 Three.js 中&#xff0c;你可以通过加载一张地球的图片作为纹理&#xff0c;并将其应用到一个 SphereGeometry 上来实现这一点。以下是如何完成这个过程的一个基本示例&#xff1a; 步骤 1: 设置场景、…

rust入门基础总结

文章目录 前言1、输出格式规范一、占位符相关&#xff08;一&#xff09;{}与{:?} 二、参数替换方式&#xff08;一&#xff09;位置参数&#xff08;二&#xff09;具名参数 三、格式化参数&#xff08;一&#xff09;宽度&#xff08;二&#xff09;对齐&#xff08;三&…

php生成PDF文件(FPDF)

FPDF即“Free PDF”&#xff0c;FPDF类库提供了基本的PDF创建功能&#xff0c;其源代码和使用权是免费的。 PDF格式文档优势 通用&#xff1a;PDF文档在UNIX和Windows系统均可正常使用。 安全&#xff1a;PDF文档可设置为只读模式&#xff0c;并且可以添加密码等保护措施。 美…

【JDK、Maven、Git、PostgreSQL】VSCode后端开发环境配置样例

文章目录 一、文件下载1 Maven早期版本下载安装1.1 文件下载1.2 设置系统变量1.3 查看是否设置成功1.4 设置MAVEN的本地仓库 和 镜像等内容 2 Git 下载安装3 下载并安装PostgreSQL 103.1 下载并安装3.2 配置系统环境变量 4 在VScode中下载扩展包5 在VSCode中为项目配置JDK 二、…

Maven 的使用:在 IDEA 中配置 Maven 的超详细步骤

一、概述 记录时间 [2024-10-20] Maven 用来管理 Java 项目中的依赖。 为什么要进行 Maven 配置呢&#xff1f;IDEA 默认选择内置的 Maven 仓库&#xff0c;但是不好用。 本文所讲述的 Maven 配置可以说是超详细的&#xff01; 从下载 Maven 这个东西开始&#xff0c;修改它…

sql-labs靶场第十七关测试报告

目录 一、测试环境 1、系统环境 2、使用工具/软件 二、测试目的 三、操作过程 1、寻找注入点 2、注入数据库 ①寻找注入方法 ②爆库&#xff0c;查看数据库名称 ③爆表&#xff0c;查看security库的所有表 ④爆列&#xff0c;查看users表的所有列 ⑤成功获取用户名…

基于微信小程序的智能校园社区服务推荐系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

华为eNSP:端口安全

一、什么是端口安全 端口安全是指保护计算机端口免受未经授权的访问、攻击或滥用的一种措施。计算机上的每个服务或应用程序都依靠特定的端口进行通信。端口安全的目的是限制对计算机端口的访问&#xff0c;确保只有经过授权的用户或服务可以使用这些端口。通过配置防火墙、访…

影刀RPA实战番外:excel函数应用指南

Excel函数是用于执行特定计算、分析和数据处理任务的预定义公式。它们可处理数学计算、文本处理、逻辑判断、日期和时间运算、查找和引用数据等。例如&#xff0c;SUM函数可以计算一系列数字的总和&#xff0c;IF函数进行逻辑测试&#xff0c;VLOOKUP函数在表格中查找数据&…