初版提交

This commit is contained in:
zengzefeng 2021-04-16 17:53:30 +08:00
parent 8a9c714586
commit 255aede037
13 changed files with 974 additions and 5 deletions

View File

@ -0,0 +1,135 @@
package cn.iocoder.dashboard.framework.validator.custom;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.dashboard.framework.validator.custom.handler.ValidateHandlerHelper;
import com.alibaba.fastjson.JSON;
import io.swagger.annotations.ApiModelProperty;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.internal.util.Contracts;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.constraints.NotNull;
import javax.validation.executable.ExecutableValidator;
import javax.validation.metadata.BeanDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import static org.hibernate.validator.internal.util.logging.Messages.MESSAGES;
/**
* 自定义参数校验器
* <p>
* 愿景实现自动生成验证失败的消息
* 1字段名根据{@link ApiModelProperty#value()}注解获取
* 2状态根据{@link NotNull}{@link javax.validation.constraints.NotEmpty}等生成
* 3拼接返回消息
* <p>
* 如果实现后则以后只需要加{@code @NotNull @NotEmpty}注解不需要再一个个写{@link NotNull#message()}的值
* <p>
* 2021.4.15 此次实现是类似于多数据源的实现通过{@link ValidatorProxy}代理
* 默认校验类({@link org.hibernate.validator.internal.engine.ValidatorImpl})和自定义校验类(this)
* · 该类只处理参数校验{@link this#validateParameters(Object, Method, Object[], Class[])}
* · 其他校验都交给默认实现
* · 因此这个类只实现了参数校验的方法
*
* @author zzf
* @date 2021/4/8 14:09
*/
@Slf4j
public class CustomValidator implements Validator, ExecutableValidator {
@Override
public <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {
return validate(object, null, new Object[]{object}, groups);
}
@SneakyThrows
@Override
public <T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, Class<?>... groups) {
return null;
}
@SneakyThrows
@Override
public <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, Class<?>... groups) {
return null;
}
@Override
public BeanDescriptor getConstraintsForClass(Class<?> clazz) {
return null;
}
@SneakyThrows
@Override
public <T> T unwrap(Class<T> type) {
return null;
}
@Override
public ExecutableValidator forExecutables() {
return this;
}
@Override
public <T> Set<ConstraintViolation<T>> validateParameters(T object, Method method, Object[] parameterValues, Class<?>... groups) {
return validate(object, method, parameterValues, groups);
}
@Override
public <T> Set<ConstraintViolation<T>> validateReturnValue(T object, Method method, Object returnValue, Class<?>... groups) {
return null;
}
@SneakyThrows
@Override
public <T> Set<ConstraintViolation<T>> validateConstructorParameters(Constructor<? extends T> constructor, Object[] parameterValues, Class<?>... groups) {
return null;
}
@SneakyThrows
@Override
public <T> Set<ConstraintViolation<T>> validateConstructorReturnValue(Constructor<? extends T> constructor, T createdObject, Class<?>... groups) {
return null;
}
private <T> Set<ConstraintViolation<T>> validate(T object, Executable executable, Object[] parameterValues, Class<?>... groups) {
try {
log.warn("Object: {}, Executable: {}, parameterValues: {}, groups: {}",
JSON.toJSONString(object),
JSON.toJSONString(executable),
JSON.toJSONString(parameterValues),
JSON.toJSONString(groups)
);
} catch (Exception ignore) {
}
Set<ConstraintViolation<T>> result = new HashSet<>();
sanityCheckGroups(groups);
if (ArrayUtil.isNotEmpty(parameterValues)) {
for (Object param : parameterValues) {
Field[] fields = param.getClass().getDeclaredFields();
for (Field field : fields) {
result.addAll(ValidateHandlerHelper.validate(field, param, object, field.getName()));
}
}
}
return result;
}
private void sanityCheckGroups(Class<?>[] groups) {
Contracts.assertNotNull(groups, MESSAGES.groupMustNotBeNull());
for (Class<?> clazz : groups) {
if (clazz == null) {
throw new IllegalArgumentException(MESSAGES.groupMustNotBeNull());
}
}
}
}

View File

@ -0,0 +1,137 @@
package cn.iocoder.dashboard.framework.validator.custom;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.helpers.MessageFormatter;
import javax.validation.constraints.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Date;
import java.util.function.BiFunction;
import java.util.function.Function;
/**
* 校验注解枚举
*
* @author zzf
* @date 2021/4/13 11:35
*/
@Slf4j
@Getter
@AllArgsConstructor
public enum ValidateAnnotationEnum {
NOT_NULL(NotNull.class,
"必传!",
(object, param) -> {
return ObjectUtil.isNotNull(object);
}
),
NOT_EMPTY(NotEmpty.class,
"内容不能为空!",
(object, param) -> {
return ObjectUtil.isNotEmpty(object);
}
),
NOT_BLANK(NotBlank.class,
"内容需包含有效字符!",
(object, param) -> {
if (object instanceof String) {
return StrUtil.isNotBlank(String.valueOf(object));
}
return false;
}
),
MAX(true,
Max.class,
"不能超过{}",
(object, param) -> {
if (object instanceof Integer) {
return param > (Integer) object;
}
if (object instanceof BigDecimal | object instanceof Double | object instanceof Short) {
return new BigDecimal(String.valueOf(param)).compareTo(new BigDecimal(String.valueOf(object))) > 0;
}
if (object instanceof Long) {
return param > (Long) object;
}
if (object instanceof Date) {
return param > ((Date) object).getTime();
}
return false;
}
),
MIN(true,
Min.class,
"不能小于{}",
(object, param) -> {
if (object instanceof Integer) {
return param < (Integer) object;
}
if (object instanceof BigDecimal | object instanceof Double | object instanceof Short) {
return new BigDecimal(String.valueOf(param)).compareTo(new BigDecimal(String.valueOf(object))) < 0;
}
if (object instanceof Long) {
return param < (Long) object;
}
if (object instanceof Date) {
return param < ((Date) object).getTime();
}
return false;
});
private final boolean hadParam;
private final Class<? extends Annotation> annotation;
private final String msg;
private final BiFunction<Object, Long, Boolean> checkFunction;
ValidateAnnotationEnum(Class<? extends Annotation> annotation, String msg, BiFunction<Object, Long, Boolean> checkFunction) {
this.hadParam = false;
this.annotation = annotation;
this.msg = msg;
this.checkFunction = checkFunction;
}
public String formatMsg(String fieldName, String... param) {
if (hadParam) {
return fieldName + MessageFormatter.arrayFormat(msg, param).getMessage();
}
return fieldName + msg;
}
public boolean checkParam(Field field, Object object, Long... param) throws IllegalAccessException {
if (hadParam && param != null && param.length == 1) {
return checkFunction.apply(field.get(object), param[0]);
}
if (!hadParam) {
return checkFunction.apply(field.get(object), null);
}
log.error("[参数校验失败!] Enum = {}, TargetClass = {}, FieldName = {}, param = {}",
this.toString(),
object.getClass().getSimpleName(),
field.getName(),
param);
return true;
}
public interface IfmFunction {
Boolean apply(Field field, Object object, Function<Object, Boolean> isValid);
}
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.dashboard.framework.validator.custom;
import org.springframework.boot.validation.MessageInterpolatorFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import javax.validation.Validator;
/**
* 参数校验器配置类
*
* @author zzf
* @date 2021/4/13 14:13
*/
@Configuration(proxyBeanMethods = false)
public class ValidateConfig {
/**
* 配置一个校验器的代理类自定义选择校验器进行校验
* <p>
* 这里必须加上@Primary注解否则会跟{@link WebMvcConfigurationSupport#mvcValidator()}的冲突
*/
@Primary
@Bean
public Validator primaryValidator() {
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
CustomValidator customValidator = new CustomValidator();
factoryBean.afterPropertiesSet();
return new ValidatorProxy(factoryBean.getValidator(), customValidator);
}
}

View File

@ -0,0 +1,96 @@
package cn.iocoder.dashboard.framework.validator.custom;
import io.swagger.annotations.ApiModelProperty;
import lombok.SneakyThrows;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.constraints.NotNull;
import javax.validation.executable.ExecutableValidator;
import javax.validation.metadata.BeanDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Set;
/**
* 自定义参数校验器
* <p>
* ###未完成###
* <p>
* 愿景实现自动生成验证失败的消息
* 1字段名根据{@link ApiModelProperty#value()}注解获取
* 2状态根据{@link NotNull}{@link javax.validation.constraints.NotEmpty}等生成
* 3拼接返回消息
* <p>
* 如果实现后则以后只需要加{@code @NotNull @NotEmpty}注解不需要再一个个写{@link NotNull#message()}的值
*
* @author zzf
* @date 2021/4/8 14:09
*/
public class ValidatorProxy implements Validator, ExecutableValidator {
private final Validator defaultValidator;
private final Validator customValidator;
public ValidatorProxy(Validator defaultValidator,
Validator customValidator) {
this.defaultValidator = defaultValidator;
this.customValidator = customValidator;
}
@Override
public <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {
return customValidator.validate(object, groups);
}
@SneakyThrows
@Override
public <T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, Class<?>... groups) {
return defaultValidator.validateProperty(object, propertyName, groups);
}
@SneakyThrows
@Override
public <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, Class<?>... groups) {
return defaultValidator.validateValue(beanType, propertyName, value, groups);
}
@Override
public BeanDescriptor getConstraintsForClass(Class<?> clazz) {
return defaultValidator.getConstraintsForClass(clazz);
}
@SneakyThrows
@Override
public <T> T unwrap(Class<T> type) {
return type.newInstance();
}
@Override
public ExecutableValidator forExecutables() {
return this;
}
@Override
public <T> Set<ConstraintViolation<T>> validateParameters(T object, Method method, Object[] parameterValues, Class<?>... groups) {
return customValidator.forExecutables().validateParameters(object, method, parameterValues, groups);
}
@Override
public <T> Set<ConstraintViolation<T>> validateReturnValue(T object, Method method, Object returnValue, Class<?>... groups) {
return defaultValidator.forExecutables().validateReturnValue(object, method, returnValue, groups);
}
@SneakyThrows
@Override
public <T> Set<ConstraintViolation<T>> validateConstructorParameters(Constructor<? extends T> constructor, Object[] parameterValues, Class<?>... groups) {
return defaultValidator.forExecutables().validateConstructorParameters(constructor, parameterValues, groups);
}
@SneakyThrows
@Override
public <T> Set<ConstraintViolation<T>> validateConstructorReturnValue(Constructor<? extends T> constructor, T createdObject, Class<?>... groups) {
return defaultValidator.forExecutables().validateConstructorReturnValue(constructor, createdObject, groups);
}
}

