说明:很多时候,前端传递的参数会是枚举,如果前后端约定好,那么传递的枚举值不会有差错,可以不需要校验。但作为后端程序员,要有安全意识,请求未必都来自前端,可能来自apifox或其他调试工具,这样传递的参数可能稀奇古怪,枚举值可能就是意料之外的,所以后端程序员还是需要校验参数值是否在枚举项内。
本文介绍如何使用 validation 框架,自定义一个校验器,校验参数值是否在枚举类之中,关于 validation 使用介绍,参考下面这篇文章:
自定义注解
创建一个注解,用于给DTO属性打上标记
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
/**
* 校验参数是否在枚举中
*/
@Documented
@Constraint(validatedBy = InEnumerationValidator.class)
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface InEnumeration {
String message() default "参数值不在枚举中";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
Class<? extends Enum<?>> enumClass();
}
校验器
校验实现,获取DTO字段值与指定枚举类查询、比较,返回校验结果。
注意这里获取枚举项编码的方法是 getCode,如果后面创建的枚举类,获取编码的方法不叫这个,会报错的。
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* 参数是否在枚举内校验器
*/
public class InEnumerationValidator implements ConstraintValidator<InEnumeration, String> {
private Class<? extends Enum<?>> enumClass;
@Override
public void initialize(InEnumeration constraintAnnotation) {
this.enumClass = constraintAnnotation.enumClass();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// 没有值,不校验,默认为true
if (value == null) {
return true;
}
try {
// 假设枚举有一个 getCode() 方法返回你想要校验的值
Method getCodeMethod = enumClass.getMethod("getCode");
Object[] enumConstants = enumClass.getEnumConstants();
return Arrays.stream(enumConstants)
.map(e -> {
try {
return getCodeMethod.invoke(e);
} catch (Exception ex) {
return null;
}
})
.anyMatch(code -> code != null && code.toString().equals(value));
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
使用
定义一个枚举类,如下,注意要生成 getCode() 方法,不然校验器里拿不到,校验那会报错,我这用 @Getter 注解生成了。
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 季节枚举
*/
@AllArgsConstructor
@Getter
public enum SeasonEnum {
SPRING("spring", "春天"),
SUMMER("summer", "夏天"),
AUTUMN("autumn", "秋天"),
WINTER("winter", "冬天");
public final String code;
private final String desc;
}
在参数对象的属性上,指定枚举类和校验不通过时的返回信息
import com.hezy.annotation.InEnumeration;
import com.hezy.enums.SeasonEnum;
import lombok.Data;
/**
* 参数
*/
@Data
public class Param {
@InEnumeration(enumClass = SeasonEnum.class, message = "季节不正确,不在枚举内")
private String season;
}
创建一个接口,如下:
@PostMapping("/enum")
public String demo4(@RequestBody @Validated Param param) {
return "success";
}
启动项目,测试,“大夏天”不在枚举项内,返回错误
“summer”在枚举内,返回成功
总结
本文介绍如何使用 validation 框架生成一个校验参数是否在枚举内的校验器