目录:
1、前言 2、加入依赖 3、创建VO实体类 4、创建接口 5、创建全局异常处理器 6、添加效验注解 7、分组 8、优化参数效验 9、@Validated或@Valid区别 10、效果
这里的参数效验指的是在Web接口中接收参数时对参数的合法性进行效验;正常情况的做法是在接收到参数时,在方法体中对参数进行核验;这样做的代码整洁性太差、代码侵入性太强;这里推荐一个利用SpringBoot
中推荐的注解方式进行参数效验。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
@Data
public class Parameter implements Serializable {
String scene;
ArrayList<Point> path;
Double speed;
Integer state;
JSONObject inputValues;
}
这个类用于接收客户端的请求参数;使用实体类接收参数时实体类需要有Getter、Setter方法,我这里用到Lombok
下的@Data
注解自动生成这些方法,所以就没有加Getter、Setter方法。
@PostMapping("")
public RequestResult app(@Validated @RequestBody Parameter parameter) {
RequestResult requestResult = new RequestResult();
requestResult.appendData("result", app.start(parameter));
return requestResult;
}
需要在接收参数的实体类上加入@Validated
或@Valid
注解,否则参数效验不会生效,这两个注解的区别后面说明。
相信能看到这里的小伙伴使用SpringMVC
创建接口应该问题不大,所以这里就不展示接口类了,重点在使用实体类接收参数时如何使用注解对参数进行效验。
@RestControllerAdvice
public class ParameterExceptionHandler {
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public RequestResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
RequestResult requestResult = new RequestResult();
requestResult.setCode(400);
requestResult.setMessage(Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage());
requestResult.appendData("url",request.getRequestURI());
return requestResult;
}
}
当参数效验失败,会抛出MethodArgumentNotValidException
异常,这个类的作用就是捕获这个异常,然后将这个异常翻译成用户能看懂的样子。
用于效验的注解可用于方法参数中,也可以用于实体类中;如果是实体类中使用的话,需要在方法参数实体类前加入@Validated
注解;如果实体类中有嵌套其他的实体类,也需要参数效验,则使用@Valid
注解标识,@Validated
或@Valid
注解区别会在后面说明。
@NotEmpty
表示不能为null
,也不能为空字符串,当类型为集合时集合不能为空,但是字符串可以是" "
(注意引号之间有一个空格)。
@NotEmpty(message = "季节不能为空")
String scene;
@NotNull
表示不可以为null
,但可以是空字符串;
@NotNull(message = "季节不能为空")
String scene;
@NotBlank
用于字符串,表示不能为null,也不能为空字符串,空格字符串也不行。
@Length
用于字符串上,限制字符串长度。
@Length(max = 1,min = 1,message = "用于表示季节的字符为A(夏季)、B(冬季)")
String scene;
@Size
用于字符串、数组和集合上,也是限制长度。
@Size(min = 2, message = "表示路线的坐标点应该不少于2个")
ArrayList<Point> path;
@Min
和@Max
表示最小值和最大值,用于字符串或数值上,如果是字符串则转换为BigDecimal
再进行比较。
@Min(value = 10,message = "速度应大于等于10千米每小时")
@Max(value = 20,message = "速度应小于等于20千米每小时")
Double speed;
@Range
表示取值范围,与@Min
和@Max
组合使用类似。
@Range(min = 1, max = 3, message = "状态应使用1-正常、2-加速、3-慢速")
Integer state;
@Email
效验邮箱格式。
@Email(message = "格式不符合规范")
String mail;
@URL
表示该参数值必须是一个URL。
@URL(message = "格式不符合规范")
String url;
@Pattern
表示该参数值必须符合这个正则表达式。
@Pattern(regexp = "^[A-Z]+$",message = "格式不符合规范")
String scene;
使用@Validated
注解可设置参数效验分组;示例如下:
public interface Autumn {
}
public interface Spring {
}
表示当前是Spring
分组;
@PostMapping("")
public RequestResult app(@Validated({Spring.class}) @RequestBody Parameter parameter) {
RequestResult requestResult = new RequestResult();
requestResult.appendData("result", app.start(parameter));
return requestResult;
}
表示只有当前分组是Autumn
时才会生效。
@Size(min = 2, message = "表示路线的坐标点应该不少于2个",groups = {Autumn.class})
ArrayList<Point> path;
如上的效验过程中,会效验所有的参数,然后把不合格的全部返回给客户端。
通过如下配置可以做到当有一个参数效验不通过时即返回,不用效验所有参数,增加效率。
@Configuration
public class AppConfig {
@Bean
public Validator validator(AutowireCapableBeanFactory beanFactory) {
try (ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
.configure().failFast(true)
.constraintValidatorFactory(new SpringConstraintValidatorFactory(beanFactory))
.buildValidatorFactory()) {
return validatorFactory.getValidator();
}
}
}
@Validated
或@Valid
区别@Validated
注解可被用于方法、参数上;无法用于成员属性上;
@Valid
注解可被用于方法、构造方法、参数和成员属性上;
@Validated
注解提供分组用法,可根据分组情况提供不同的参数效验规则;
@Valid
注解不提供;
参数效验未通过后的效果如下:
{
"code": 400,
"message": "表示路线的坐标点应该不少于2个",
"data": {
"url": "/test"
}
}