View File

@ -0,0 +1,47 @@
package cn.iocoder.dashboard.framework.validator.custom.handler;
import org.slf4j.helpers.MessageFormatter;
import javax.validation.constraints.Max;
import java.math.BigDecimal;
import java.util.Date;
/**
* 最大值校验处理类
*
* @author zzf
* @date 2021/4/15 9:21
*/
public class MaxHandler implements ValidateAnnotationHandler<Max> {
@Override
public Class<Max> getAnnotation() {
return Max.class;
}
@Override
public String validate(Max validateAnnotation, Object fieldValue) {
long value = validateAnnotation.value();
boolean valid;
if (fieldValue instanceof Integer) {
valid = value > (Integer) fieldValue;
} else if (fieldValue instanceof BigDecimal | fieldValue instanceof Double | fieldValue instanceof Short) {
valid = new BigDecimal(String.valueOf(value)).compareTo(new BigDecimal(String.valueOf(fieldValue))) > 0;
} else if (fieldValue instanceof Long) {
valid = value > (Long) fieldValue;
} else if (fieldValue instanceof Date) {
valid = value > ((Date) fieldValue).getTime();
} else {
valid = true;
}
if (!valid) {
MessageFormatter.format(getResultMsgWhenInvalid(), value).getMessage();
}
return null;
}
@Override
public String getResultMsgWhenInvalid() {
return "的值必须小于{}!";
}
}

View File

