diff --git a/API文档.md b/API文档.md
index 475207d..78005d9 100644
--- a/API文档.md
+++ b/API文档.md
@@ -545,9 +545,101 @@
}
```
+## 批量导入接口
+
+### 1. 批量导入用户
+
+- **接口**:`POST /api/import/users`
+- **描述**:通过 Excel 文件批量导入用户
+- **认证**:需要
+- **请求体**:
+ - `Content-Type`: `multipart/form-data`
+ - `file`: Excel 文件(.xlsx)
+- **Excel 文件格式**:
+ | 用户名 | 邮箱 | 密码 | 部门名称 |
+ |--------|------|------|----------|
+ | 张三 | zhangsan@example.com | 123456 | 技术部 |
+- **成功响应**:
+ ```json
+ {
+ "code": 10000,
+ "message": "成功",
+ "data": "成功导入2条数据"
+ }
+ ```
+- **错误响应**:
+ ```json
+ {
+ "code": 10012,
+ "message": "成功导入0条数据。错误信息:第2行邮箱已存在;第3行部门不存在;",
+ "data": null
+ }
+ ```
+
+### 2. 批量导入课程任务
+
+- **接口**:`POST /api/import/lesson-tasks`
+- **描述**:通过 Excel 文件批量导入课程任务
+- **认证**:需要
+- **请求体**:
+ - `Content-Type`: `multipart/form-data`
+ - `file`: Excel 文件(.xlsx)
+- **Excel 文件格式**:
+ | 课程名称 | 微课名称 | 教师邮箱 |
+ |----------|----------|-----------|
+ | 数学课程 | 第一章 | teacher@example.com |
+- **成功响应**:
+ ```json
+ {
+ "code": 10000,
+ "message": "成功",
+ "data": "成功导入3条数据"
+ }
+ ```
+- **错误响应**:
+ ```json
+ {
+ "code": 10012,
+ "message": "成功导入0条数据。错误信息:第2行未找到教师用户(teacher@example.com);",
+ "data": null
+ }
+ ```
+
+### 3. 批量导入部门
+
+- **接口**:`POST /api/import/departments`
+- **描述**:通过 Excel 文件批量导入部门
+- **认证**:需要
+- **请求体**:
+ - `Content-Type`: `multipart/form-data`
+ - `file`: Excel 文件(.xlsx)
+- **Excel 文件格式**:
+ | 部门名称 | 部门描述 |
+ |----------|----------|
+ | 技术部 | 负责技术研发 |
+- **成功响应**:
+ ```json
+ {
+ "code": 10000,
+ "message": "成功",
+ "data": "成功导入2条数据"
+ }
+ ```
+- **错误响应**:
+ ```json
+ {
+ "code": 10012,
+ "message": "成功导入0条数据。错误信息:第2行部门名称已存在;",
+ "data": null
+ }
+ ```
+
## 注意事项
1. 所有时间戳字段均使用秒级时间戳(10 位)
2. 课程任务状态变更时会自动记录相应的时间戳
3. 部门课程任务列表会额外返回用户名信息
4. 分页参数中的页码从 1 开始
+5. 批量导入时,Excel 文件必须严格按照模板格式填写
+6. 批量导入时,如果某行数据导入失败,会在返回信息中说明具体原因
+7. 批量导入时,如果全部数据导入失败,会返回错误状态码(10012)
diff --git a/pom.xml b/pom.xml
index 3360fa9..fad92c4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -92,6 +92,19 @@
org.apache.commons
commons-pool2
+
+
+ com.alibaba
+ easyexcel
+ 3.3.2
+
+
+
+
+ org.apache.commons
+ commons-lang3
+ 3.12.0
+
diff --git a/src/main/java/com/huertian/jinduguanli/common/ErrorCode.java b/src/main/java/com/huertian/jinduguanli/common/ErrorCode.java
index e0e1486..3894d0c 100644
--- a/src/main/java/com/huertian/jinduguanli/common/ErrorCode.java
+++ b/src/main/java/com/huertian/jinduguanli/common/ErrorCode.java
@@ -1,14 +1,68 @@
package com.huertian.jinduguanli.common;
public class ErrorCode {
+ /**
+ * 操作成功
+ */
public static final int SUCCESS = 10000;
+
+ /**
+ * 系统内部错误
+ */
public static final int SYSTEM_ERROR = 10001;
+
+ /**
+ * 参数校验错误
+ */
public static final int INVALID_PARAM = 10002;
+
+ /**
+ * 用户不存在
+ */
public static final int USER_NOT_FOUND = 10003;
+
+ /**
+ * 用户不存在或已被禁用
+ */
public static final int USER_NOT_FOUND_OR_DISABLED = 10004;
+
+ /**
+ * 邮箱已存在
+ */
public static final int EMAIL_EXISTS = 10005;
- public static final int PASSWORD_INCORRECT = 10006;
+
+ /**
+ * 业务逻辑错误
+ */
+ public static final int BUSINESS_ERROR = 10006;
+
+ /**
+ * 无效的令牌
+ */
public static final int INVALID_TOKEN = 10007;
+
+ /**
+ * 未授权访问
+ */
public static final int UNAUTHORIZED = 10008;
+
+ /**
+ * 用户名已存在
+ */
public static final int USERNAME_EXISTS = 10009;
+
+ /**
+ * 密码错误
+ */
+ public static final int PASSWORD_INCORRECT = 10010;
+
+ /**
+ * 参数为空
+ */
+ public static final int PARAM_IS_BLANK = 10011;
+
+ /**
+ * 参数错误
+ */
+ public static final int PARAM_ERROR = 10012;
}
diff --git a/src/main/java/com/huertian/jinduguanli/controller/ImportController.java b/src/main/java/com/huertian/jinduguanli/controller/ImportController.java
new file mode 100644
index 0000000..85412ef
--- /dev/null
+++ b/src/main/java/com/huertian/jinduguanli/controller/ImportController.java
@@ -0,0 +1,130 @@
+package com.huertian.jinduguanli.controller;
+
+import com.alibaba.excel.EasyExcel;
+import com.huertian.jinduguanli.common.ApiResponse;
+import com.huertian.jinduguanli.common.ErrorCode;
+import com.huertian.jinduguanli.dto.DepartmentImportDTO;
+import com.huertian.jinduguanli.dto.LessonTaskImportDTO;
+import com.huertian.jinduguanli.dto.UserImportDTO;
+import com.huertian.jinduguanli.service.DepartmentService;
+import com.huertian.jinduguanli.service.LessonTaskService;
+import com.huertian.jinduguanli.service.UserService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+@Slf4j
+@RestController
+@RequestMapping("/api/import")
+public class ImportController {
+
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private LessonTaskService lessonTaskService;
+
+ @Autowired
+ private DepartmentService departmentService;
+
+ @PostMapping("/users")
+ public ApiResponse importUsers(@RequestParam("file") MultipartFile file) {
+ if (file.isEmpty()) {
+ return new ApiResponse<>(ErrorCode.INVALID_PARAM, "文件不能为空", null);
+ }
+
+ String originalFilename = file.getOriginalFilename();
+ if (!isValidExcelFile(originalFilename)) {
+ return new ApiResponse<>(ErrorCode.INVALID_PARAM, "只支持.xlsx格式的文件", null);
+ }
+
+ try {
+ log.info("开始导入用户数据,文件名:{}", originalFilename);
+ List userList = EasyExcel.read(file.getInputStream())
+ .head(UserImportDTO.class)
+ .sheet()
+ .doReadSync();
+ log.info("读取到{}条用户数据", userList.size());
+
+ for (int i = 0; i < userList.size(); i++) {
+ log.info("第{}行数据:{}", i + 1, userList.get(i));
+ }
+
+ return userService.batchImportUsers(userList);
+ } catch (Exception e) {
+ log.error("导入用户数据失败", e);
+ return new ApiResponse<>(ErrorCode.SYSTEM_ERROR, "导入用户数据失败:" + e.getMessage(), null);
+ }
+ }
+
+ @PostMapping("/lesson-tasks")
+ public ApiResponse importLessonTasks(@RequestParam("file") MultipartFile file) {
+ if (file.isEmpty()) {
+ return new ApiResponse<>(ErrorCode.INVALID_PARAM, "文件不能为空", null);
+ }
+
+ String originalFilename = file.getOriginalFilename();
+ if (!isValidExcelFile(originalFilename)) {
+ return new ApiResponse<>(ErrorCode.INVALID_PARAM, "只支持.xlsx格式的文件", null);
+ }
+
+ try {
+ log.info("开始导入课程任务数据,文件名:{}", originalFilename);
+ List taskList = EasyExcel.read(file.getInputStream())
+ .head(LessonTaskImportDTO.class)
+ .sheet()
+ .doReadSync();
+ log.info("读取到{}条课程任务数据", taskList.size());
+
+ for (int i = 0; i < taskList.size(); i++) {
+ log.info("第{}行数据:{}", i + 1, taskList.get(i));
+ }
+
+ return lessonTaskService.batchImportLessonTasks(taskList);
+ } catch (Exception e) {
+ log.error("导入课程任务数据失败", e);
+ return new ApiResponse<>(ErrorCode.SYSTEM_ERROR, "导入课程任务数据失败:" + e.getMessage(), null);
+ }
+ }
+
+ @PostMapping("/departments")
+ public ApiResponse importDepartments(@RequestParam("file") MultipartFile file) {
+ if (file.isEmpty()) {
+ return new ApiResponse<>(ErrorCode.INVALID_PARAM, "文件不能为空", null);
+ }
+
+ String originalFilename = file.getOriginalFilename();
+ if (!isValidExcelFile(originalFilename)) {
+ return new ApiResponse<>(ErrorCode.INVALID_PARAM, "只支持.xlsx格式的文件", null);
+ }
+
+ try {
+ log.info("开始导入部门数据,文件名:{}", originalFilename);
+ List departmentList = EasyExcel.read(file.getInputStream())
+ .head(DepartmentImportDTO.class)
+ .sheet()
+ .doReadSync();
+ log.info("读取到{}条部门数据", departmentList.size());
+
+ for (int i = 0; i < departmentList.size(); i++) {
+ log.info("第{}行数据:{}", i + 1, departmentList.get(i));
+ }
+
+ return departmentService.batchImportDepartments(departmentList);
+ } catch (Exception e) {
+ log.error("导入部门数据失败", e);
+ return new ApiResponse<>(ErrorCode.SYSTEM_ERROR, "导入部门数据失败:" + e.getMessage(), null);
+ }
+ }
+
+ private boolean isValidExcelFile(String filename) {
+ return StringUtils.isNotBlank(filename) && filename.toLowerCase().endsWith(".xlsx");
+ }
+}
diff --git a/src/main/java/com/huertian/jinduguanli/dto/DepartmentImportDTO.java b/src/main/java/com/huertian/jinduguanli/dto/DepartmentImportDTO.java
new file mode 100644
index 0000000..fa0be18
--- /dev/null
+++ b/src/main/java/com/huertian/jinduguanli/dto/DepartmentImportDTO.java
@@ -0,0 +1,30 @@
+package com.huertian.jinduguanli.dto;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+
+
+public class DepartmentImportDTO {
+ @ExcelProperty("部门名称")
+ private String departmentName;
+
+ @ExcelProperty("部门描述")
+ private String description;
+
+ public String getDepartmentName() {
+ return departmentName;
+ }
+
+ public void setDepartmentName(String departmentName) {
+ this.departmentName = departmentName;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+}
diff --git a/src/main/java/com/huertian/jinduguanli/dto/LessonTaskImportDTO.java b/src/main/java/com/huertian/jinduguanli/dto/LessonTaskImportDTO.java
new file mode 100644
index 0000000..0e69dfe
--- /dev/null
+++ b/src/main/java/com/huertian/jinduguanli/dto/LessonTaskImportDTO.java
@@ -0,0 +1,39 @@
+package com.huertian.jinduguanli.dto;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+
+public class LessonTaskImportDTO {
+ @ExcelProperty("课程名称")
+ private String lessonName;
+
+ @ExcelProperty("微课名称")
+ private String microLessonName;
+
+ @ExcelProperty("教师账号")
+ private String teacherEmail;
+
+ public String getLessonName() {
+ return lessonName;
+ }
+
+ public void setLessonName(String lessonName) {
+ this.lessonName = lessonName;
+ }
+
+ public String getMicroLessonName() {
+ return microLessonName;
+ }
+
+ public void setMicroLessonName(String microLessonName) {
+ this.microLessonName = microLessonName;
+ }
+
+ public String getTeacherEmail() {
+ return teacherEmail;
+ }
+
+ public void setTeacherEmail(String teacherEmail) {
+ this.teacherEmail = teacherEmail;
+ }
+}
diff --git a/src/main/java/com/huertian/jinduguanli/dto/UserImportDTO.java b/src/main/java/com/huertian/jinduguanli/dto/UserImportDTO.java
new file mode 100644
index 0000000..3bc17f9
--- /dev/null
+++ b/src/main/java/com/huertian/jinduguanli/dto/UserImportDTO.java
@@ -0,0 +1,61 @@
+package com.huertian.jinduguanli.dto;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+
+public class UserImportDTO {
+ @ExcelProperty(index = 0)
+ private String username;
+
+ @ExcelProperty(index = 1)
+ private String email;
+
+ @ExcelProperty(index = 2)
+ private String password;
+
+ @ExcelProperty(index = 3)
+ private String departmentName;
+
+ @ExcelProperty(index = 4)
+ private String roleAndJob;
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getDepartmentName() {
+ return departmentName;
+ }
+
+ public void setDepartmentName(String departmentName) {
+ this.departmentName = departmentName;
+ }
+
+ public String getRoleAndJob() {
+ return roleAndJob;
+ }
+
+ public void setRoleAndJob(String roleAndJob) {
+ this.roleAndJob = roleAndJob;
+ }
+}
diff --git a/src/main/java/com/huertian/jinduguanli/entity/Department.java b/src/main/java/com/huertian/jinduguanli/entity/Department.java
new file mode 100644
index 0000000..7e68baf
--- /dev/null
+++ b/src/main/java/com/huertian/jinduguanli/entity/Department.java
@@ -0,0 +1,22 @@
+package com.huertian.jinduguanli.entity;
+
+import jakarta.persistence.*;
+import lombok.Data;
+
+@Data
+@Entity
+@Table(name = "departments")
+public class Department {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Column(unique = true)
+ private String name;
+
+ private String description;
+
+ private Long createdAt;
+
+ private Long updatedAt;
+}
diff --git a/src/main/java/com/huertian/jinduguanli/repository/DepartmentRepository.java b/src/main/java/com/huertian/jinduguanli/repository/DepartmentRepository.java
new file mode 100644
index 0000000..c4fb4d7
--- /dev/null
+++ b/src/main/java/com/huertian/jinduguanli/repository/DepartmentRepository.java
@@ -0,0 +1,8 @@
+package com.huertian.jinduguanli.repository;
+
+import com.huertian.jinduguanli.entity.Department;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface DepartmentRepository extends JpaRepository {
+ Department findByName(String name);
+}
diff --git a/src/main/java/com/huertian/jinduguanli/service/DepartmentService.java b/src/main/java/com/huertian/jinduguanli/service/DepartmentService.java
new file mode 100644
index 0000000..c2611d4
--- /dev/null
+++ b/src/main/java/com/huertian/jinduguanli/service/DepartmentService.java
@@ -0,0 +1,76 @@
+package com.huertian.jinduguanli.service;
+
+import com.huertian.jinduguanli.common.ApiResponse;
+import com.huertian.jinduguanli.common.ErrorCode;
+import com.huertian.jinduguanli.dto.DepartmentImportDTO;
+import com.huertian.jinduguanli.entity.Department;
+import com.huertian.jinduguanli.repository.DepartmentRepository;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class DepartmentService {
+ private static final Logger logger = LoggerFactory.getLogger(DepartmentService.class);
+ private final DepartmentRepository departmentRepository;
+
+ @Autowired
+ public DepartmentService(DepartmentRepository departmentRepository) {
+ this.departmentRepository = departmentRepository;
+ }
+
+ public ApiResponse batchImportDepartments(List departmentList) {
+ if (departmentList == null || departmentList.isEmpty()) {
+ return new ApiResponse<>(ErrorCode.PARAM_ERROR, "导入数据不能为空", null);
+ }
+
+ StringBuilder errorMsg = new StringBuilder();
+ int successCount = 0;
+
+ for (int i = 0; i < departmentList.size(); i++) {
+ DepartmentImportDTO dto = departmentList.get(i);
+ try {
+ // 基本数据验证
+ if (StringUtils.isBlank(dto.getDepartmentName())) {
+ errorMsg.append(String.format("第%d行部门名称不能为空;", i + 2));
+ continue;
+ }
+
+ // 检查部门名称是否已存在
+ if (departmentRepository.findByName(dto.getDepartmentName()) != null) {
+ errorMsg.append(String.format("第%d行部门名称已存在;", i + 2));
+ continue;
+ }
+
+ // 创建部门
+ Department department = new Department();
+ department.setName(dto.getDepartmentName());
+ department.setDescription(dto.getDescription());
+ department.setCreatedAt(System.currentTimeMillis() / 1000);
+ department.setUpdatedAt(System.currentTimeMillis() / 1000);
+
+ departmentRepository.save(department);
+ successCount++;
+ } catch (Exception e) {
+ logger.error("导入第{}行数据失败", i + 2, e);
+ errorMsg.append(String.format("第%d行导入失败;", i + 2));
+ }
+ }
+
+ String resultMsg = String.format("成功导入%d条数据", successCount);
+ if (errorMsg.length() > 0) {
+ resultMsg += "。错误信息:" + errorMsg;
+ }
+
+ // 如果没有成功导入任何数据,返回错误状态
+ if (successCount == 0) {
+ return new ApiResponse<>(ErrorCode.PARAM_ERROR, resultMsg, null);
+ }
+
+ return ApiResponse.success(resultMsg);
+ }
+}
diff --git a/src/main/java/com/huertian/jinduguanli/service/LessonTaskService.java b/src/main/java/com/huertian/jinduguanli/service/LessonTaskService.java
index 368152d..25af6a6 100644
--- a/src/main/java/com/huertian/jinduguanli/service/LessonTaskService.java
+++ b/src/main/java/com/huertian/jinduguanli/service/LessonTaskService.java
@@ -1,8 +1,12 @@
package com.huertian.jinduguanli.service;
+import com.huertian.jinduguanli.common.ApiResponse;
+import com.huertian.jinduguanli.common.ErrorCode;
import com.huertian.jinduguanli.dto.LessonTaskDTO;
+import com.huertian.jinduguanli.dto.LessonTaskImportDTO;
import com.huertian.jinduguanli.dto.LessonTaskRequest;
import com.huertian.jinduguanli.entity.LessonTask;
+import com.huertian.jinduguanli.entity.User;
import com.huertian.jinduguanli.repository.LessonTaskRepository;
import jakarta.persistence.EntityNotFoundException;
import org.slf4j.Logger;
@@ -15,13 +19,20 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.BeanUtils;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+
@Service
public class LessonTaskService {
private static final Logger logger = LoggerFactory.getLogger(LessonTaskService.class);
private final LessonTaskRepository lessonTaskRepository;
+ private final UserService userService; // 添加 UserService 的依赖
- public LessonTaskService(LessonTaskRepository lessonTaskRepository) {
+ public LessonTaskService(LessonTaskRepository lessonTaskRepository, UserService userService) {
this.lessonTaskRepository = lessonTaskRepository;
+ this.userService = userService;
}
@Cacheable(value = "lessonTasks", key = "#userId != null ? 'user:' + #userId + ':page:' + #pageable.pageNumber : 'all:page:' + #pageable.pageNumber")
@@ -192,6 +203,74 @@ public class LessonTaskService {
return lessonTaskRepository.findByDepartmentIdAndUserStatus(departmentId, userStatus, pageable);
}
+ @Transactional
+ public ApiResponse batchImportLessonTasks(List taskList) {
+ if (taskList == null || taskList.isEmpty()) {
+ logger.error("导入任务列表为空");
+ return new ApiResponse<>(ErrorCode.PARAM_IS_BLANK, "导入任务列表为空", null);
+ }
+
+ StringBuilder errorMsg = new StringBuilder();
+ int successCount = 0;
+
+ for (int i = 0; i < taskList.size(); i++) {
+ LessonTaskImportDTO dto = taskList.get(i);
+ try {
+ // 基本数据验证
+ if (StringUtils.isBlank(dto.getLessonName())) {
+ errorMsg.append(String.format("第%d行课程名称不能为空;", i + 2));
+ continue;
+ }
+ if (StringUtils.isBlank(dto.getMicroLessonName())) {
+ errorMsg.append(String.format("第%d行微课名称不能为空;", i + 2));
+ continue;
+ }
+ if (StringUtils.isBlank(dto.getTeacherEmail())) {
+ errorMsg.append(String.format("第%d行教师账号不能为空;", i + 2));
+ continue;
+ }
+
+ // 查找教师用户ID
+ ApiResponse teacherResponse = userService.findTeacherByEmail(dto.getTeacherEmail());
+ if (teacherResponse.getCode() != ErrorCode.SUCCESS) {
+ errorMsg.append(String.format("第%d行未找到教师用户(%s);", i + 2, dto.getTeacherEmail()));
+ continue;
+ }
+
+ LessonTask task = new LessonTask();
+ task.setCourseName(dto.getLessonName());
+ task.setMicroLessonName(dto.getMicroLessonName());
+ task.setUserId(teacherResponse.getData().getId());
+ task.setProgressStatus(0); // 初始状态:未开始
+ task.setCreatedAt(System.currentTimeMillis() / 1000);
+ task.setUpdatedAt(System.currentTimeMillis() / 1000);
+
+ try {
+ lessonTaskRepository.save(task);
+ successCount++;
+ } catch (Exception e) {
+ logger.error("保存课程任务失败", e);
+ errorMsg.append(String.format("第%d行保存失败: %s;", i + 2, e.getMessage()));
+ }
+ } catch (Exception e) {
+ logger.error("导入第{}行数据失败", i + 2, e);
+ errorMsg.append(String.format("第%d行导入失败: %s;", i + 2, e.getMessage()));
+ }
+ }
+
+ String resultMsg = String.format("成功导入%d条数据", successCount);
+ if (errorMsg.length() > 0) {
+ resultMsg += "。错误信息:" + errorMsg;
+ }
+
+ // 如果没有成功导入任何数据,返回错误状态
+ if (successCount == 0) {
+ return new ApiResponse<>(ErrorCode.PARAM_ERROR, resultMsg, null);
+ }
+
+ return ApiResponse.success(resultMsg);
+ }
+
private void validateRequest(LessonTaskRequest request) {
if (request.getCourseName() == null || request.getCourseName().trim().isEmpty()) {
throw new IllegalArgumentException("课程名称不能为空");
diff --git a/src/main/java/com/huertian/jinduguanli/service/UserService.java b/src/main/java/com/huertian/jinduguanli/service/UserService.java
index faa8d3c..13a2011 100644
--- a/src/main/java/com/huertian/jinduguanli/service/UserService.java
+++ b/src/main/java/com/huertian/jinduguanli/service/UserService.java
@@ -2,13 +2,13 @@ package com.huertian.jinduguanli.service;
import com.huertian.jinduguanli.common.ApiResponse;
import com.huertian.jinduguanli.common.ErrorCode;
-import com.huertian.jinduguanli.dto.CreateUserRequest;
-import com.huertian.jinduguanli.dto.LoginResponse;
-import com.huertian.jinduguanli.dto.UserLoginRequest;
-import com.huertian.jinduguanli.dto.UserPageResponse;
+import com.huertian.jinduguanli.dto.*;
+import com.huertian.jinduguanli.entity.Department;
import com.huertian.jinduguanli.entity.User;
+import com.huertian.jinduguanli.repository.DepartmentRepository;
import com.huertian.jinduguanli.repository.UserRepository;
import com.huertian.jinduguanli.security.service.JwtService;
+import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -28,13 +28,16 @@ public class UserService implements UserDetailsService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final JwtService jwtService;
+ private final DepartmentRepository departmentRepository;
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
@Autowired
- public UserService(JwtService jwtService, PasswordEncoder passwordEncoder, UserRepository userRepository) {
+ public UserService(JwtService jwtService, PasswordEncoder passwordEncoder, UserRepository userRepository,
+ DepartmentRepository departmentRepository) {
this.jwtService = jwtService;
this.passwordEncoder = passwordEncoder;
this.userRepository = userRepository;
+ this.departmentRepository = departmentRepository;
}
@Override
@@ -77,7 +80,7 @@ public class UserService implements UserDetailsService {
user.setCreatorId(request.getCreatorId());
user.setStatus(1);
// 时间戳由 @PrePersist 处理,这里不需要手动设置
-
+
userRepository.save(user);
return ApiResponse.success();
@@ -183,22 +186,83 @@ public class UserService implements UserDetailsService {
return new ApiResponse<>(ErrorCode.USER_NOT_FOUND, "用户不存在", null);
}
- // 验证用户是否为教师角色且为课程制作教师岗位
- if (user.getRoles() != 1) {
- return new ApiResponse<>(ErrorCode.INVALID_PARAM, "非教师用户", null);
- }
-
- if (user.getJobs() != 1) {
- return new ApiResponse<>(ErrorCode.INVALID_PARAM, "非课程制作教师", null);
- }
-
if (user.getStatus() != 1) {
return new ApiResponse<>(ErrorCode.INVALID_PARAM, "用户状态异常", null);
}
- // 清除敏感信息
- user.setPassword(null);
-
return ApiResponse.success(user);
}
+
+ public ApiResponse batchImportUsers(List userList) {
+ if (userList == null || userList.isEmpty()) {
+ return new ApiResponse<>(ErrorCode.PARAM_ERROR, "导入数据不能为空", null);
+ }
+
+ StringBuilder errorMsg = new StringBuilder();
+ int successCount = 0;
+
+ for (int i = 0; i < userList.size(); i++) {
+ UserImportDTO dto = userList.get(i);
+ try {
+ // 基本数据验证
+ if (StringUtils.isBlank(dto.getUsername()) ||
+ StringUtils.isBlank(dto.getEmail()) ||
+ StringUtils.isBlank(dto.getPassword()) ||
+ StringUtils.isBlank(dto.getDepartmentName()) ||
+ StringUtils.isBlank(dto.getRoleAndJob())) {
+ errorMsg.append(String.format("第%d行数据不完整;", i + 2));
+ continue;
+ }
+
+ // 检查邮箱是否已存在
+ if (userRepository.findByEmail(dto.getEmail()).isPresent()) {
+ errorMsg.append(String.format("第%d行邮箱已存在;", i + 2));
+ continue;
+ }
+
+ // 查找部门ID
+ Department department = departmentRepository.findByName(dto.getDepartmentName());
+ logger.info("查找部门:{},结果:{}", dto.getDepartmentName(), department);
+ if (department == null) {
+ errorMsg.append(String.format("第%d行部门不存在;", i + 2));
+ continue;
+ }
+
+ // 创建新用户
+ User user = new User();
+ user.setUsername(dto.getUsername());
+ user.setEmail(dto.getEmail());
+ user.setPassword(passwordEncoder.encode(dto.getPassword()));
+ user.setDepartmentId(department.getId());
+ user.setRoles(0); // 默认角色
+ user.setJobs(0); // 默认工作
+ user.setStatus(1); // 设置状态为正常
+ user.setCreatedAt(System.currentTimeMillis() / 1000);
+ user.setUpdatedAt(System.currentTimeMillis() / 1000);
+
+ try {
+ userRepository.save(user);
+ successCount++;
+ } catch (Exception e) {
+ logger.error("保存用户失败", e);
+ errorMsg.append(String.format("第%d行保存失败: %s;", i + 2, e.getMessage()));
+ }
+ } catch (Exception e) {
+ logger.error("导入第{}行数据失败", i + 2, e);
+ errorMsg.append(String.format("第%d行导入失败;", i + 2));
+ }
+ }
+
+ String resultMsg = String.format("成功导入%d条数据", successCount);
+ if (errorMsg.length() > 0) {
+ resultMsg += "。错误信息:" + errorMsg;
+ }
+
+ // 如果没有成功导入任何数据,返回错误状态
+ if (successCount == 0) {
+ return new ApiResponse<>(ErrorCode.PARAM_ERROR, resultMsg, null);
+ }
+
+ return ApiResponse.success(resultMsg);
+ }
}
diff --git a/批量添加用户模版.xlsx b/批量添加用户模版.xlsx
new file mode 100644
index 0000000..f3e5070
Binary files /dev/null and b/批量添加用户模版.xlsx differ
diff --git a/批量添加课程模版.xlsx b/批量添加课程模版.xlsx
new file mode 100644
index 0000000..cd30c30
Binary files /dev/null and b/批量添加课程模版.xlsx differ
diff --git a/批量添加部门模版.xlsx b/批量添加部门模版.xlsx
new file mode 100644
index 0000000..438ca25
Binary files /dev/null and b/批量添加部门模版.xlsx differ