JAVA自定义注解校验输入字段是否符合规则
- 1、类中某个属性,前端只能传入某几个固定的值,使用方法: 在类中属性上使用该注解
- 2、类中某个属性,输入的值只能是数字
- 3、某个属性只能是时间类型的值
校验输入信息是否正确有很多方式,这里我们将一种自定义注解实现校验。通过注解的方式,可以避免在项目中输入大量的校验语句,保证代码整洁。可以通过实现 ConstraintValidator<自定义注解,校验的类型> 接口的方式实现
话不多说,上代码
1、类中某个属性,前端只能传入某几个固定的值,使用方法: 在类中属性上使用该注解
案例:
@InputValueMatch(values = {"BUSINESS", "FUNCTION"})
private String roleType;
这种写法表示,roleType的值只能是BUSINESS或FUNCTION
实现:
package com.upbim.twin.park.common.validation.validator;
import com.google.common.collect.Lists;
import com.upbim.twin.park.common.validation.constraint.InputValueMatch;
import com.upbim.twin.park.common.validation.constraint.TwinForestryType;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl;
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintViolationCreationContext;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public class InputValueMatchValidator implements ConstraintValidator<InputValueMatch, String> {
private Class<? extends TwinForestryType>[] types;
private List<String> values;
private boolean required;
private boolean emptyToNull;
@Override
public void initialize(InputValueMatch constraintAnnotation) {
types = constraintAnnotation.types();
values = Arrays.asList(constraintAnnotation.values());
required = constraintAnnotation.required();
emptyToNull = constraintAnnotation.emptyToNull();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
final List<String> valuesInTypes = Arrays.stream(types).map(clazz ->
clazz.isEnum() ? clazz.getEnumConstants()[0].getAllNames() : null
).filter(Objects::nonNull).flatMap(Collection::stream).collect(Collectors.toList());
List<String> allValidValues = Lists.newArrayList();
allValidValues.addAll(valuesInTypes);
allValidValues.addAll(values);
// 空字符串转null(因为'空字符串'与'null'具有不同的语意,所以需要指定emptyToNull=true,才会做此转换)
if (emptyToNull) {
value = StringUtils.isEmpty(value) ? null : value;
}
// 参数非必传条件下:入参为null,通过!
if (value == null && !required) {
return true;
} else {
// 参数必传条件下:参数为null 或者 参数不匹配指定的字符串组,不通过!
if (value == null || allValidValues.stream().noneMatch(value::equals)) {
String field = getField((ConstraintValidatorContextImpl) context);
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(String.format("[%s]字段:传入参数 [%s] 无效,参数只能是: %s", field, value, allValidValues))
.addConstraintViolation();
return false;
}
}
return true;
}
private String getField(ConstraintValidatorContextImpl context) {
List<ConstraintViolationCreationContext> creationContexts = context.getConstraintViolationCreationContexts();
return creationContexts.get(0).getPath().getLeafNode().asString();
}
}
自定义注解:
package com.upbim.twin.park.common.validation.constraint;
import com.upbim.twin.park.common.validation.validator.InputValueMatchValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Documented
@Constraint(validatedBy = InputValueMatchValidator.class)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface InputValueMatch {
/**
* 制定上传的参数必须匹配数组列表中的值
*
* @return values 匹配列表
*/
String[] values() default {};
/**
* 参数是否必传
* true:必传
* false:非必传(可以为null,但如果不为null,则必须匹配特定内容)
*
* @return required
*/
boolean required() default true;
/**
* 校验不同过时的提示
*
* @return message
*/
String message() default "Invalid input value!";
/**
* 将空字符串置为null(默认false)
*
* @return emptyToNull
*/
boolean emptyToNull() default false;
/**
* 上传的字符串必须匹配枚举中的值 name()
*
* @return twin-forestryType
*/
Class<? extends TwinForestryType>[] types() default {};
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@interface List {
InputValueMatch[] value();
}
}
2、类中某个属性,输入的值只能是数字
案例:
@NumberValid(message = "type只能是数字类型", type = Integer.class)
private Object type;
实现:
package com.upbim.twin.park.common.validation.constraint;
import com.upbim.twin.park.common.validation.validator.NumberValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = NumberValidator.class)
public @interface NumberValid {
/**
* 默认错误提示
*/
String message() default "param is invalid";
/**
* 输入的内容必须可以转化成 指定类型
*/
Class<?> type();
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String[] extendNames() default {};
}
package com.upbim.twin.park.common.validation.validator;
import com.upbim.twin.park.common.validation.constraint.NumberValid;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.math.BigDecimal;
public class NumberValidator implements ConstraintValidator<NumberValid, Object> {
private Class type = null;
@Override
public void initialize(NumberValid constraintAnnotation) {
type = constraintAnnotation.type();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
try {
if (BigDecimal.class == type) {
new BigDecimal(String.valueOf(value));
} else if (Long.class == type) {
Long.valueOf(String.valueOf(value));
} else if (Double.class == type) {
Double.valueOf(String.valueOf(value));
} else if (Integer.class == type) {
Integer.valueOf(String.valueOf(value));
}
} catch (Exception ex) {
return false;
}
return true;
}
}
3、某个属性只能是时间类型的值
实现:
package com.upbim.twin.park.common.validation.constraint;
import com.upbim.twin.park.common.validation.validator.DateTimeValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = DateTimeValidator.class)
@Documented
public @interface DateTimeValid {
String message() default "格式错误";
String format() default "yyyy-MM-dd HH:mm";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
package com.upbim.twin.park.common.validation.validator;
import com.upbim.twin.park.common.validation.constraint.DateTimeValid;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.text.SimpleDateFormat;
@Slf4j
public class DateTimeValidator implements ConstraintValidator<DateTimeValid, String> {
private DateTimeValid dateTime;
@Override
public void initialize(DateTimeValid dateTime) {
this.dateTime = dateTime;
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
/** 如果 value 为空则不进行格式验证,为空验证可以使用 @NotBlank @NotNull @NotEmpty 等注解来进行控制,职责分离*/
if (StringUtils.isEmpty(value)) {
return true;
}
String format = dateTime.format();
if (value.length() != format.length()) {
return false;
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
try {
simpleDateFormat.parse(value);
} catch (Exception e) {
return false;
}
return true;
}
}
感谢浏览,如果帮到你了,可以收藏使用。