当前位置:网站首页>Enum + Validation 的个人最佳实践 demo 分享
Enum + Validation 的个人最佳实践 demo 分享
2022-07-07 15:39:00 【小水牛...】
前言
很多场景中我们需要校验前端传来的参数是否属于某个 Enum
值,分享一段个人最佳实践的 demo
:
Enum
的最简声明@OfEnum & OfEnumValidator
Test suite
Enum 声明
通常 Enum
的声明是映射到对应的 DB
字段,个人实践是直接以 Enum Name
对应具体值,无需在 Enum
里包含释义信息等,比如 SexEnum
声明为 man woman
而不是类似 男("man") 女("woman")
,这样也方便后续 Validator
类的编写
public enum SexEnum {
man
, woman
;
}
@OfEnum
@Constraint(
validatedBy = {
OfEnumValidator.class }
)
@Target({
ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface OfEnum {
Class<?> enumType();
String message() default "目标值必须是 ${enumType.simpleName} 类型的枚举值";
Class<?>[] groups() default {
};
Class<? extends Payload>[] payload() default {
};
}
该注解主要用于字段、参数上结合对应的 OfEnumValidator
执行校验
@Constraint
注解声明对应的OfEnumValidator
- 属性
enumType
声明对应的枚举类型 message
中引用EL
表达式输出合理的校验信息
OfEnumValidator
public class OfEnumValidator implements ConstraintValidator<OfEnum, String> {
private List<String> enums;
// 枚举值初始化
@Override
public void initialize(OfEnum constraintAnnotation) {
enums = Optional.ofNullable(constraintAnnotation)
.map(OfEnum::enumType)
.filter(Class::isEnum)
.map(Class::getEnumConstants)
.map(arr -> Arrays.stream(arr)
.map(Object::toString)
.collect(Collectors.toList()))
.orElse(new ArrayList<>());
}
@Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
return !ObjectUtils.isEmpty(enums) && enums.contains(s);
}
}
OfEnumValidator
类负责执行 @OfEnum
注解对应的校验
- 基于指定的枚举类来初始化
enums
属性,直接基于toString
方法,因此前文推荐Enum
的简单声明 isValid
进行校验
Test
public class OfEnumTest {
ApplicationContextRunner runner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class));
@Validated
static class Handler {
public void handle(@OfEnum(enumType = SexEnum.class) String sex) {
}
}
static class Config {
@Bean
public Handler handler() {
return new Handler();
}
}
@Test
public void test() {
runner.withUserConfiguration(Config.class)
.run(context -> {
Handler bean = context.getBean(Handler.class);
bean.handle("man");
assertThatThrownBy(() -> bean.handle("error"))
.isInstanceOf(ConstraintViolationException.class)
.hasMessage("handle.sex: 目标值必须是 SexEnum 类型的枚举值");
});
}
}
针对 @OfEnum
注解的测试类:
- 基于
ApplicationContextRunner
编写,很好用的测试辅助类,之前有分享 - 可以看到,当传入
SexEnum
成员之外的值时,会抛出校验异常
总结
以上就是个人 Enum + Validation
的最佳实践分享
边栏推荐
- skimage学习(3)——使灰度滤镜适应 RGB 图像、免疫组化染色分离颜色、过滤区域最大值
- Sator推出Web3游戏“Satorspace” ,并上线Huobi
- rpcms获取指定分类下的文章的方法
- 【TPM2.0原理及应用指南】 12、13、14章
- Sator a lancé le jeu web 3 "satorspace" et a lancé huobi
- mysql官网下载:Linux的mysql8.x版本(图文详解)
- redis主从、哨兵主备切换搭建一步一步图解实现
- 到底有多二(Lua)
- 【源码解读】| LiveListenerBus源码解读
- Siggraph 2022 best technical paper award comes out! Chen Baoquan team of Peking University was nominated for honorary nomination
猜你喜欢
随机推荐
DevOps 的运营和商业利益指南
Sator推出Web3遊戲“Satorspace” ,並上線Huobi
skimage学习(3)——使灰度滤镜适应 RGB 图像、免疫组化染色分离颜色、过滤区域最大值
DNS series (I): why does the updated DNS record not take effect?
Matplotlib绘图界面设置
[source code interpretation] | source code interpretation of livelistenerbus
First in China! Todesk integrates RTC technology into remote desktop, with clearer image quality and smoother operation
Flash build API service
Matplotlib绘制三维图形
Leetcode brush questions day49
Linux 安装mysql8.X超详细图文教程
LeetCode 1981. Minimize the difference between the target value and the selected element one question per day
MRS离线数据分析:通过Flink作业处理OBS数据
LeetCode 1654. The minimum number of jumps to get home one question per day
[image sensor] correlated double sampling CDs
LeetCode 1774. The dessert cost closest to the target price is one question per day
【TPM2.0原理及应用指南】 9、10、11章
【饭谈】那些看似为公司着想,实际却很自私的故事 (一:造轮子)
LeetCode 312. Poke balloon daily
Skimage learning (3) -- adapt the gray filter to RGB images, separate colors by immunohistochemical staining, and filter the maximum value of the region