# 开发日志 2026-03-23 ## 班级名称唯一性校验 ### 问题描述 当前系统中,同一个租户下可以创建多个相同名称的班级,导致数据混乱和管理困难。 ### 需求 在新增和修改班级时,需要校验班级名称在同一租户下的唯一性。 ### 实现方案 #### 1. 修改文件 | 文件 | 修改内容 | |------|----------| | `reading-platform-java/src/main/java/com/reading/platform/service/impl/ClassServiceImpl.java` | 在 `createClass` 和 `updateClass` 方法中添加唯一性校验 | #### 2. 代码修改 **创建班级时校验**(`createClass` 方法): ```java // 检查班级名称是否唯一(MyBatis-Plus 会自动排除 deleted=1 的记录) LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Clazz::getTenantId, tenantId) .eq(Clazz::getName, request.getName()); Long count = clazzMapper.selectCount(wrapper); if (count > 0) { throw new BusinessException(ErrorCode.INVALID_PARAM, "该班级名称已存在"); } ``` **更新班级时校验**(`updateClass` 方法): ```java if (StringUtils.hasText(request.getName())) { // 检查班级名称是否唯一(排除当前班级和已删除) LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Clazz::getTenantId, clazz.getTenantId()) .eq(Clazz::getName, request.getName()) .ne(Clazz::getId, id); // 排除当前班级 Long count = clazzMapper.selectCount(wrapper); if (count > 0) { throw new BusinessException(ErrorCode.INVALID_PARAM, "该班级名称已存在"); } clazz.setName(request.getName()); } ``` ### 技术要点 1. **逻辑删除处理**: `Clazz` 实体继承 `BaseEntity`,包含 `deleted` 字段,MyBatis-Plus 的 `@TableLogic` 注解会在查询时自动添加 `deleted = 0` 条件 2. **唯一性校验范围**: 仅检查同一租户下的未删除记录 3. **错误提示**: 统一返回 "该班级名称已存在" 4. **错误码**: 使用 `ErrorCode.INVALID_PARAMETER`(参数校验错误,错误码 2004) ### 测试场景 - [x] 创建班级 "小一班" → 成功 - [x] 再次创建班级 "小一班"(同租户) → 应抛出异常 "该班级名称已存在" - [x] 删除 "小一班" 后,再次创建 "小一班" → 成功(因为原记录已删除) - [x] 更新班级,将名称改为已存在的名称 → 应抛出异常 - [x] 更新班级,名称不变 → 成功 - [x] 后端编译通过 ### 文件变更列表 | 文件 | 变更说明 | |------|---------| | `reading-platform-java/src/main/java/com/reading/platform/service/impl/ClassServiceImpl.java` | 在 `createClass` 和 `updateClass` 方法中添加唯一性校验逻辑 | --- **今日完成**: 班级名称唯一性校验、教师手机号唯一性校验 --- ## 教师手机号唯一性校验 ### 问题描述 在学校端教师管理中,新增和编辑教师时未对手机号唯一性进行校验,导致同一租户下不同教师可能使用相同的手机号。 ### 需求 - **新增教师**:检查手机号在当前租户下是否已存在 - **编辑教师**:检查手机号是否与当前租户下其他教师重复(排除自己) ### 实现方案 #### 修改文件 | 文件 | 修改内容 | |------|----------| | `TeacherServiceImpl.java` | 添加 `checkPhoneUnique` 方法,在 `createTeacher` 和 `updateTeacher` 中调用 | #### 代码修改 **新增手机号校验方法**: ```java /** * 检查手机号唯一性 */ private void checkPhoneUnique(Long tenantId, String phone, Long excludeTeacherId) { if (!StringUtils.hasText(phone)) { return; // 手机号为空时不校验(由 @NotBlank 校验) } LambdaQueryWrapper wrapper = new LambdaQueryWrapper() .eq(Teacher::getTenantId, tenantId) .eq(Teacher::getPhone, phone); // 编辑时排除当前教师 if (excludeTeacherId != null) { wrapper.ne(Teacher::getId, excludeTeacherId); } Teacher existing = teacherMapper.selectOne(wrapper); if (existing != null) { log.warn("手机号已存在,tenantId: {}, phone: {}", tenantId, phone); throw new BusinessException(ErrorCode.DATA_ALREADY_EXISTS, "手机号已存在"); } } ``` **createTeacher 方法**:在插入前调用校验 ```java // 检查手机号是否已存在 checkPhoneUnique(tenantId, request.getPhone(), null); ``` **updateTeacher 方法**:在更新前调用校验(排除当前教师) ```java // 检查手机号是否已存在(排除当前教师) checkPhoneUnique(teacher.getTenantId(), request.getPhone(), teacher.getId()); ``` ### 技术要点 1. **租户隔离**:校验时带上 `tenantId` 条件,确保不同租户之间数据隔离 2. **编辑排除逻辑**:使用 `ne` 条件排除当前教师 ID,避免自己修改自己时报错 3. **空值处理**:手机号为空时不校验(由 Controller 层的 `@NotBlank` 注解校验) 4. **错误码**:使用 `ErrorCode.DATA_ALREADY_EXISTS`(数据已存在) ### 测试场景 - [x] 创建教师使用手机号 13800138000 → 成功 - [x] 再次创建教师使用相同手机号 13800138000(同租户) → 应失败,提示"手机号已存在" - [x] 创建教师使用不同手机号 13800138001 → 成功 - [x] 编辑教师 A,不修改手机号 → 成功 - [x] 编辑教师 A,修改为教师 B 的手机号 → 应失败 - [x] 编辑教师 A,修改为未使用的手机号 → 成功 - [x] 租户 1 下已有手机号 13800138000,租户 2 下可以使用相同手机号 → 成功(租户隔离) - [x] 后端编译通过 ### 文件变更列表 | 文件 | 变更说明 | |------|---------| | `reading-platform-java/src/main/java/com/reading/platform/service/impl/TeacherServiceImpl.java` | 添加 `checkPhoneUnique` 方法,在 `createTeacher` 和 `updateTeacher` 中调用 |功能