★ 手术训练系统项目
项目描述:手术训练系统,它提供了多项功能,包括账户登录与创建、数据库与账户管理、课程管理、小组管理、成绩统计、证书发布、训练和系统设置。
职责描述:
1、训练功能开发(任务概述、任务指导、评分规则、评分成绩)。
2、课程管理功能(CRUD课程、为课程分配任务、设置评分规则)。
3、数据库设计。
我参与开发的项目是一个手术训练系统,它提供了多项功能,包括账户登录与创建、数据库与账户管理、课程管理、小组管理、成绩统计、证书发布、训练和系统设置。我的主要负责领域是训练功能和课程管理功能。
训练功能:我负责开发系统中的训练模块。其中的主要难点之一是展示当前课程的级别-训练树,这需要将课程结构以树形式展示,并与训练任务进行关联。我成功地实现了这一功能,使用户能够轻松地浏览和选择适合他们的训练任务。
课程管理功能:我还负责课程管理模块的开发。这包括创建新的课程和管理已有课程。用户可以定义课程的基本属性,如名称、尝试次数和评论。这个模块的开发也与训练任务的创建和关联密切相关,确保了系统的一致性和流畅性。
数据库设计:
在项目中,我们使用了一种具有表层级的数据库结构,其中主要的表是course、block和task,以及一个名为exercise的训练池表。为了管理多种评分标准,我们还创建了task_metrics_configuration表,负责12种维度的评分标准。这种设计将任务、评分标准名称和评分标准属性合理地组织在一起。
1、面对到任务id-评分标准名称-评分标准内容三个维度的情况,如下图所示,为了减少多对多关系表的复杂性,我们采用了一种巧妙的设计,将任务ID、左手器械的最小值、最大值、状态和权重等信息存储在同一表中,以逻辑的整合换取了数据库表结构的简洁性,提高了系统的性能和可维护性。
2、导出到本地需要配置虚拟路径方法
public class SaTokenConfigure implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 配置虚拟地址 "/video/**" 映射到实际视频文件路径
registry.addResourceHandler("/virtual/**")
.addResourceLocations("file:///" + RESOURCE_PATH)
.resourceChain(true)
.addResolver(new DebugResourceResolver());
}
}
核心难点:
3、如下图所示,左边可选训练任务是exercise(及其配置表)、中间已分配训练任务是block与task表(及其配置表),那么这棵树能够新增同级、新增子级,还能随意地复制任意结点、删除结点,由于每个训练用户还能自定义配置任务时长限制、可尝试次数、任务评分规则配置等信息,所以能预见到推论1:如果需要新增训练时,需要从exercise表中复制,而复制训练时,需要从task及其配置表中复制。
推论2:前端不会每次新增操作了给你传过来、复制操作给你传过来数据、删除操作给你传过来数据,因为前端对用户操作是无感知的,这也就意味着你在执行编辑当前课程的逻辑时,只能拿到你之前的这棵树的逻辑和前端传过来的之后修改后的这棵树的逻辑。
我与前端有如下约定:
1、exerciseId区分block与task
2、id区分是新增结点还是复制的结点
实现步骤思想:
1、清理数据结构。
2、为没有ID的子节点设置唯一的ID。
3、处理可能存在的重复ID的情况,以确保每个节点都有唯一的ID。
4、为树的每个节点设置parentId。
5、解析前端传递的参数,生成树节点列表。
6、删除与特定课程ID相关的数据库中的信息。
7、根据节点类型将节点分为任务(Task)和块(Block)。
8、将任务(Task)节点插入到任务表中。
8、将块(Block)节点插入到块表中,并关联它们到特定课程。
10、返回更新后的课程树数据。
@PostMapping("updateDirectoryTree2")
public CommonResult updateDirectoryTree2(@RequestBody UpdateDirectoryTreeDto updateDirectoryTreeDto) {
//清理
treeNodeList = new ArrayList<>();
idCountMap = new HashMap<>();
//为没有id的子节点设置唯一的id
setUniqueIdsIfNotNull(updateDirectoryTreeDto.getList());
//TODO 新增的结点是没有id的,updateDirectoryTreeDto.getList()有id重复的时候说明有复制的id,需要进行重新赋予id的操作,同时需要将配置表的信息也连带复制过来
handleDuplicateIds(updateDirectoryTreeDto.getList());
//为树的每个节点设置parentId
setParentIds(updateDirectoryTreeDto.getList(), null);
//前端传的参数解析
setTreeNode(updateDirectoryTreeDto.getList());
System.out.println("treeNodeList:" + treeNodeList);
//删除与该课程id相关的block和task表中信息
taskService.deleteTaskByCourseId(updateDirectoryTreeDto.getCourseId());
blockService.deleteBlockByCourseId(updateDirectoryTreeDto.getCourseId());
List<TreeNode> taskList = new ArrayList<>();
List<TreeNode> blockList = new ArrayList<>();
for (TreeNode node : treeNodeList) {
if (node.getExerciseId() != null && !node.getExerciseId().isEmpty()) {
taskList.add(node);
} else {
blockList.add(node);
}
}
// 打印结果
taskService.insertTask(taskList);
blockService.insertBlock(blockList, updateDirectoryTreeDto.getCourseId());
return CommonResult.success(blockService.getDataTreeByCourseId(updateDirectoryTreeDto.getCourseId()));
}
1、考虑权限@SaCheckRole(value = {RoleConstants.ROLE_STUDENT, RoleConstants.ROLE_GUEST}, mode = SaMode.OR)
2、@MapperScan不要加到@SpringBootApplication,加到MybatisPlusConfig ,否则扫描包时会有异常情况。
@Configuration
@MapperScan("com.wego.training.mapper")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
3、碰到枚举的情况,至少要设置一个constants类,并加上必要的注释,否则就会与同事逻辑不一致,也便于以后修改枚举值
package com.wego.training.constant;
/**
* @author lst
* @date 2023年10月18日 10:27
*/
public class CourseConstants {
/**
* 课程私有的
*
* @author lst
* @date 2023/10/18 10:28
* @param null
* @return null
*/
public static final int COURSE_PRIVATE = 0;
/**
* 课程公开的
*
* @author lst
* @date 2023/10/18 10:28
* @param null
* @return null
*/
public static final int COURSE_PUBLIC = 1;
/**
* 课程同组的
*
* @author lst
* @date 2023/10/18 10:28
* @param null
* @return null
*/
public static final int COURSE_GROUP = 2;
}
总结:
在这个项目中,我承担了训练功能和课程管理功能的开发任务,并成功应对了展示课程结构、任务评分和数据库设计等关键挑战。我的工作使项目能够提供用户友好的手术训练体验,并确保了系统的高性能和可维护性。