一个强大的 Java 参数校验包,基于 SpEL 实现,扩展自 javax.validation 包,几乎支持所有场景下的参数校验。
「SpEL Validator」是基于 SpEL 的参数校验包,也是 javax.validation 的扩展增强包,用于简化参数校验。
它解决了什么问题 | 简介 | 快速开始 | 使用指南 | 示例项目 | 常见问题 | 更新日志 | 贡献指南 | 捐赠支持 | 联系作者
枚举值字段校验:
@SpelAssert(assertTrue = " T(cn.sticki.enums.UserStatusEnum).getByCode(#this.userStatus) != null ", message = "用户状态不合法")
private Integer userStatus;
多字段联合校验:
@NotNull
private Integer contentType;
@SpelNotNull(condition = "#this.contentType == 1", message = "语音内容不能为空")
private Object audioContent;
@SpelNotNull(condition = "#this.contentType == 2", message = "视频内容不能为空")
private Object videoContent;
复杂逻辑校验,调用静态方法:
// 中文算两个字符,英文算一个字符,要求总长度不超过 10
// 调用外部静态方法进行校验
@SpelAssert(assertTrue = "T(cn.sticki.util.StringUtil).getLength(#this.userName) <= 10", message = "用户名长度不能超过10")
private String userName;
调用 Spring Bean(需要使用 @EnableSpelValidatorBeanRegistrar 开启Spring Bean支持):
// 这里只是简单举例,实际开发中不建议这样判断用户是否存在
@SpelAssert(assertTrue = "@userService.getById(#this.userId) != null", message = "用户不存在")
private Long userId;
更多使用场景,欢迎探索和补充!
目前仅测试了 JDK8 环境,理论上来说 JDK8+ 应该都是支持的。
添加依赖
<dependency>
<groupId>cn.sticki</groupId>
<artifactId>spel-validator</artifactId>
<version>Latest Version</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot-starter-web.version}</version>
</dependency>
在接口参数上使用 @Valid
或 @Validated
注解
@RestController
@RequestMapping("/example")
public class ExampleController {
/**
* 简单校验示例
*/
@PostMapping("/simple")
public Resp<Void> simple(@RequestBody @Valid SimpleExampleParamVo simpleExampleParamVo) {
return Resp.ok(null);
}
}
在实体类上使用 @SpelValid
注解,同时在需要校验的字段上使用 @SpelNotNull
等约束注解
@Data
@SpelValid
public class SimpleExampleParamVo {
@NotNull
private Boolean switchAudio;
/**
* 当 switchAudio 为 true 时,校验 audioContent,audioContent 不能为null
*/
@SpelNotNull(condition = "#this.switchAudio == true", message = "语音内容不能为空")
private Object audioContent;
}
添加异常处理器,处理校验异常
@RestControllerAdvice
public class ControllerExceptionAdvice {
@ExceptionHandler({BindException.class, MethodArgumentNotValidException.class})
public Resp<Void> handleBindException(BindException ex) {
String msg = ex.getFieldErrors().stream()
.map(error -> error.getField() + " " + error.getDefaultMessage())
.reduce((s1, s2) -> s1 + "," + s2)
.orElse("");
return new Resp<>(400, msg);
}
}
发起请求,即可看到校验结果
请求体:
{
"switchAudio": true,
"audioContent": null
}
响应体
{
"code": 400,
"message": "audioContent 语音内容不能为空",
"data": null
}
请求体
{
"switchAudio": false,
"audioContent": null
}
响应体
{
"code": 200,
"message": "成功",
"data": null
}
请求体
{
"switchAudio": null,
"audioContent": null
}
响应体
{
"code": 400,
"message": "switchAudio 不能为null",
"data": null
}
注意:本组件的目的不是代替
javax.validation
的校验注解,而是作为一个扩展,方便某些场景下的参数校验。 能够使用javax.validation
的场景就不要使用spel-validator
,因为spel-validator
会有一定的性能损耗。
需要满足以下两个条件,才会对带注解的元素进行校验:
@Valid
或 @Validated
注解@SpelValid
注解如果只满足第一个条件,那么只会对带 @NotNull
、@NotEmpty
、@NotBlank
等注解的元素进行校验。
如果只满足第二个条件,那么不会对任何元素进行校验。
这是因为 @SpelValid
注解是基于 javax.validation.Constraint
实现的,只有在 @Valid
或 @Validated
注解的支持下才会生效。
而 spel-validator
提供的约束注解是基于 @SpelValid
进行扫描校验的,只有在 @SpelValid
注解生效的情况下才会执行约束校验。
目前支持的约束注解有:
注解 | 说明 | 对标 javax.validation |
---|---|---|
@SpelAssert |
逻辑断言校验 | 无 |
@SpelNotNull |
非 null 校验 | @NotNull |
@SpelNotEmpty |
集合、字符串、数组大小非空校验 | @NotEmpty |
@SpelNotBlank |
字符串非空串校验 | @NotBlank |
@SpelNull |
必须为 null 校验 | @Null |
@SpelSize |
集合、字符串、数组长度校验 | @Size |
每个约束注解都包含三个默认的属性:
message
:校验失败时的提示信息。group
:分组条件,支持 SpEL 表达式,当分组条件满足时,才会对带注解的元素进行校验。condition
:约束开启条件,支持 SpEL 表达式,当 表达式为空 或 计算结果为true 时,才会对带注解的元素进行校验。默认情况下,解析器无法识别 SpEL 表达式中的 Spring Bean。
如果需要在 SpEL 表达式中调用 Spring Bean,需要在启动类上添加 @EnableSpelValidatorBeanRegistrar
注解,
开启 Spring Bean 支持。
@EnableSpelValidatorBeanRegistrar
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
参考 cn.sticki.validator.spel.SpelConstraint
类,实现自定义约束注解。
如果你使用过 javax.validation
的自定义约束注解,那么你会发现 SpEL Validator
的自定义约束注解几乎与 javax.validation
一致。
代码里使用了较多的反射,会有一定的性能损耗,但我也加了一些缓存来减少损耗。
我进行了简单的测试,在示例项目中,我对接口进行了多次随机调用,除了刚开始的前几次请求耗时会达到 10ms 以上, 后续请求耗时会稳定在 1ms 左右。
您可以打开 debug 日志,过滤 Spel validate cost time
语句,查看校验耗时,会得到类似如下的日志内容:
其中每条记录表示一次接口调用的完整校验耗时。
https://github.com/stick-i/spel-validator/releases
非常欢迎您来参与项目贡献,但希望您可以先在 issue 中提出您的想法,我们可以一起讨论,然后再进行代码编写。
微信赞赏 | 支付宝赞赏 |
---|---|