@ -0,0 +1,47 @@
package cn.iocoder.dashboard.framework.validator.custom.handler;
import org.slf4j.helpers.MessageFormatter;
import javax.validation.constraints.Min;
import java.math.BigDecimal;
import java.util.Date;
/**
* 最小值校验处理类
*
* @author zzf
* @date 2021/4/15 9:21
*/
public class MinHandler implements ValidateAnnotationHandler<Min> {
@Override
public Class<Min> getAnnotation() {
return Min.class;
}
@Override
public String validate(Min validateAnnotation, Object fieldValue) {
long value = validateAnnotation.value();
boolean valid;
if (fieldValue instanceof Integer) {
valid = value < (Integer) fieldValue;
} else if (fieldValue instanceof BigDecimal | fieldValue instanceof Double | fieldValue instanceof Short) {
valid = new BigDecimal(String.valueOf(value)).compareTo(new BigDecimal(String.valueOf(fieldValue))) < 0;
} else if (fieldValue instanceof Long) {
valid = value < (Long) fieldValue;
} else if (fieldValue instanceof Date) {
valid = value < ((Date) fieldValue).getTime();
} else {
valid = true;
}
if (!valid) {
MessageFormatter.format(getResultMsgWhenInvalid(), value).getMessage();
}
return null;
}
@Override
public String getResultMsgWhenInvalid() {
return "的值必须小于{}!";
}
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.dashboard.framework.validator.custom.handler;
import cn.hutool.core.util.StrUtil;
import javax.validation.constraints.NotBlank;
/**
* 非空字符校验处理类
*
* @author zzf
* @date 2021/4/15 9:21
*/
public class NotBlankHandler implements ValidateAnnotationHandler<NotBlank> {
@Override
public Class<NotBlank> getAnnotation() {
return NotBlank.class;
}
@Override
public String validate(NotBlank validateAnnotation, Object fieldValue) {
if(StrUtil.isBlankIfStr(fieldValue)) {
return getResultMsgWhenInvalid();
}
return null;
}
@Override
public String getResultMsgWhenInvalid() {
return "格式错误或者没有有效字符!";
}
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.dashboard.framework.validator.custom.handler;
import cn.hutool.core.util.ObjectUtil;
import javax.validation.constraints.NotEmpty;
/**
* 内容不可空校验处理类
*
* @author zzf
* @date 2021/4/15 9:21
*/
public class NotEmptyHandler implements ValidateAnnotationHandler<NotEmpty> {
@Override
public Class<NotEmpty> getAnnotation() {
return NotEmpty.class;
}
@Override
public String validate(NotEmpty validateAnnotation, Object fieldValue) {
if(ObjectUtil.isEmpty(fieldValue)) {
return getResultMsgWhenInvalid();
}
return null;
}
@Override
public String getResultMsgWhenInvalid() {
return "不能为空!!!!";
}
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.dashboard.framework.validator.custom.handler;
import cn.hutool.core.util.ObjectUtil;
import org.springframework.beans.factory.annotation.Value;
import javax.validation.constraints.NotNull;
/**
* 必传校验处理类
*
* @author zzf
* @date 2021/4/15 9:21
*/
public class NotNullHandler implements ValidateAnnotationHandler<NotNull> {
@Override
public Class<NotNull> getAnnotation() {
return NotNull.class;
}
@Override
public String validate(NotNull validateAnnotation, Object fieldValue) {
if (ObjectUtil.isNull(fieldValue)) {
return getResultMsgWhenInvalid();
}
return null;
}
@Override
public String getResultMsgWhenInvalid() {
return "必传!";
}
}

View File

@ -0,0 +1,65 @@
package cn.iocoder.dashboard.framework.validator.custom.handler;
import cn.hutool.core.util.ReflectUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
/**
* 校验注解处理抽象接口
* <p>
* ### 实现类要使用起来需要注册到{@link ValidateHandlerHelper} ###
*
* @author zzf
* @date 2021/4/15 9:22
*/
public interface ValidateAnnotationHandler<T extends Annotation> {
/**
* 获取实现类的具体的注解类对象
*/
Class<T> getAnnotation();
/**
* 判断参数字段是否存在该注解
*
* @param field 字段对象
* @return 是否存在该注解
*/
default Boolean isAnnotationPresent(Field field) {
return field.isAnnotationPresent(getAnnotation());
}
/**
* 校验字段值如果值合法返回null不合法返回消息内容
*
* @param field 需要校验的字段
* @param targetObject 字段所在的对象
* @return 值合法返回null不合法返回消息内容
*/
default String validate(Field field, Object targetObject) {
T annotation = field.getAnnotation(getAnnotation());
return validate(annotation, ReflectUtil.getFieldValue(targetObject, field));
}
/**
* 校验字段值如果值合法返回null不合法返回消息内容
* <p>
* 这里之所以没有直接返回boolean而是直接返回msg
* 是为了适配如{@link javax.validation.constraints.Max}{@link javax.validation.constraints.Min}
* 消息中需要获取注解属性值的注解
*
* @param validateAnnotation 标记的注解
* @param fieldValue 字段值
* @return 如果值合法返回null不合法返回消息内容
*/
String validate(T validateAnnotation, Object fieldValue);
/**
* @return 消息模板
*/
String getResultMsgWhenInvalid();
}

View File

@ -0,0 +1,282 @@
package cn.iocoder.dashboard.framework.validator.custom.handler;
import cn.hutool.core.collection.CollectionUtil;
import io.swagger.annotations.ApiModelProperty;
import lombok.Setter;
import org.hibernate.validator.internal.engine.path.PathImpl;
import javax.validation.*;
import javax.validation.metadata.ConstraintDescriptor;
import javax.validation.metadata.ValidateUnwrappedValue;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;
/**
* 校验处理辅助类
*
* @author zzf
* @date 2021/4/15 9:49
*/
public class ValidateHandlerHelper {
private static final Set<ValidateAnnotationHandler<?>> handlerSet = new HashSet<>(10);
/**
* 初始化注册校验处理类
*/
static {
handlerSet.add(new NotNullHandler());
handlerSet.add(new NotEmptyHandler());
handlerSet.add(new NotBlankHandler());
handlerSet.add(new MaxHandler());
handlerSet.add(new MinHandler());
}
/**
* 校验指定字段值是否合法
* <p>
* 这里针对集合类型字段做递归校验
* 实现深层对象参数值校验
*
* @param field 字段对象
* @param paramObject 需要校验的字段所在的对象
* @param rootBean 需要校验的方法所在的类对象
* @param propertyPath 属性路径
* @param <T> 需要校验的方法所在的类
* @return 校验结果集
*/
public static <T> Set<ConstraintViolation<T>> validate(Field field,
Object paramObject,
T rootBean,
String propertyPath) {
Set<ConstraintViolation<T>> result = new HashSet<>();
Object fieldValue;
try {
field.setAccessible(true);
fieldValue = field.get(paramObject);
} catch (IllegalAccessException e) {
return result;
}
if (fieldValue instanceof Collection) {
Collection<?> collectionFieldValue = (Collection<?>) fieldValue;
if (CollectionUtil.isNotEmpty(collectionFieldValue)) {
for (Object collectionElement : collectionFieldValue) {
Field[] fields = collectionElement.getClass().getDeclaredFields();
for (Field collectionFieldElementField : fields) {
result.addAll(
validate(
collectionFieldElementField,
collectionElement,
rootBean,
propertyPath + "." + collectionFieldElementField.getName()
)
);
}
}
}
}
CustomConstraintViolation<T> violation = validateField(field, paramObject, rootBean, propertyPath, fieldValue);
if (violation != null) {
result.add(violation);
}
return result;
}
/**
* 校验字段值如果值合法返回null不合法返回消息内容
*
* @param field 需要校验的字段
* @param targetObject 字段所在的对象
* @return 值合法返回null不合法返回消息内容
*/
private static <T> CustomConstraintViolation<T> validateField(Field field,
Object targetObject,
T rootBean,
String propertyPath,
Object fieldValue) {
Optional<ValidateAnnotationHandler<?>> handlerOptional =
handlerSet.stream().filter(s -> s.isAnnotationPresent(field)).findFirst();
if (handlerOptional.isPresent()) {
String validate = handlerOptional.get().validate(field, targetObject);
if (validate != null) {
String fieldComment;
if (field.isAnnotationPresent(ApiModelProperty.class)) {
ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
fieldComment = annotation.value();
} else {
fieldComment = field.getName();
}
String msg = fieldComment + handlerOptional.get().getResultMsgWhenInvalid();
CustomConstraintDescriptor<?> customConstraintDescriptor =
new CustomConstraintDescriptor<>(field.getAnnotation(handlerOptional.get().getAnnotation()));
return CustomConstraintViolation.of(rootBean, msg, propertyPath, fieldValue, customConstraintDescriptor);
}
}
return null;
}
/**
* 校验不通过的返回值对象
*
* @param <T> 需要校验的方法所在的类
*/
public static class CustomConstraintViolation<T> implements ConstraintViolation<T> {
public static <T> CustomConstraintViolation<T> of(T rootBean,
String msg,
String path,
Object invalidValue,
ConstraintDescriptor<?> constraintDescriptor) {
CustomConstraintViolation<T> constraintViolation = new CustomConstraintViolation<>();
constraintViolation.setMessage(msg);
constraintViolation.setRootBean(rootBean);
constraintViolation.setPropertyPath(PathImpl.createPathFromString(path));
constraintViolation.setInvalidValue(invalidValue);
constraintViolation.setConstraintDescriptor(constraintDescriptor);
return constraintViolation;
}
@Setter
private String message;
@Setter
private T rootBean;
@Setter
private Path propertyPath;
@Setter
private Object invalidValue;
@Setter
private ConstraintDescriptor<?> constraintDescriptor;
@Override
public String getMessage() {
return message;
}
@Override
public String getMessageTemplate() {
return null;
}
@Override
public T getRootBean() {
return rootBean;
}
@Override
public Class<T> getRootBeanClass() {
return null;
}
@Override
public Object getLeafBean() {
return null;
}
@Override
public Object[] getExecutableParameters() {
return new Object[0];
}
@Override
public Object getExecutableReturnValue() {
return null;
}
@Override
public Path getPropertyPath() {
return propertyPath;
}
@Override
public Object getInvalidValue() {
return invalidValue;
}
@Override
public ConstraintDescriptor<?> getConstraintDescriptor() {
return constraintDescriptor;
}
@Override
public <U> U unwrap(Class<U> type) {
return null;
}
}
public static class CustomConstraintDescriptor<R extends Annotation> implements ConstraintDescriptor<R> {
private final R annotation;
public CustomConstraintDescriptor(R annotation) {
this.annotation = annotation;
}
@Override
public R getAnnotation() {
return annotation;
}
@Override
public String getMessageTemplate() {
return null;
}
@Override
public Set<Class<?>> getGroups() {
return null;
}
@Override
public Set<Class<? extends Payload>> getPayload() {
return null;
}
@Override
public ConstraintTarget getValidationAppliesTo() {
return null;
}
@Override
public List<Class<? extends ConstraintValidator<R, ?>>> getConstraintValidatorClasses() {
return null;
}
@Override
public Map<String, Object> getAttributes() {
return new HashMap<>();
}
@Override
public Set<ConstraintDescriptor<?>> getComposingConstraints() {
return null;
}
@Override
public boolean isReportAsSingleViolation() {
return false;
}
@Override
public ValidateUnwrappedValue getValueUnwrapping() {
return null;
}
@Override
public <U> U unwrap(Class<U> type) {
return null;
}
}
}

View File

@ -0,0 +1,24 @@
package cn.iocoder.dashboard.framework.validator.custom;
/**
* 参数校验实现
* <p>
* 功能说明https://blog.csdn.net/qq_38688267/article/details/115720412
* <p>
* 环境搭建
* 1实现{@link cn.iocoder.dashboard.framework.validator.custom.handler.ValidateAnnotationHandler}
* 2将实现类注册到{@link cn.iocoder.dashboard.framework.validator.custom.handler.ValidateHandlerHelper}
* 3实现全局异常拦截{@link javax.validation.ConstraintViolationException}异常
*
* 使用步骤
* 1给存在需要校验方法的Controller加上{@link javax.validation.Validator} 注解
* 2给需要校验的方法的参数加上 {@link javax.validation.Valid} 注解
* 3给需要校验的参数属性加上想要校验的注解
* {@link javax.validation.constraints.NotNull} {@link javax.validation.constraints.NotEmpty}
* <p>
* DEMO:
* {@link cn.iocoder.dashboard.modules.system.controller.auth.SysAuthController#login(cn.iocoder.dashboard.modules.system.controller.auth.vo.auth.SysAuthLoginReqVO)}
* <p>
* 亮点
* 校验过程中有实现对集合类型对象的递归校验实现深层校验
*/

View File

@ -10,31 +10,32 @@ import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import java.io.Serializable;
@ApiModel("账号密码登陆 Request VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class SysAuthLoginReqVO {
public class SysAuthLoginReqVO implements Serializable {
@ApiModelProperty(value = "账号", required = true, example = "yudaoyuanma")
@NotEmpty(message = "登陆账号不能为空")
@NotEmpty
@Length(min = 4, max = 16, message = "账号长度为 4-16 位")
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
private String username;
@ApiModelProperty(value = "密码", required = true, example = "buzhidao")
@NotEmpty(message = "密码不能为空")
@NotEmpty
@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
private String password;
@ApiModelProperty(value = "验证码", required = true, example = "1024")
@NotEmpty(message = "验证码不能为空")
@NotEmpty
private String code;
@ApiModelProperty(value = "验证码的唯一标识", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62")
@NotEmpty(message = "唯一标识不能为空")
@NotEmpty
private String uuid;
}