最新一次提交
This commit is contained in:
@@ -1,77 +0,0 @@
|
||||
name: 构建和部署Spring Boot应用程序
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
pull_request:
|
||||
branches: ["main"]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: 检出代码库
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: 设置JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: "17"
|
||||
distribution: "temurin"
|
||||
- name: 缓存Maven包
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-maven-
|
||||
|
||||
- name: 安装依赖
|
||||
run: ./mvnw install -DskipTests
|
||||
|
||||
- name: 运行测试
|
||||
run: ./mvnw test
|
||||
|
||||
- name: 打包应用程序
|
||||
run: ./mvnw package -DskipTests
|
||||
|
||||
- name: 上传构件
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: spring-boot-app
|
||||
path: |
|
||||
target/jinduguanli-0.0.1-SNAPSHOT.jar
|
||||
src/main/resources/application.yml
|
||||
|
||||
deploy:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: 下载构件
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: spring-boot-app
|
||||
path: target/
|
||||
|
||||
- name: 通过scp复制文件
|
||||
uses: appleboy/scp-action@v0.1.1
|
||||
with:
|
||||
host: ${{ secrets.REMOTE_HOST }}
|
||||
username: ${{ secrets.REMOTE_USER }}
|
||||
key: ${{ secrets.REMOTE_SSH_KEY }}
|
||||
source: |
|
||||
target/jinduguanli-0.0.1-SNAPSHOT.jar
|
||||
src/main/resources/application.yml
|
||||
target: "/huertian/"
|
||||
|
||||
- name: 通过ssh执行远程命令
|
||||
uses: appleboy/ssh-action@v0.1.8
|
||||
with:
|
||||
host: ${{ secrets.REMOTE_HOST }}
|
||||
username: ${{ secrets.REMOTE_USER }}
|
||||
key: ${{ secrets.REMOTE_SSH_KEY }}
|
||||
script: |
|
||||
cd /huertian/
|
||||
java -jar jinduguanli-0.0.1-SNAPSHOT.jar --spring.config.location=application.yml
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.huertian.jinduguanli.common;
|
||||
|
||||
public enum ProgressStatus {
|
||||
NOT_STARTED(0, "未开始"),
|
||||
SCRIPT_CREATION(1, "脚本制作"),
|
||||
SCRIPT_REVIEW(2, "脚本审核"),
|
||||
SCRIPT_CONFIRMATION(3, "脚本确认"),
|
||||
VIDEO_CREATION(4, "视频拍摄与制作"),
|
||||
VIDEO_CONFIRMATION(5, "视频确认");
|
||||
|
||||
private final int code;
|
||||
private final String description;
|
||||
|
||||
ProgressStatus(int code, String description) {
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public static ProgressStatus fromCode(int code) {
|
||||
for (ProgressStatus status : ProgressStatus.values()) {
|
||||
if (status.code == code) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("未知的进度状态代码: " + code);
|
||||
}
|
||||
|
||||
public static String getDescription(int code) {
|
||||
return fromCode(code).getDescription();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.huertian.jinduguanli.controller;
|
||||
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.excel.read.listener.PageReadListener;
|
||||
import com.huertian.jinduguanli.common.ApiResponse;
|
||||
import com.huertian.jinduguanli.common.ErrorCode;
|
||||
import com.huertian.jinduguanli.dto.DepartmentImportDTO;
|
||||
@@ -13,12 +14,13 @@ 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.RequestHeader;
|
||||
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;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@@ -34,8 +36,15 @@ public class ImportController {
|
||||
@Autowired
|
||||
private DepartmentService departmentService;
|
||||
|
||||
/**
|
||||
* 每批处理的数据量
|
||||
*/
|
||||
private static final int BATCH_SIZE = 100;
|
||||
|
||||
@PostMapping("/users")
|
||||
public ApiResponse<String> importUsers(@RequestParam("file") MultipartFile file) {
|
||||
public ApiResponse<String> importUsers(
|
||||
@RequestParam("file") MultipartFile file,
|
||||
@RequestHeader("Authorization") String authHeader) {
|
||||
if (file.isEmpty()) {
|
||||
return new ApiResponse<>(ErrorCode.INVALID_PARAM, "文件不能为空", null);
|
||||
}
|
||||
@@ -47,17 +56,29 @@ public class ImportController {
|
||||
|
||||
try {
|
||||
log.info("开始导入用户数据,文件名:{}", originalFilename);
|
||||
List<UserImportDTO> userList = EasyExcel.read(file.getInputStream())
|
||||
.head(UserImportDTO.class)
|
||||
.sheet()
|
||||
.doReadSync();
|
||||
log.info("读取到{}条用户数据", userList.size());
|
||||
String token = authHeader.substring(7);
|
||||
AtomicInteger totalCount = new AtomicInteger(0);
|
||||
AtomicInteger successCount = new AtomicInteger(0);
|
||||
StringBuilder errorMsg = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < userList.size(); i++) {
|
||||
log.info("第{}行数据:{}", i + 1, userList.get(i));
|
||||
// 使用分批读取,每次处理 BATCH_SIZE 条数据,避免内存溢出
|
||||
EasyExcel.read(file.getInputStream(), UserImportDTO.class, new PageReadListener<UserImportDTO>(batch -> {
|
||||
log.debug("处理用户数据批次,本批数量:{}", batch.size());
|
||||
totalCount.addAndGet(batch.size());
|
||||
ApiResponse<String> result = userService.batchImportUsers(batch, token);
|
||||
if (result.getCode() == ErrorCode.SUCCESS) {
|
||||
successCount.addAndGet(batch.size());
|
||||
} else {
|
||||
errorMsg.append(result.getMessage()).append(";");
|
||||
}
|
||||
}, BATCH_SIZE)).sheet().doRead();
|
||||
|
||||
log.info("用户导入完成,总计:{}条,成功:{}条", totalCount.get(), successCount.get());
|
||||
String resultMsg = String.format("导入完成,总计%d条,成功%d条", totalCount.get(), successCount.get());
|
||||
if (errorMsg.length() > 0) {
|
||||
resultMsg += "。错误信息:" + errorMsg;
|
||||
}
|
||||
|
||||
return userService.batchImportUsers(userList);
|
||||
return ApiResponse.success(resultMsg);
|
||||
} catch (Exception e) {
|
||||
log.error("导入用户数据失败", e);
|
||||
return new ApiResponse<>(ErrorCode.SYSTEM_ERROR, "导入用户数据失败:" + e.getMessage(), null);
|
||||
@@ -77,17 +98,28 @@ public class ImportController {
|
||||
|
||||
try {
|
||||
log.info("开始导入课程任务数据,文件名:{}", originalFilename);
|
||||
List<LessonTaskImportDTO> taskList = EasyExcel.read(file.getInputStream())
|
||||
.head(LessonTaskImportDTO.class)
|
||||
.sheet()
|
||||
.doReadSync();
|
||||
log.info("读取到{}条课程任务数据", taskList.size());
|
||||
AtomicInteger totalCount = new AtomicInteger(0);
|
||||
AtomicInteger successCount = new AtomicInteger(0);
|
||||
StringBuilder errorMsg = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < taskList.size(); i++) {
|
||||
log.info("第{}行数据:{}", i + 1, taskList.get(i));
|
||||
// 使用分批读取,每次处理 BATCH_SIZE 条数据,避免内存溢出
|
||||
EasyExcel.read(file.getInputStream(), LessonTaskImportDTO.class, new PageReadListener<LessonTaskImportDTO>(batch -> {
|
||||
log.debug("处理课程任务数据批次,本批数量:{}", batch.size());
|
||||
totalCount.addAndGet(batch.size());
|
||||
ApiResponse<String> result = lessonTaskService.batchImportLessonTasks(batch);
|
||||
if (result.getCode() == ErrorCode.SUCCESS) {
|
||||
successCount.addAndGet(batch.size());
|
||||
} else {
|
||||
errorMsg.append(result.getMessage()).append(";");
|
||||
}
|
||||
}, BATCH_SIZE)).sheet().doRead();
|
||||
|
||||
log.info("课程任务导入完成,总计:{}条,成功:{}条", totalCount.get(), successCount.get());
|
||||
String resultMsg = String.format("导入完成,总计%d条,成功%d条", totalCount.get(), successCount.get());
|
||||
if (errorMsg.length() > 0) {
|
||||
resultMsg += "。错误信息:" + errorMsg;
|
||||
}
|
||||
|
||||
return lessonTaskService.batchImportLessonTasks(taskList);
|
||||
return ApiResponse.success(resultMsg);
|
||||
} catch (Exception e) {
|
||||
log.error("导入课程任务数据失败", e);
|
||||
return new ApiResponse<>(ErrorCode.SYSTEM_ERROR, "导入课程任务数据失败:" + e.getMessage(), null);
|
||||
@@ -107,17 +139,28 @@ public class ImportController {
|
||||
|
||||
try {
|
||||
log.info("开始导入部门数据,文件名:{}", originalFilename);
|
||||
List<DepartmentImportDTO> departmentList = EasyExcel.read(file.getInputStream())
|
||||
.head(DepartmentImportDTO.class)
|
||||
.sheet()
|
||||
.doReadSync();
|
||||
log.info("读取到{}条部门数据", departmentList.size());
|
||||
AtomicInteger totalCount = new AtomicInteger(0);
|
||||
AtomicInteger successCount = new AtomicInteger(0);
|
||||
StringBuilder errorMsg = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < departmentList.size(); i++) {
|
||||
log.info("第{}行数据:{}", i + 1, departmentList.get(i));
|
||||
// 使用分批读取,每次处理 BATCH_SIZE 条数据,避免内存溢出
|
||||
EasyExcel.read(file.getInputStream(), DepartmentImportDTO.class, new PageReadListener<DepartmentImportDTO>(batch -> {
|
||||
log.debug("处理部门数据批次,本批数量:{}", batch.size());
|
||||
totalCount.addAndGet(batch.size());
|
||||
ApiResponse<String> result = departmentService.batchImportDepartments(batch);
|
||||
if (result.getCode() == ErrorCode.SUCCESS) {
|
||||
successCount.addAndGet(batch.size());
|
||||
} else {
|
||||
errorMsg.append(result.getMessage()).append(";");
|
||||
}
|
||||
}, BATCH_SIZE)).sheet().doRead();
|
||||
|
||||
log.info("部门导入完成,总计:{}条,成功:{}条", totalCount.get(), successCount.get());
|
||||
String resultMsg = String.format("导入完成,总计%d条,成功%d条", totalCount.get(), successCount.get());
|
||||
if (errorMsg.length() > 0) {
|
||||
resultMsg += "。错误信息:" + errorMsg;
|
||||
}
|
||||
|
||||
return departmentService.batchImportDepartments(departmentList);
|
||||
return ApiResponse.success(resultMsg);
|
||||
} catch (Exception e) {
|
||||
log.error("导入部门数据失败", e);
|
||||
return new ApiResponse<>(ErrorCode.SYSTEM_ERROR, "导入部门数据失败:" + e.getMessage(), null);
|
||||
|
||||
@@ -9,7 +9,6 @@ import com.huertian.jinduguanli.service.LessonTaskService;
|
||||
import jakarta.validation.Valid;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -20,7 +19,6 @@ public class LessonTaskController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(LessonTaskController.class);
|
||||
private final LessonTaskService lessonTaskService;
|
||||
|
||||
@Autowired
|
||||
public LessonTaskController(LessonTaskService lessonTaskService) {
|
||||
this.lessonTaskService = lessonTaskService;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ public class LessonTaskDTO {
|
||||
private String courseName;
|
||||
private String microLessonName;
|
||||
private Long userId;
|
||||
private String username; // 添加用户名字段
|
||||
private String username; // 添加用户名字段
|
||||
private Integer progressStatus;
|
||||
private Long scriptCreateTime;
|
||||
private Long scriptReviewTime;
|
||||
@@ -17,7 +17,9 @@ public class LessonTaskDTO {
|
||||
private Long videoCreateTime;
|
||||
private Long videoConfirmTime;
|
||||
private Long finishTime;
|
||||
private Integer expediteStatus;
|
||||
private String advise;
|
||||
private String msg;
|
||||
private Long createdAt;
|
||||
private Long updatedAt;
|
||||
|
||||
@@ -36,7 +38,9 @@ public class LessonTaskDTO {
|
||||
dto.setVideoCreateTime(lessonTask.getVideoCreateTime());
|
||||
dto.setVideoConfirmTime(lessonTask.getVideoConfirmTime());
|
||||
dto.setFinishTime(lessonTask.getFinishTime());
|
||||
dto.setExpediteStatus(lessonTask.getExpediteStatus());
|
||||
dto.setAdvise(lessonTask.getAdvise());
|
||||
dto.setMsg(lessonTask.getMsg());
|
||||
dto.setCreatedAt(lessonTask.getCreatedAt());
|
||||
dto.setUpdatedAt(lessonTask.getUpdatedAt());
|
||||
return dto;
|
||||
@@ -146,6 +150,22 @@ public class LessonTaskDTO {
|
||||
this.advise = advise;
|
||||
}
|
||||
|
||||
public Integer getExpediteStatus() {
|
||||
return expediteStatus;
|
||||
}
|
||||
|
||||
public void setExpediteStatus(Integer expediteStatus) {
|
||||
this.expediteStatus = expediteStatus;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public Long getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ public class LessonTaskRequest {
|
||||
private Long videoCreateTime;
|
||||
private Long videoConfirmTime;
|
||||
private Long finishTime;
|
||||
private Integer expediteStatus;
|
||||
private String advise;
|
||||
private String msg;
|
||||
|
||||
public String getCourseName() {
|
||||
return courseName;
|
||||
@@ -105,4 +107,20 @@ public class LessonTaskRequest {
|
||||
public void setAdvise(String advise) {
|
||||
this.advise = advise;
|
||||
}
|
||||
|
||||
public Integer getExpediteStatus() {
|
||||
return expediteStatus;
|
||||
}
|
||||
|
||||
public void setExpediteStatus(Integer expediteStatus) {
|
||||
this.expediteStatus = expediteStatus;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.huertian.jinduguanli.dto;
|
||||
|
||||
import com.huertian.jinduguanli.entity.LessonTask;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class LessonTaskSimpleDTO {
|
||||
private Long id;
|
||||
private Integer progressStatus;
|
||||
private String msg;
|
||||
|
||||
// 从 LessonTask 实体转换为简化 DTO
|
||||
public static LessonTaskSimpleDTO fromEntity(LessonTask lessonTask) {
|
||||
LessonTaskSimpleDTO dto = new LessonTaskSimpleDTO();
|
||||
dto.setId(lessonTask.getId());
|
||||
dto.setProgressStatus(lessonTask.getProgressStatus());
|
||||
dto.setMsg(lessonTask.getMsg());
|
||||
return dto;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getProgressStatus() {
|
||||
return progressStatus;
|
||||
}
|
||||
|
||||
public void setProgressStatus(Integer progressStatus) {
|
||||
this.progressStatus = progressStatus;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
}
|
||||
@@ -38,9 +38,14 @@ public class LessonTask implements Serializable {
|
||||
private Long videoCreateTime;
|
||||
private Long videoConfirmTime;
|
||||
private Long finishTime;
|
||||
|
||||
|
||||
@Column(nullable = false)
|
||||
private Integer expediteStatus;
|
||||
|
||||
private String advise;
|
||||
|
||||
private String msg;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Long createdAt;
|
||||
|
||||
@@ -49,20 +54,21 @@ public class LessonTask implements Serializable {
|
||||
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
logger.info("创建新课程任务 - 课程名称: {}, 微课名称: {}, 用户ID: {}",
|
||||
this.courseName, this.microLessonName, this.userId);
|
||||
progressStatus = 0;
|
||||
logger.info("创建新课程任务 - 课程名称: {}, 微课名称: {}, 用户ID: {}",
|
||||
this.courseName, this.microLessonName, this.userId);
|
||||
progressStatus = 0;
|
||||
expediteStatus = 0; // 默认未催办
|
||||
long now = System.currentTimeMillis() / 1000;
|
||||
createdAt = now;
|
||||
updatedAt = now;
|
||||
logger.info("创建课程任务成功 - 进度状态: {}, 创建时间: {}, 更新时间: {}",
|
||||
progressStatus, createdAt, updatedAt);
|
||||
logger.info("创建课程任务成功 - 进度状态: {}, 催办状态: {}, 创建时间: {}, 更新时间: {}",
|
||||
progressStatus, expediteStatus, createdAt, updatedAt);
|
||||
}
|
||||
|
||||
@PreUpdate
|
||||
protected void onUpdate() {
|
||||
logger.info("更新课程任务 - ID: {}, 课程名称: {}, 微课名称: {}",
|
||||
this.id, this.courseName, this.microLessonName);
|
||||
logger.info("更新课程任务 - ID: {}, 课程名称: {}, 微课名称: {}",
|
||||
this.id, this.courseName, this.microLessonName);
|
||||
updatedAt = System.currentTimeMillis() / 1000;
|
||||
logger.info("更新课程任务成功 - ID: {}, 更新时间: {}", id, updatedAt);
|
||||
}
|
||||
|
||||
@@ -8,20 +8,12 @@ import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Repository
|
||||
public interface LessonTaskRepository extends JpaRepository<LessonTask, Long> {
|
||||
Page<LessonTask> findByUserId(Long userId, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 查询指定部门的所有课程任务
|
||||
* 通过连接users表查询属于指定部门的所有用户的课程任务
|
||||
*/
|
||||
@Query("SELECT lt FROM LessonTask lt JOIN User u ON lt.userId = u.id WHERE u.departmentId = :departmentId")
|
||||
List<LessonTask> findByDepartmentId(@Param("departmentId") Long departmentId);
|
||||
|
||||
/**
|
||||
* 分页查询指定部门的所有课程任务
|
||||
*/
|
||||
|
||||
@@ -66,6 +66,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
}
|
||||
|
||||
final String jwt = authHeader.substring(7);
|
||||
logger.debug("Received JWT token: {}", jwt);
|
||||
final String username = jwtService.extractUsername(jwt);
|
||||
|
||||
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
|
||||
@@ -5,6 +5,8 @@ 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 jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -16,7 +18,12 @@ import java.util.List;
|
||||
@Service
|
||||
public class DepartmentService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(DepartmentService.class);
|
||||
private static final int BATCH_FLUSH_SIZE = 50; // 每50条清理一次缓存
|
||||
|
||||
private final DepartmentRepository departmentRepository;
|
||||
|
||||
@PersistenceContext
|
||||
private EntityManager entityManager;
|
||||
|
||||
@Autowired
|
||||
public DepartmentService(DepartmentRepository departmentRepository) {
|
||||
@@ -55,11 +62,24 @@ public class DepartmentService {
|
||||
|
||||
departmentRepository.save(department);
|
||||
successCount++;
|
||||
|
||||
// 每 BATCH_FLUSH_SIZE 条数据清理一次 Hibernate 一级缓存,避免内存溢出
|
||||
if (successCount % BATCH_FLUSH_SIZE == 0) {
|
||||
entityManager.flush();
|
||||
entityManager.clear();
|
||||
logger.debug("已处理 {} 条部门数据,清理缓存", successCount);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("导入第{}行数据失败", i + 2, e);
|
||||
errorMsg.append(String.format("第%d行导入失败;", i + 2));
|
||||
}
|
||||
}
|
||||
|
||||
// 处理剩余数据的缓存清理
|
||||
if (successCount % BATCH_FLUSH_SIZE != 0) {
|
||||
entityManager.flush();
|
||||
entityManager.clear();
|
||||
}
|
||||
|
||||
String resultMsg = String.format("成功导入%d条数据", successCount);
|
||||
if (errorMsg.length() > 0) {
|
||||
|
||||
@@ -8,7 +8,9 @@ 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.EntityManager;
|
||||
import jakarta.persistence.EntityNotFoundException;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
@@ -26,8 +28,13 @@ import org.apache.commons.lang3.StringUtils;
|
||||
@Service
|
||||
public class LessonTaskService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(LessonTaskService.class);
|
||||
private static final int BATCH_FLUSH_SIZE = 50; // 每50条清理一次缓存
|
||||
|
||||
private final LessonTaskRepository lessonTaskRepository;
|
||||
private final UserService userService; // 添加 UserService 的依赖
|
||||
private final UserService userService;
|
||||
|
||||
@PersistenceContext
|
||||
private EntityManager entityManager;
|
||||
|
||||
public LessonTaskService(LessonTaskRepository lessonTaskRepository, UserService userService) {
|
||||
this.lessonTaskRepository = lessonTaskRepository;
|
||||
@@ -129,6 +136,12 @@ public class LessonTaskService {
|
||||
if (request.getAdvise() != null) {
|
||||
task.setAdvise(request.getAdvise());
|
||||
}
|
||||
if (request.getMsg() != null) {
|
||||
task.setMsg(request.getMsg());
|
||||
}
|
||||
if (request.getExpediteStatus() != null) {
|
||||
task.setExpediteStatus(request.getExpediteStatus());
|
||||
}
|
||||
if (request.getCourseName() != null) {
|
||||
task.setCourseName(request.getCourseName());
|
||||
}
|
||||
@@ -247,6 +260,13 @@ public class LessonTaskService {
|
||||
try {
|
||||
lessonTaskRepository.save(task);
|
||||
successCount++;
|
||||
|
||||
// 每 BATCH_FLUSH_SIZE 条数据清理一次 Hibernate 一级缓存,避免内存溢出
|
||||
if (successCount % BATCH_FLUSH_SIZE == 0) {
|
||||
entityManager.flush();
|
||||
entityManager.clear();
|
||||
logger.debug("已处理 {} 条数据,清理缓存", successCount);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("保存课程任务失败", e);
|
||||
errorMsg.append(String.format("第%d行保存失败: %s;", i + 2, e.getMessage()));
|
||||
@@ -256,6 +276,12 @@ public class LessonTaskService {
|
||||
errorMsg.append(String.format("第%d行导入失败: %s;", i + 2, e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// 处理剩余数据的缓存清理
|
||||
if (successCount % BATCH_FLUSH_SIZE != 0) {
|
||||
entityManager.flush();
|
||||
entityManager.clear();
|
||||
}
|
||||
|
||||
String resultMsg = String.format("成功导入%d条数据", successCount);
|
||||
if (errorMsg.length() > 0) {
|
||||
|
||||
@@ -8,6 +8,8 @@ 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 jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -25,11 +27,16 @@ import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class UserService implements UserDetailsService {
|
||||
private static final int BATCH_FLUSH_SIZE = 50; // 每50条清理一次缓存
|
||||
|
||||
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);
|
||||
|
||||
@PersistenceContext
|
||||
private EntityManager entityManager;
|
||||
|
||||
@Autowired
|
||||
public UserService(JwtService jwtService, PasswordEncoder passwordEncoder, UserRepository userRepository,
|
||||
@@ -193,7 +200,7 @@ public class UserService implements UserDetailsService {
|
||||
return ApiResponse.success(user);
|
||||
}
|
||||
|
||||
public ApiResponse<String> batchImportUsers(List<UserImportDTO> userList) {
|
||||
public ApiResponse<String> batchImportUsers(List<UserImportDTO> userList, String token) {
|
||||
if (userList == null || userList.isEmpty()) {
|
||||
return new ApiResponse<>(ErrorCode.PARAM_ERROR, "导入数据不能为空", null);
|
||||
}
|
||||
@@ -234,8 +241,29 @@ public class UserService implements UserDetailsService {
|
||||
user.setEmail(dto.getEmail());
|
||||
user.setPassword(passwordEncoder.encode(dto.getPassword()));
|
||||
user.setDepartmentId(department.getId());
|
||||
user.setRoles(0); // 默认角色
|
||||
user.setJobs(0); // 默认工作
|
||||
|
||||
// 处理角色和岗位
|
||||
String roleAndJob = dto.getRoleAndJob();
|
||||
if (!StringUtils.isBlank(roleAndJob)) {
|
||||
try {
|
||||
user.setRoles(Integer.parseInt(roleAndJob));
|
||||
user.setJobs(Integer.parseInt(roleAndJob));
|
||||
} catch (NumberFormatException e) {
|
||||
logger.warn("角色/岗位不是有效的数字: {}", roleAndJob);
|
||||
errorMsg.append(String.format("第%d行角色/岗位不是有效的数字;", i + 2));
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
logger.warn("角色/岗位不能为空");
|
||||
errorMsg.append(String.format("第%d行角色/岗位不能为空;", i + 2));
|
||||
continue;
|
||||
}
|
||||
|
||||
// 设置创建者ID
|
||||
String email = jwtService.extractUsername(token);
|
||||
Optional<User> creator = userRepository.findByEmail(email);
|
||||
user.setCreatorId(creator.map(User::getId).orElse(0L));
|
||||
|
||||
user.setStatus(1); // 设置状态为正常
|
||||
user.setCreatedAt(System.currentTimeMillis() / 1000);
|
||||
user.setUpdatedAt(System.currentTimeMillis() / 1000);
|
||||
@@ -243,6 +271,13 @@ public class UserService implements UserDetailsService {
|
||||
try {
|
||||
userRepository.save(user);
|
||||
successCount++;
|
||||
|
||||
// 每 BATCH_FLUSH_SIZE 条数据清理一次 Hibernate 一级缓存,避免内存溢出
|
||||
if (successCount % BATCH_FLUSH_SIZE == 0) {
|
||||
entityManager.flush();
|
||||
entityManager.clear();
|
||||
logger.debug("已处理 {} 条用户数据,清理缓存", successCount);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("保存用户失败", e);
|
||||
errorMsg.append(String.format("第%d行保存失败: %s;", i + 2, e.getMessage()));
|
||||
@@ -252,6 +287,12 @@ public class UserService implements UserDetailsService {
|
||||
errorMsg.append(String.format("第%d行导入失败;", i + 2));
|
||||
}
|
||||
}
|
||||
|
||||
// 处理剩余数据的缓存清理
|
||||
if (successCount % BATCH_FLUSH_SIZE != 0) {
|
||||
entityManager.flush();
|
||||
entityManager.clear();
|
||||
}
|
||||
|
||||
String resultMsg = String.format("成功导入%d条数据", successCount);
|
||||
if (errorMsg.length() > 0) {
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
# 数据库配置
|
||||
spring.datasource.url=jdbc:mysql://172.16.215.132:3306/fenshenzhike?useSSL=false&serverTimezone=UTC
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=123
|
||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
|
||||
server.port=1218
|
||||
|
||||
# JPA配置
|
||||
spring.jpa.show-sql=true
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
|
||||
spring.jpa.properties.hibernate.format_sql=true
|
||||
|
||||
# JWT配置
|
||||
jwt.secret=404E635266556A586E3272357538782F413F4428472B4B6250645367566B5970
|
||||
jwt.expiration=604800000
|
||||
|
||||
# 日志配置
|
||||
logging.level.org.springframework.security=DEBUG
|
||||
logging.level.com.huertian.jinduguanli=DEBUG
|
||||
|
||||
spring.devtools.restart.enabled=false
|
||||
@@ -1,14 +1,31 @@
|
||||
server:
|
||||
port: 1218
|
||||
ssl:
|
||||
enabled: true
|
||||
key-store: /root/jinduguanli/key-store/service5.fenshenzhike.com.pfx
|
||||
key-store-password: "q4a9hpm0"
|
||||
key-store-type: PKCS12
|
||||
|
||||
spring:
|
||||
main:
|
||||
banner-mode: console
|
||||
|
||||
datasource:
|
||||
url: jdbc:mysql://172.16.215.132:3306/fenshenzhike?useSSL=false&serverTimezone=UTC
|
||||
username: root
|
||||
password: 123
|
||||
url: jdbc:mysql://8.137.89.177:3306/jinduguanli?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
|
||||
username: jinduguanli
|
||||
password: root041218
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
|
||||
hikari:
|
||||
maximum-pool-size: 10
|
||||
minimum-idle: 2
|
||||
idle-timeout: 600000 # 10 min
|
||||
max-lifetime: 1800000 # 30 min
|
||||
connection-timeout: 30000 # 30 s
|
||||
validation-timeout: 5000 # 5 s
|
||||
keepalive-time: 300000 # 5 min
|
||||
connection-test-query: "SELECT 1"
|
||||
|
||||
jpa:
|
||||
show-sql: true
|
||||
hibernate:
|
||||
@@ -17,12 +34,15 @@ spring:
|
||||
hibernate:
|
||||
format_sql: true
|
||||
use_sql_comments: true
|
||||
# 新版可自动选择方言,保留注释以免误导
|
||||
# dialect: org.hibernate.dialect.MySQLDialect
|
||||
|
||||
redis:
|
||||
host: 172.16.215.132
|
||||
host: 8.137.89.177
|
||||
port: 6379
|
||||
database: 0
|
||||
timeout: 10000
|
||||
password: # 如果Redis设置了密码,需要在这里添加
|
||||
password: #如有密码在此填入
|
||||
lettuce:
|
||||
pool:
|
||||
max-active: 8
|
||||
@@ -37,7 +57,7 @@ spring:
|
||||
|
||||
jwt:
|
||||
secret: 404E635266556A586E3272357538782F413F4428472B4B6250645367566B5970
|
||||
expiration: 86400000 # 24小时
|
||||
expiration: 2592000000 # 30天(毫秒)
|
||||
|
||||
logging:
|
||||
level:
|
||||
@@ -45,4 +65,4 @@ logging:
|
||||
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
|
||||
com.huertian.jinduguanli: DEBUG
|
||||
org.springframework.data.redis: DEBUG
|
||||
io.lettuce.core: DEBUG
|
||||
io.lettuce.core: DEBUG
|
||||
Reference in New Issue
Block a user