前端部分更新

This commit is contained in:
2026-06-26 17:39:57 +08:00
parent 628a63a250
commit d38cbdbf07
165 changed files with 35393 additions and 284 deletions
@@ -9,15 +9,26 @@ import com.weather.common.utils.Result;
import com.weather.modules.log.entity.SysLogErrorEntity;
import com.weather.modules.log.service.SysLogErrorService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
@@ -56,6 +67,57 @@ public class CustomExceptionHandler {
return new Result().error(ErrorCode.UNAUTHORIZED);
}
/**
* 处理 @Valid/@Validated 校验失败(@RequestBody 参数)
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
FieldError fieldError = ex.getBindingResult().getFieldError();
String msg = fieldError != null ? fieldError.getDefaultMessage() : ex.getMessage();
return new Result().error(ErrorCode.PARAMS_GET_ERROR, msg);
}
/**
* 处理类级别 @Validated 校验失败(路径/查询参数)
*/
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Result handleConstraintViolationException(ConstraintViolationException ex) {
Set<ConstraintViolation<?>> violations = ex.getConstraintViolations();
String msg = violations.stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.joining("; "));
return new Result().error(ErrorCode.PARAMS_GET_ERROR, msg);
}
/**
* 处理请求体解析失败(JSON格式错误等)
*/
@ExceptionHandler(HttpMessageNotReadableException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Result handleHttpMessageNotReadableException(HttpMessageNotReadableException ex) {
return new Result().error(ErrorCode.PARAMS_GET_ERROR, "请求参数格式错误");
}
/**
* 处理缺少必要请求参数
*/
@ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Result handleMissingServletRequestParameterException(MissingServletRequestParameterException ex) {
return new Result().error(ErrorCode.NOT_NULL, "参数[" + ex.getParameterName() + "]不能为空");
}
/**
* 处理请求方法不支持(GET/POST方法错误)
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
public Result handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException ex) {
return new Result().error(ErrorCode.INTERNAL_SERVER_ERROR, "请求方法不支持: " + ex.getMethod());
}
@ExceptionHandler(Exception.class)
public Result handleException(Exception ex) {
log.error(ex.getMessage(), ex);
@@ -4,6 +4,7 @@ package com.weather.modules.security.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import lombok.Data;
import java.io.Serializable;
@@ -20,6 +21,7 @@ public class LoginDTO implements Serializable {
@Schema(title = "用户名", required = true)
@NotBlank(message="{sysuser.username.require}")
@Pattern(regexp="^[a-zA-Z0-9]+$", message="{sysuser.username.format}")
private String username;
@Schema(title = "密码")
@@ -11,6 +11,7 @@ import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Null;
import jakarta.validation.constraints.Pattern;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
@@ -36,6 +37,7 @@ public class SysUserDTO implements Serializable {
@Schema(title = "用户名", required = true)
@NotBlank(message="{sysuser.username.require}", groups = DefaultGroup.class)
@Pattern(regexp="^[a-zA-Z0-9]+$", message="{sysuser.username.format}", groups = DefaultGroup.class)
private String username;
@Schema(title = "密码")
@@ -2,8 +2,6 @@ package com.weather.modules.weather.filescan;
import cn.hutool.core.util.StrUtil;
import com.weather.common.constant.Constant;
import com.weather.modules.sys.dao.SysDeptDao;
import com.weather.modules.sys.entity.SysDeptEntity;
import com.weather.modules.sys.service.SysParamsService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -12,11 +10,6 @@ import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Slf4j
@@ -30,7 +23,6 @@ public class FileScanStartupRunner {
private static final long STARTUP_DELAY_SECONDS = 30;
private final SysParamsService sysParamsService;
private final SysDeptDao sysDeptDao;
private final FileWatchServiceManager fileWatchServiceManager;
@Async
@@ -45,38 +37,12 @@ public class FileScanStartupRunner {
}
String rootPath = sysParamsService.getValue(Constant.FILE_SCAN_ROOT_PATH);
if (StrUtil.isBlank(rootPath)) {
if (StrUtil.isBlank(rootPath) || "0".equals(rootPath)) {
log.warn("FILE_SCAN_ROOT_PATH 未配置,跳过文件扫描目录初始化");
return;
}
// 确保根层级 receive / display / archive 目录存在(用于模型预报等非部门文件)
List<String> rootDirs = List.of("receive", "display", "archive");
for (String sub : rootDirs) {
Path dir = Paths.get(rootPath, sub);
try {
Files.createDirectories(dir);
log.debug("创建根目录: {}", dir);
} catch (IOException e) {
log.error("创建根目录失败: {}", dir, e);
}
}
// 创建各部门子目录
List<SysDeptEntity> deptList = sysDeptDao.selectList(null);
for (SysDeptEntity dept : deptList) {
if (StrUtil.isBlank(dept.getName())) continue;
for (String sub : rootDirs) {
Path dir = Paths.get(rootPath, sub, dept.getName());
try {
Files.createDirectories(dir);
log.debug("创建目录: {}", dir);
} catch (IOException e) {
log.error("创建目录失败: {}", dir, e);
}
}
}
fileWatchServiceManager.ensureDirectoriesExist();
fileWatchServiceManager.registerDeptDirectories();
fileWatchServiceManager.scanAllDirectories();
@@ -1,6 +1,9 @@
package com.weather.modules.weather.filescan;
import cn.hutool.core.util.StrUtil;
import com.weather.common.constant.Constant;
import com.weather.modules.job.task.ITask;
import com.weather.modules.sys.service.SysParamsService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@@ -10,11 +13,27 @@ import org.springframework.stereotype.Component;
@AllArgsConstructor
public class FileScanTask implements ITask {
private final SysParamsService sysParamsService;
private final FileWatchServiceManager fileWatchServiceManager;
@Override
public void run(String params) {
log.info("文件扫描定时任务开始执行");
String rootPath = sysParamsService.getValue(Constant.FILE_SCAN_ROOT_PATH);
if (StrUtil.isBlank(rootPath) || "0".equals(rootPath)) {
log.warn("FILE_SCAN_ROOT_PATH 未配置,跳过文件扫描定时任务");
return;
}
log.info("文件扫描定时任务开始执行, 根路径: {}", rootPath);
// 确保目录结构存在(路径可能在启动后才配置)
fileWatchServiceManager.ensureDirectoriesExist();
// 如果 WatchService 尚未注册部门目录则注册
if (fileWatchServiceManager.deptDirMap.isEmpty()) {
fileWatchServiceManager.registerDeptDirectories();
}
fileWatchServiceManager.scanAllDirectories();
log.info("文件扫描定时任务执行完毕");
}
@@ -46,7 +46,7 @@ public class FileWatchServiceManager {
private static final Set<String> SKIP_DIR_NAMES = Set.of("新建文件夹");
private WatchService watchService;
private final Map<String, Long> deptDirMap = new LinkedHashMap<>();
final Map<String, Long> deptDirMap = new LinkedHashMap<>();
private String rootReceiveDir;
private volatile boolean running = false;
@@ -74,10 +74,43 @@ public class FileWatchServiceManager {
}
}
/** 确保文件扫描目录结构存在(receive/display/archive 及各部门子目录) */
public void ensureDirectoriesExist() {
String rootPath = sysParamsService.getValue(Constant.FILE_SCAN_ROOT_PATH);
if (StrUtil.isBlank(rootPath) || "0".equals(rootPath)) {
return;
}
List<String> rootDirs = List.of("receive", "display", "archive");
for (String sub : rootDirs) {
Path dir = Paths.get(rootPath, sub);
try {
Files.createDirectories(dir);
log.debug("确保根目录存在: {}", dir);
} catch (IOException e) {
log.error("创建根目录失败: {}", dir, e);
}
}
List<SysDeptEntity> deptList = sysDeptDao.selectList(null);
for (SysDeptEntity dept : deptList) {
if (StrUtil.isBlank(dept.getName())) continue;
for (String sub : rootDirs) {
Path dir = Paths.get(rootPath, sub, dept.getName());
try {
Files.createDirectories(dir);
log.debug("确保部门目录存在: {}", dir);
} catch (IOException e) {
log.error("创建部门目录失败: {}", dir, e);
}
}
}
}
/** 注册部门目录 + 根目录的 WatchService 监控 */
public void registerDeptDirectories() {
String rootPath = sysParamsService.getValue(Constant.FILE_SCAN_ROOT_PATH);
if (StrUtil.isBlank(rootPath)) {
if (StrUtil.isBlank(rootPath) || "0".equals(rootPath)) {
log.warn("文件扫描根路径未配置,请检查 sys_params 中的 FILE_SCAN_ROOT_PATH");
return;
}
@@ -114,7 +147,7 @@ public class FileWatchServiceManager {
/** 全量扫描:部门子目录 + 根目录直接文件 */
public void scanAllDirectories() {
String rootPath = sysParamsService.getValue(Constant.FILE_SCAN_ROOT_PATH);
if (StrUtil.isBlank(rootPath)) return;
if (StrUtil.isBlank(rootPath) || "0".equals(rootPath)) return;
Path receiveRoot = Paths.get(rootPath, "receive");
if (!Files.exists(receiveRoot)) return;