401 lines
9.8 KiB
Markdown
401 lines
9.8 KiB
Markdown
# 用户导入班级验证优化说明
|
||
|
||
## 🎯 **需求说明**
|
||
|
||
### **用户要求**
|
||
1. ❌ 不要在导入前就报错中断
|
||
2. ✅ 优先完成导入任务
|
||
3. ✅ 遇到班级不存在的记录,跳过该条记录
|
||
4. ✅ 继续导入其他记录
|
||
5. ✅ 最后在导入结果中统一显示失败的记录和原因
|
||
|
||
---
|
||
|
||
## ✅ **实现方案**
|
||
|
||
### **方案:逐条验证 + 异常捕获**
|
||
|
||
#### **核心逻辑**
|
||
1. 在处理每个用户时,**在插入用户之前**验证班级是否存在
|
||
2. 如果班级不存在,抛出异常
|
||
3. 外层catch捕获异常,记录到失败信息中
|
||
4. 继续处理下一个用户
|
||
5. 最后统一显示导入结果
|
||
|
||
#### **为什么在插入前验证?**
|
||
- ✅ 避免用户已插入但班级分配失败
|
||
- ✅ 保证数据一致性
|
||
- ✅ 失败的用户不会被导入到系统
|
||
|
||
---
|
||
|
||
## 🔧 **修改内容**
|
||
|
||
### **修改1:移除Controller中的预验证**
|
||
|
||
**文件:** `StudyClassUserController.java`
|
||
|
||
**移除的代码:**
|
||
```java
|
||
// 预先验证所有班级是否存在
|
||
Set<String> uniqueClassNames = new HashSet<>();
|
||
// ... 收集班级名称
|
||
Map<String, Long> existingClasses = classUserService.getClassNameToIdMap();
|
||
// ... 检查班级
|
||
if (!missingClasses.isEmpty())
|
||
{
|
||
throw new ServiceException("导入失败:...");
|
||
}
|
||
```
|
||
|
||
**原因:** 不要在导入前就中断整个流程
|
||
|
||
---
|
||
|
||
### **修改2:添加逐条验证逻辑**
|
||
|
||
**文件:** `StudyClassUserServiceImpl.java`
|
||
|
||
**添加的代码:**
|
||
```java
|
||
// 预先验证班级是否存在(在插入/更新用户之前)
|
||
if (StringUtils.isNotEmpty(user.getRemark()))
|
||
{
|
||
String remark = user.getRemark();
|
||
int idx = remark.indexOf("班级名称:");
|
||
if (idx >= 0)
|
||
{
|
||
String className = remark.substring(idx + 5).trim();
|
||
if (StringUtils.isNotEmpty(className))
|
||
{
|
||
Long classId = classNameToIdMap.get(className);
|
||
if (classId == null)
|
||
{
|
||
// 班级不存在,抛出异常
|
||
throw new ServiceException("信息编号[" + infoNoStr + "]:班级 [" + className + "] 不存在,请先创建该班级");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 验证通过后,再插入/更新用户
|
||
SysUser u = userMapper.selectUserById(infoNo);
|
||
if (StringUtils.isNull(u))
|
||
{
|
||
// 插入用户
|
||
userMapper.insertUser(user);
|
||
// ... 分配班级
|
||
}
|
||
```
|
||
|
||
**关键点:**
|
||
- ✅ 验证在插入用户**之前**
|
||
- ✅ 如果班级不存在,用户不会被插入
|
||
- ✅ 异常会被外层catch捕获
|
||
|
||
---
|
||
|
||
### **修改3:优化异常处理**
|
||
|
||
**文件:** `StudyClassUserServiceImpl.java`
|
||
|
||
**班级分配失败时的异常:**
|
||
```java
|
||
else
|
||
{
|
||
// 班级不存在,抛出异常
|
||
throw new ServiceException("班级 [" + className + "] 不存在,请先创建该班级");
|
||
}
|
||
```
|
||
|
||
**作用:** 作为双重保险,防止遗漏
|
||
|
||
---
|
||
|
||
## 🔄 **完整流程**
|
||
|
||
### **导入流程图**
|
||
|
||
```
|
||
开始导入
|
||
↓
|
||
解析Excel(100条记录)
|
||
↓
|
||
开始逐条处理
|
||
↓
|
||
┌─────────────────────┐
|
||
│ 处理第1条:张三 │
|
||
│ 班级:一班 │
|
||
│ ↓ │
|
||
│ 验证班级是否存在 │
|
||
│ ✅ 一班存在 │
|
||
│ ↓ │
|
||
│ 插入用户 │
|
||
│ ↓ │
|
||
│ 分配班级 │
|
||
│ ↓ │
|
||
│ ✅ 导入成功 │
|
||
└─────────────────────┘
|
||
↓
|
||
┌─────────────────────┐
|
||
│ 处理第2条:李四 │
|
||
│ 班级:三班 │
|
||
│ ↓ │
|
||
│ 验证班级是否存在 │
|
||
│ ❌ 三班不存在 │
|
||
│ ↓ │
|
||
│ 抛出异常 │
|
||
│ ↓ │
|
||
│ catch捕获异常 │
|
||
│ ↓ │
|
||
│ 记录到errorMsg: │
|
||
│ "班级[三班]不存在" │
|
||
│ ↓ │
|
||
│ ❌ 导入失败 │
|
||
│ ❌ 用户未插入 │
|
||
└─────────────────────┘
|
||
↓
|
||
┌─────────────────────┐
|
||
│ 处理第3条:王五 │
|
||
│ 班级:二班 │
|
||
│ ↓ │
|
||
│ 验证班级是否存在 │
|
||
│ ✅ 二班存在 │
|
||
│ ↓ │
|
||
│ 插入用户 │
|
||
│ ↓ │
|
||
│ 分配班级 │
|
||
│ ↓ │
|
||
│ ✅ 导入成功 │
|
||
└─────────────────────┘
|
||
↓
|
||
... 继续处理其他记录 ...
|
||
↓
|
||
所有记录处理完成
|
||
↓
|
||
生成导入结果:
|
||
- 成功:2条
|
||
- 失败:1条
|
||
- 失败详情:
|
||
1、信息编号 1002,罪犯姓名 李四
|
||
失败原因:班级 [三班] 不存在,请先创建该班级
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 **导入结果示例**
|
||
|
||
### **示例1:部分失败**
|
||
|
||
**Excel数据:**
|
||
```
|
||
信息编号 | 姓名 | 监区 | 班级
|
||
1001 | 张三 | A区 | 一班
|
||
1002 | 李四 | B区 | 三班
|
||
1003 | 王五 | C区 | 二班
|
||
1004 | 赵六 | D区 | 四班
|
||
```
|
||
|
||
**数据库班级:** 一班、二班(没有三班、四班)
|
||
|
||
**导入结果:**
|
||
```
|
||
导入完成!
|
||
新增: 2 条
|
||
更新: 0 条
|
||
失败: 2 条
|
||
|
||
失败详情:
|
||
1、信息编号 1002,罪犯姓名 李四
|
||
失败原因:信息编号[1002]:班级 [三班] 不存在,请先创建该班级
|
||
|
||
2、信息编号 1004,罪犯姓名 赵六
|
||
失败原因:信息编号[1004]:班级 [四班] 不存在,请先创建该班级
|
||
```
|
||
|
||
**数据库结果:**
|
||
- ✅ 张三导入成功,分配到一班
|
||
- ❌ 李四导入失败,未插入数据库
|
||
- ✅ 王五导入成功,分配到二班
|
||
- ❌ 赵六导入失败,未插入数据库
|
||
|
||
---
|
||
|
||
### **示例2:全部成功**
|
||
|
||
**Excel数据:**
|
||
```
|
||
信息编号 | 姓名 | 监区 | 班级
|
||
1001 | 张三 | A区 | 一班
|
||
1002 | 李四 | B区 | 二班
|
||
```
|
||
|
||
**数据库班级:** 一班、二班
|
||
|
||
**导入结果:**
|
||
```
|
||
导入完成!
|
||
新增: 2 条
|
||
更新: 0 条
|
||
失败: 0 条
|
||
```
|
||
|
||
---
|
||
|
||
### **示例3:部分无班级**
|
||
|
||
**Excel数据:**
|
||
```
|
||
信息编号 | 姓名 | 监区 | 班级
|
||
1001 | 张三 | A区 | 一班
|
||
1002 | 李四 | B区 | (空)
|
||
1003 | 王五 | C区 | 三班
|
||
```
|
||
|
||
**数据库班级:** 一班、二班(没有三班)
|
||
|
||
**导入结果:**
|
||
```
|
||
导入完成!
|
||
新增: 2 条
|
||
更新: 0 条
|
||
失败: 1 条
|
||
|
||
失败详情:
|
||
1、信息编号 1003,罪犯姓名 王五
|
||
失败原因:信息编号[1003]:班级 [三班] 不存在,请先创建该班级
|
||
```
|
||
|
||
**数据库结果:**
|
||
- ✅ 张三导入成功,分配到一班
|
||
- ✅ 李四导入成功,不分配班级(班级为空不验证)
|
||
- ❌ 王五导入失败,未插入数据库
|
||
|
||
---
|
||
|
||
## ⚠️ **重要说明**
|
||
|
||
### **1. 验证时机**
|
||
- ✅ 在插入/更新用户**之前**验证班级
|
||
- ✅ 验证失败时,用户不会被插入/更新
|
||
- ✅ 保证数据一致性
|
||
|
||
### **2. 空班级处理**
|
||
- ✅ 班级为空时,不进行验证
|
||
- ✅ 用户可以导入成功,只是不分配班级
|
||
|
||
### **3. 异常处理**
|
||
- ✅ 每条记录的异常独立处理
|
||
- ✅ 一条记录失败不影响其他记录
|
||
- ✅ 所有失败记录统一显示
|
||
|
||
### **4. 错误信息格式**
|
||
```
|
||
信息编号[1002]:班级 [三班] 不存在,请先创建该班级
|
||
```
|
||
|
||
**包含信息:**
|
||
- 信息编号:方便定位是哪条记录
|
||
- 班级名称:明确哪个班级不存在
|
||
- 操作建议:提示用户先创建班级
|
||
|
||
---
|
||
|
||
## 🧪 **测试场景**
|
||
|
||
### **测试1:混合场景**
|
||
```
|
||
Excel:
|
||
- 张三 → 一班(存在)
|
||
- 李四 → 三班(不存在)
|
||
- 王五 → 二班(存在)
|
||
- 赵六 → 四班(不存在)
|
||
- 孙七 → (空)
|
||
|
||
预期结果:
|
||
✅ 张三导入成功
|
||
❌ 李四导入失败(班级不存在)
|
||
✅ 王五导入成功
|
||
❌ 赵六导入失败(班级不存在)
|
||
✅ 孙七导入成功(无班级)
|
||
|
||
统计:
|
||
- 成功:3条
|
||
- 失败:2条
|
||
- 失败详情列出李四和赵六
|
||
```
|
||
|
||
---
|
||
|
||
## 🚀 **部署步骤**
|
||
|
||
### **1. 重新编译后端**
|
||
```bash
|
||
cd C:\Users\Administrator\Desktop\Project\ry_study-v_03\Study-Vue-redis
|
||
mvn clean package -DskipTests
|
||
```
|
||
|
||
### **2. 重启后端服务**
|
||
|
||
### **3. 测试导入**
|
||
1. 创建"一班"和"二班"
|
||
2. 准备Excel,包含一班、二班、三班
|
||
3. 执行导入
|
||
4. 查看导入结果:
|
||
- ✅ 一班和二班的用户导入成功
|
||
- ❌ 三班的用户导入失败,显示错误信息
|
||
|
||
---
|
||
|
||
## 📋 **验收标准**
|
||
|
||
### **功能验收**
|
||
- [ ] 班级存在时,用户导入成功
|
||
- [ ] 班级不存在时,该用户导入失败
|
||
- [ ] 失败的用户不会被插入到数据库
|
||
- [ ] 一个用户失败不影响其他用户
|
||
- [ ] 导入结果显示成功数和失败数
|
||
- [ ] 失败详情包含信息编号、姓名和失败原因
|
||
- [ ] 班级为空时,用户可以导入成功
|
||
|
||
### **数据一致性验收**
|
||
- [ ] 失败的用户在sys_user表中不存在
|
||
- [ ] 失败的用户在student_class表中不存在
|
||
- [ ] 成功的用户正确分配到指定班级
|
||
- [ ] 没有"用户存在但班级未分配"的情况
|
||
|
||
### **用户体验验收**
|
||
- [ ] 导入过程不中断
|
||
- [ ] 导入结果一次性展示
|
||
- [ ] 错误信息清晰明确
|
||
- [ ] 可以根据错误信息快速定位问题
|
||
|
||
---
|
||
|
||
## 💡 **优化建议**
|
||
|
||
### **建议1:批量创建班级**
|
||
在导入结果中提供"创建缺失的班级"按钮,一键创建所有不存在的班级
|
||
|
||
### **建议2:Excel模板**
|
||
提供Excel模板下载,包含当前系统中所有班级的下拉列表
|
||
|
||
### **建议3:导入预检**
|
||
在上传Excel后、开始导入前,先显示预检结果(哪些班级不存在)
|
||
|
||
---
|
||
|
||
## ✅ **总结**
|
||
|
||
### **优化效果**
|
||
- ✅ 导入不会因个别记录失败而中断
|
||
- ✅ 成功的记录正常导入,失败的记录清晰展示
|
||
- ✅ 数据一致性得到保证
|
||
- ✅ 用户体验更友好
|
||
|
||
### **技术要点**
|
||
- 逐条验证而非批量验证
|
||
- 验证在插入之前而非之后
|
||
- 异常独立处理而非全局处理
|
||
- 结果统一展示而非即时报错
|