ai模块
This commit is contained in:
@@ -24,6 +24,10 @@
|
||||
<groupId>org.xyzh.common</groupId>
|
||||
<artifactId>common-auth</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xyzh.common</groupId>
|
||||
<artifactId>common-exception</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xyzh.common</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
|
||||
@@ -7,7 +7,7 @@ import org.springframework.stereotype.Component;
|
||||
import org.xyzh.common.core.domain.LoginDomain;
|
||||
import org.xyzh.common.dto.sys.TbSysUserDTO;
|
||||
import org.xyzh.common.dto.sys.TbSysUserInfoDTO;
|
||||
import org.xyzh.common.utils.IDUtils;
|
||||
import org.xyzh.common.utils.id.IdUtil;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.util.Date;
|
||||
@@ -55,7 +55,7 @@ public class JwtTokenUtil {
|
||||
return Jwts.builder()
|
||||
.setClaims(claims)
|
||||
.setSubject(user.getUserId())
|
||||
.setId(IDUtils.generateID()) // 使用IDUtils生成JWT ID
|
||||
.setId(IdUtil.generateID()) // 使用IdUtil生成JWT ID
|
||||
.setIssuedAt(new Date())
|
||||
.setExpiration(generateExpirationDate())
|
||||
.signWith(getSigningKey())
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
package org.xyzh.common.auth.utils;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import org.xyzh.common.core.domain.LoginDomain;
|
||||
import org.xyzh.common.redis.service.RedisService;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @description 登录用户工具类,从Redis获取当前登录用户信息
|
||||
* @filename LoginUtil.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-12-17
|
||||
*/
|
||||
@Component
|
||||
public class LoginUtil {
|
||||
|
||||
private static final String AUTHORIZATION_HEADER = "Authorization";
|
||||
private static final String BEARER_PREFIX = "Bearer ";
|
||||
private static final String LOGIN_TOKEN_PREFIX = "login:token:";
|
||||
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
private static LoginUtil instance;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录用户信息
|
||||
*/
|
||||
public static LoginDomain getCurrentLogin() {
|
||||
String token = getToken();
|
||||
if (!StringUtils.hasText(token)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
String cacheKey = LOGIN_TOKEN_PREFIX + token;
|
||||
Object obj = instance.redisService.get(cacheKey);
|
||||
if (obj instanceof LoginDomain) {
|
||||
return (LoginDomain) obj;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 忽略异常
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户ID
|
||||
*/
|
||||
public static String getCurrentUserId() {
|
||||
LoginDomain login = getCurrentLogin();
|
||||
if (login != null && login.getUser() != null) {
|
||||
return login.getUser().getUserId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户名
|
||||
*/
|
||||
public static String getCurrentUserName() {
|
||||
LoginDomain login = getCurrentLogin();
|
||||
if (login != null && login.getUserInfo() != null) {
|
||||
return login.getUserInfo().getUsername();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断用户是否已登录
|
||||
*/
|
||||
public static boolean isLoggedIn() {
|
||||
return getCurrentLogin() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从请求头获取Token
|
||||
*/
|
||||
public static String getToken() {
|
||||
HttpServletRequest request = getRequest();
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String authHeader = request.getHeader(AUTHORIZATION_HEADER);
|
||||
if (StringUtils.hasText(authHeader) && authHeader.startsWith(BEARER_PREFIX)) {
|
||||
return authHeader.substring(BEARER_PREFIX.length());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前请求
|
||||
*/
|
||||
private static HttpServletRequest getRequest() {
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (attributes != null) {
|
||||
return attributes.getRequest();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,9 @@ public class PageDomain<T> implements Serializable {
|
||||
* @since 2025-11-02
|
||||
*/
|
||||
private List<T> dataList;
|
||||
|
||||
public PageDomain() {
|
||||
}
|
||||
|
||||
public PageDomain(PageParam pageParam, List<T> dataList) {
|
||||
if (pageParam == null) {
|
||||
|
||||
@@ -73,4 +73,11 @@ public class PageParam implements Serializable {
|
||||
}
|
||||
this.offset = (this.page - 1) * this.pageSize;
|
||||
}
|
||||
|
||||
public void setTotal(int total){
|
||||
this.total = total;
|
||||
if (this.pageSize > 0) {
|
||||
this.totalPages = (int) Math.ceil((double) total / pageSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.xyzh.common.dto.sys;
|
||||
|
||||
import org.xyzh.common.dto.BaseDTO;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "来客信息")
|
||||
public class TbGuestDTO extends BaseDTO{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "来客ID")
|
||||
private String userId;
|
||||
|
||||
@Schema(description = "姓名")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "电话")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "邮箱")
|
||||
private String email;
|
||||
|
||||
@Schema(description = "微信ID")
|
||||
private String wechatId;
|
||||
}
|
||||
@@ -24,9 +24,15 @@ public class BaseVO implements Serializable {
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creator;
|
||||
|
||||
@Schema(description = "创建人名称")
|
||||
private String creatorName;
|
||||
|
||||
@Schema(description = "更新人")
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新人名称")
|
||||
private String updaterName;
|
||||
|
||||
@Schema(description = "部门路径")
|
||||
private String deptPath;
|
||||
|
||||
46
urbanLifelineServ/common/common-exception/pom.xml
Normal file
46
urbanLifelineServ/common/common-exception/pom.xml
Normal file
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.xyzh.common</groupId>
|
||||
<artifactId>common-exception</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.xyzh.common</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
<version>${urban-lifeline.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.xyzh.common.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @description 业务异常
|
||||
* @filename BusinessException.java
|
||||
* @author yslg
|
||||
* @copyright yslg
|
||||
* @since 2025-12-17
|
||||
*/
|
||||
@Getter
|
||||
public class BusinessException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final Integer code;
|
||||
private final String message;
|
||||
|
||||
public BusinessException(String message) {
|
||||
super(message);
|
||||
this.code = 500;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public BusinessException(Integer code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public BusinessException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.code = 500;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package org.xyzh.common.exception.handler;
|
||||
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.FieldError;
|
||||
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 org.springframework.web.multipart.MaxUploadSizeExceededException;
|
||||
import org.springframework.web.multipart.support.MissingServletRequestPartException;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import org.xyzh.common.exception.BusinessException;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @description 全局异常处理器
|
||||
* @filename GlobalExceptionHandler.java
|
||||
* @author yslg
|
||||
* @copyright yslg
|
||||
* @since 2025-12-17
|
||||
*/
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
/**
|
||||
* 业务异常
|
||||
*/
|
||||
@ExceptionHandler(BusinessException.class)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public ResultDomain<?> handleBusinessException(BusinessException e) {
|
||||
log.warn("业务异常: {}", e.getMessage());
|
||||
return ResultDomain.failure(e.getCode(), e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数校验异常 - @RequestBody 参数校验失败
|
||||
*/
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public ResultDomain<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
|
||||
String message = e.getBindingResult().getFieldErrors().stream()
|
||||
.map(FieldError::getDefaultMessage)
|
||||
.collect(Collectors.joining("; "));
|
||||
log.warn("参数校验失败: {}", message);
|
||||
return ResultDomain.failure(HttpStatus.BAD_REQUEST.value(), message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数校验异常 - @Validated 校验失败(方法参数直接校验)
|
||||
*/
|
||||
@ExceptionHandler(ConstraintViolationException.class)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public ResultDomain<?> handleConstraintViolationException(ConstraintViolationException e) {
|
||||
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
|
||||
String message = violations.stream()
|
||||
.map(ConstraintViolation::getMessage)
|
||||
.collect(Collectors.joining("; "));
|
||||
log.warn("参数校验失败: {}", message);
|
||||
return ResultDomain.failure(HttpStatus.BAD_REQUEST.value(), message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数绑定异常
|
||||
*/
|
||||
@ExceptionHandler(BindException.class)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public ResultDomain<?> handleBindException(BindException e) {
|
||||
String message = e.getFieldErrors().stream()
|
||||
.map(FieldError::getDefaultMessage)
|
||||
.collect(Collectors.joining("; "));
|
||||
log.warn("参数绑定失败: {}", message);
|
||||
return ResultDomain.failure(HttpStatus.BAD_REQUEST.value(), message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缺少请求参数
|
||||
*/
|
||||
@ExceptionHandler(MissingServletRequestParameterException.class)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public ResultDomain<?> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
|
||||
String message = "缺少必要参数: " + e.getParameterName();
|
||||
log.warn(message);
|
||||
return ResultDomain.failure(HttpStatus.BAD_REQUEST.value(), message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缺少请求Part(multipart/form-data)
|
||||
*/
|
||||
@ExceptionHandler(MissingServletRequestPartException.class)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public ResultDomain<?> handleMissingServletRequestPartException(MissingServletRequestPartException e) {
|
||||
String message = "缺少必要参数: " + e.getRequestPartName();
|
||||
log.warn(message);
|
||||
return ResultDomain.failure(HttpStatus.BAD_REQUEST.value(), message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传大小超限
|
||||
*/
|
||||
@ExceptionHandler(MaxUploadSizeExceededException.class)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public ResultDomain<?> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
|
||||
log.warn("文件上传大小超限: {}", e.getMessage());
|
||||
return ResultDomain.failure(HttpStatus.BAD_REQUEST.value(), "上传文件大小超过限制");
|
||||
}
|
||||
|
||||
/**
|
||||
* 其他未捕获异常
|
||||
*/
|
||||
@ExceptionHandler(Exception.class)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public ResultDomain<?> handleException(Exception e) {
|
||||
log.error("系统异常: ", e);
|
||||
return ResultDomain.failure(HttpStatus.INTERNAL_SERVER_ERROR.value(), "系统异常,请联系管理员");
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package org.xyzh.common.utils;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @description IDUtils.java文件描述
|
||||
* @filename IDUtils.java
|
||||
* @author yslg
|
||||
* @copyright yslg
|
||||
* @since 2025-11-02
|
||||
*/
|
||||
public class IDUtils {
|
||||
|
||||
/**
|
||||
* @description 生成UUID
|
||||
* @return UUID
|
||||
* @author yslg
|
||||
* @since 2025-11-02
|
||||
*/
|
||||
public static String generateID() {
|
||||
return UUID.randomUUID().toString().replaceAll("-", "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.xyzh.common.utils.id;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* @description ID生成工具类
|
||||
* @filename IdUtil.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-12-17
|
||||
*/
|
||||
public class IdUtil {
|
||||
|
||||
private static final AtomicLong SEQUENCE = new AtomicLong(0);
|
||||
|
||||
/**
|
||||
* 生成流水号(UUID格式,无横线)
|
||||
*/
|
||||
public static String getOptsn() {
|
||||
return "optsn"+UUID.randomUUID().toString().replaceAll("-", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成雪花ID(简化实现,使用时间戳+序列号)
|
||||
*/
|
||||
public static String getSnowflakeId() {
|
||||
long timestamp = System.currentTimeMillis();
|
||||
long seq = SEQUENCE.incrementAndGet() % 10000;
|
||||
return String.valueOf(timestamp) + String.format("%04d", seq);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成UUID
|
||||
*/
|
||||
public static String generateUUID() {
|
||||
return UUID.randomUUID().toString().replaceAll("-", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成ID
|
||||
*/
|
||||
public static String generateID() {
|
||||
return UUID.randomUUID().toString().replaceAll("-", "");
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,13 @@
|
||||
package org.xyzh.common.utils.validation;
|
||||
|
||||
import org.xyzh.common.utils.validation.method.InSetValidateMethod;
|
||||
import org.xyzh.common.utils.validation.method.MinFieldsValidateMethod;
|
||||
import org.xyzh.common.utils.validation.method.ObjectValidateMethod;
|
||||
import org.xyzh.common.utils.validation.method.ValidateMethod;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -37,10 +42,10 @@ public class ValidationUtils {
|
||||
for (ValidationParam param : validationParams) {
|
||||
try {
|
||||
Object fieldValue = getFieldValue(obj, param.getFieldName());
|
||||
validateField(param, fieldValue, result);
|
||||
validateField(param, fieldValue, obj, result);
|
||||
} catch (Exception e) {
|
||||
result.addError(param.getFieldLabel() + "字段获取失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -52,7 +57,7 @@ public class ValidationUtils {
|
||||
* @param validationParams 校验参数列表
|
||||
* @return ValidationResult 校验结果
|
||||
*/
|
||||
public static ValidationResult validateMap(Map<String, Object> map, List<ValidationParam> validationParams) {
|
||||
public static <V> ValidationResult validateMap(Map<String, V> map, List<ValidationParam> validationParams) {
|
||||
ValidationResult result = new ValidationResult();
|
||||
|
||||
if (map == null) {
|
||||
@@ -66,7 +71,7 @@ public class ValidationUtils {
|
||||
|
||||
for (ValidationParam param : validationParams) {
|
||||
Object fieldValue = map.get(param.getFieldName());
|
||||
validateField(param, fieldValue, result);
|
||||
validateField(param, fieldValue, map, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -76,9 +81,10 @@ public class ValidationUtils {
|
||||
* @description 校验单个字段
|
||||
* @param param 校验参数
|
||||
* @param fieldValue 字段值
|
||||
* @param obj 原始对象
|
||||
* @param result 校验结果
|
||||
*/
|
||||
private static void validateField(ValidationParam param, Object fieldValue, ValidationResult result) {
|
||||
private static void validateField(ValidationParam param, Object fieldValue, Object obj, ValidationResult result) {
|
||||
String fieldLabel = param.getFieldLabel();
|
||||
|
||||
// 1. 必填校验
|
||||
@@ -176,10 +182,11 @@ public class ValidationUtils {
|
||||
}
|
||||
}
|
||||
|
||||
// 8. 使用ValidateMethod校验(直接传入实例,保留兼容性)
|
||||
// 8. 使用ValidateMethod校验(直接传入实例)
|
||||
if (param.getValidateMethod() != null) {
|
||||
try {
|
||||
if (!param.getValidateMethod().validate(fieldValue)) {
|
||||
Object validateTarget = (param.getValidateMethod() instanceof ObjectValidateMethod) ? obj : fieldValue;
|
||||
if (!param.getValidateMethod().validate(validateTarget)) {
|
||||
String errorMsg = param.getValidateMethod().getErrorMessage();
|
||||
if (errorMsg != null && !errorMsg.isEmpty()) {
|
||||
result.addError(errorMsg);
|
||||
@@ -194,13 +201,27 @@ public class ValidationUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取对象字段值(支持getter方法和直接访问)
|
||||
* @description 获取对象字段值(支持getter方法、直接访问和嵌套路径)
|
||||
* @param obj 对象
|
||||
* @param fieldName 字段名
|
||||
* @param fieldName 字段名,支持嵌套路径如"pageParam.page"
|
||||
* @return 字段值
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
private static Object getFieldValue(Object obj, String fieldName) throws Exception {
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 支持嵌套路径,如"pageParam.page"
|
||||
if (fieldName.contains(".")) {
|
||||
String[] parts = fieldName.split("\\.", 2);
|
||||
Object nestedObj = getFieldValue(obj, parts[0]);
|
||||
if (nestedObj == null) {
|
||||
return null;
|
||||
}
|
||||
return getFieldValue(nestedObj, parts[1]);
|
||||
}
|
||||
|
||||
if (obj instanceof Map) {
|
||||
return ((Map<?, ?>) obj).get(fieldName);
|
||||
}
|
||||
@@ -317,5 +338,46 @@ public class ValidationUtils {
|
||||
.patternDesc("请输入有效的手机号码")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 创建"至少填一个"校验参数
|
||||
* @param fieldNames 字段名列表
|
||||
* @param fieldLabels 字段标签列表
|
||||
* @return ValidationParam
|
||||
*/
|
||||
public static ValidationParam atLeastOne(List<String> fieldNames, List<String> fieldLabels) {
|
||||
return minFields(fieldNames, fieldLabels, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 创建"至少填几个"校验参数
|
||||
* @param fieldNames 字段名列表
|
||||
* @param fieldLabels 字段标签列表
|
||||
* @param minCount 至少填写的数量
|
||||
* @return ValidationParam
|
||||
*/
|
||||
public static ValidationParam minFields(List<String> fieldNames, List<String> fieldLabels, int minCount) {
|
||||
return ValidationParam.builder()
|
||||
.fieldName("_minFields")
|
||||
.fieldLabel(String.join("、", fieldLabels))
|
||||
.validateMethod(new MinFieldsValidateMethod(fieldNames, fieldLabels, minCount))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 创建N选1校验参数(值必须是集合中的一个)
|
||||
* @param fieldName 字段名
|
||||
* @param fieldLabel 字段标签
|
||||
* @param required 是否必填
|
||||
* @param allowedValues 允许的值集合
|
||||
* @return ValidationParam
|
||||
*/
|
||||
public static ValidationParam inSet(String fieldName, String fieldLabel, Boolean required, Collection<?> allowedValues) {
|
||||
return ValidationParam.builder()
|
||||
.fieldName(fieldName)
|
||||
.fieldLabel(fieldLabel)
|
||||
.required(required)
|
||||
.validateMethod(new InSetValidateMethod(fieldLabel, allowedValues))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.xyzh.common.utils.validation.method;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @description N选1校验方法,值必须是指定集合中的一个
|
||||
* @filename InSetValidateMethod.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-12-18
|
||||
*/
|
||||
public class InSetValidateMethod implements ValidateMethod {
|
||||
|
||||
private final Set<Object> allowedValues;
|
||||
private final String errorMessage;
|
||||
|
||||
/**
|
||||
* @description 构造函数
|
||||
* @param fieldLabel 字段标签
|
||||
* @param allowedValues 允许的值集合
|
||||
*/
|
||||
public InSetValidateMethod(String fieldLabel, Collection<?> allowedValues) {
|
||||
this.allowedValues = allowedValues.stream().map(v -> (Object) v).collect(Collectors.toSet());
|
||||
this.errorMessage = fieldLabel + "必须是以下值之一: " + formatValues(allowedValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 构造函数(自定义错误信息)
|
||||
* @param fieldLabel 字段标签
|
||||
* @param allowedValues 允许的值集合
|
||||
* @param customErrorMessage 自定义错误信息
|
||||
*/
|
||||
public InSetValidateMethod(String fieldLabel, Collection<?> allowedValues, String customErrorMessage) {
|
||||
this.allowedValues = allowedValues.stream().map(v -> (Object) v).collect(Collectors.toSet());
|
||||
this.errorMessage = customErrorMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean validate(Object value) {
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
return allowedValues.contains(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "N选1校验";
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 格式化允许值列表
|
||||
* @param values 值集合
|
||||
* @return 格式化后的字符串
|
||||
*/
|
||||
private String formatValues(Collection<?> values) {
|
||||
return values.stream()
|
||||
.map(v -> v instanceof String ? "\"" + v + "\"" : String.valueOf(v))
|
||||
.collect(Collectors.joining(", ", "[", "]"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package org.xyzh.common.utils.validation.method;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @description 至少填几个字段校验方法
|
||||
* @filename MinFieldsValidateMethod.java
|
||||
* @author yslg
|
||||
* @copyright yslg
|
||||
* @since 2025-12-18
|
||||
*/
|
||||
public class MinFieldsValidateMethod implements ObjectValidateMethod {
|
||||
|
||||
|
||||
private final List<String> fieldNames;
|
||||
private final int minCount;
|
||||
private final String errorMessage;
|
||||
|
||||
public MinFieldsValidateMethod(List<String> fieldNames, List<String> fieldLabels) {
|
||||
this(fieldNames, fieldLabels, 1);
|
||||
}
|
||||
|
||||
public MinFieldsValidateMethod(List<String> fieldNames, List<String> fieldLabels, int minCount) {
|
||||
this.fieldNames = fieldNames;
|
||||
this.minCount = minCount;
|
||||
this.errorMessage = String.join("、", fieldLabels) + "至少填写" + minCount + "项";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean validate(Object obj) {
|
||||
if (obj == null || fieldNames == null || fieldNames.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (String fieldName : fieldNames) {
|
||||
try {
|
||||
Object fieldValue = getFieldValue(obj, fieldName);
|
||||
if (fieldValue != null) {
|
||||
if (fieldValue instanceof String) {
|
||||
if (!((String) fieldValue).trim().isEmpty()) {
|
||||
count++;
|
||||
}
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 字段不存在,忽略
|
||||
}
|
||||
}
|
||||
return count >= minCount;
|
||||
}
|
||||
|
||||
private Object getFieldValue(Object obj, String fieldName) throws Exception {
|
||||
if (obj instanceof Map) {
|
||||
return ((Map<?, ?>) obj).get(fieldName);
|
||||
}
|
||||
|
||||
Class<?> clazz = obj.getClass();
|
||||
|
||||
// 尝试getter方法
|
||||
try {
|
||||
String getterName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
|
||||
Method getter = clazz.getMethod(getterName);
|
||||
return getter.invoke(obj);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// 尝试直接访问字段
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
} catch (NoSuchFieldException ex) {
|
||||
// 尝试父类
|
||||
Class<?> superClass = clazz.getSuperclass();
|
||||
if (superClass != null) {
|
||||
Field field = superClass.getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "至少填" + minCount + "个校验";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.xyzh.common.utils.validation.method;
|
||||
|
||||
/**
|
||||
* @description 对象级校验方法接口,表示对整个对象进行校验
|
||||
* @filename ObjectValidateMethod.java
|
||||
* @author yslg
|
||||
* @copyright yslg
|
||||
* @since 2025-12-18
|
||||
*/
|
||||
public interface ObjectValidateMethod extends ValidateMethod {
|
||||
}
|
||||
@@ -20,6 +20,7 @@
|
||||
<module>common-redis</module>
|
||||
<module>common-utils</module>
|
||||
<module>common-all</module>
|
||||
<module>common-exception</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
@@ -59,6 +60,11 @@
|
||||
<artifactId>common-utils</artifactId>
|
||||
<version>${urban-lifeline.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xyzh.common</groupId>
|
||||
<artifactId>common-exception</artifactId>
|
||||
<version>${urban-lifeline.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
</project>
|
||||
Reference in New Issue
Block a user