收集 Java 程序员在处理接口的参数校验时觉得麻烦的例子,收集无法使用 @NotNull 等注解来校验参数的例子

235 天前
 sticki

对于 Java 程序员来说,接口的参数校验一般是通过 @NotNull 、 @NotBlank 、 @Size(min = 0, max = 255) 等这些注解来校验的。

但是有一些情况下,这些注解无法满足校验的需求,比如下面这段代码:

public class Test {

	/**
	 * 状态,值必须为枚举类 Status 中的 code
	 */
	Integer status;

	/**
	 * 是否开启语音提示
	 */
	Boolean enableVoice;

	/**
	 * 语音提示内容
	 */
	String voiceContent;

}

这里涉及到两种参数校验是现有的注解无法满足的:

  1. 状态的 Int 值必须存在于枚举类中
  2. 当开启语音提示时,内容必须不为空,本质上是上下文关联的参数校验

这里我只是进行举例,我主要是想收集一下大家遇到的类型情况,然后我想做一个组件,能够尽可能的解决这些问题。

其实我已经有一个这样的组件了,但是担心自己考虑到的情况还不太够,所以想收集一下大家的建议,之后完善一下然后开源出来给大家使用。

6548 次点击
所在节点    Java
30 条回复
jov1
234 天前
也会有类似问题,通用的用提供的注解声明,这种情况判定来动态处理验证的,我目前放在业务实现里面校验处理,因为可能还需要对数据处理,比如 enableVoice 不等于 true ,如果前端传入了 voiceContent ,后端其实还类似需要清空这个值,那么顺手可以把校验 enableVoice=true 时 voiceContent 的非空校验做了,
类似于
if (BooleanUtils.isTrue(xx.getEnableVoice()) {

}
jov1
234 天前
if (BooleanUtils.isTrue(xx.getEnableVoice()) {
// 校验 voiceContent 是否为空
} else {
xx.setVoiceContent(null);
} 应该也可以实现 ConstraintValidator 来自定义校验规则,拓展注解之类的,只是目前是类似这样处理的
unclevv
234 天前
只有我一个人觉得 Boolean enableVoice 定义不规范吗,Boolean voiceSwitch 与 String voiceContent 对应,作为变量,enableVoice 应该是用作方法名
layxy
234 天前
1.自定义校验注解和校验器
2.建议手动校验吧,自动校验也可以实现,但是把业务判断逻辑放到配置中感觉不是太好
KongLiu
234 天前
自定义验证+正则
liuzhaowei55
234 天前
可以看看 laravel 的 validation 设计,完爆其他所有语言,框架的校验
目前比较需要的就是你提到的这个校验入参值是否在给定可选值中
Karte
234 天前
对于枚举的验证做法:
1. 硬代码, 通过 Assert 相关断言判断
2. 通过 @Min, @Max 设定枚举边界.
3. 通过实现 `ConstraintValidator` 对类进行校验.
4. 通过代理 + 反射的方式添加自定义处理注解, 然后通过定义 `spel` 表达式确认是否校验通过.
```java
@FieldValid(spel = "#p1.field != 0")
```

用硬代码虽然会略显丑陋, 但是在新增枚举时可以不用改动代码.
而 @Min, @Max 在枚举修改后需要同步修改, 如果没有相关注释说明会存在隐性 BUG.
使用 `ConstraintValidator` 相对比较好, 因为能够自定义实现校验逻辑. 但是验证范围只能为对应类, 如果不做继承的话
无法实现复用
代理 + 反射会有略微性能损耗, 而 `spel` 表达式需要额外学习, 且有点耗费性能 (通过反射获取数据). 在多参数时需要在编译时增加 `-parameters` 否则参数名无法写入, `spel` 就无法获取到对应的对象, 校验就失败了.
Ashe007
234 天前
@halov 通常的 aop 是基于代理模式实现,为了一个参数检验,引入更大的项目复杂度,消耗更多的服务器资源,你觉得可取吗?
sticki
233 天前
我才添加完附言,就没人回复了,沉底了🤡🤡
Aresxue
227 天前
第一确实存在这样的业务诉求,这是很合理的,别被其它人绕晕了;
第二实现方式最好不是自定义一套注解,理解成本很高,具体很好的实现方式一下子没想好,最好是可以和原来搭配使用,比如 SpelNotNull 就可以改成 @NotNull + @When("enableVoice == true"),上面只是举个例子;
第三注意这里存在潜在的性能问题对于高并发接口来说这些校验最好是直接写在业务代码中的,但是绝大多数接口并不是什么高并发接口,这个东西的用处应当是用来快速实现校验功能,当这个接口的 QPS 要求发生变化时再重新设计实现,当然更多接口可能永远都都不到这一步。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1036488

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX