SpringBoot自定义校验注解
校验注解的作用
系统执行业务逻辑之前,会对输入数据进行校验,检测数据是否有效合法的。所以我们可能会写大量的if else
等判断逻辑,特别是在不同方法出现相同的数据时,校验的逻辑代码会反复出现,导致代码冗余,阅读性和可维护性极差。
自定义校验注解
引入依赖
Hibernate框架中有一个组件hibernate-validator
专门用于数据校验,在平常的Spring项目中虽然数据层不使用Hibernate做ORM
框架,但是hibernate-validator
也经常被集成来做数据校验。
org.hibernate.validator
hibernate-validator
6.1.7.Final
下面我们写一个用于
URL
校验的注解,实现一个简单的网站信息管理的URL
校验,做校验的方式我们也使用现成的apache工具包中提供的校验工具。
commons-validator
commons-validator
1.7
实现注解
校验注解
/**
* 会将注解信息包含在javadoc中
*/
@Documented
/**
* 1、RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;
* 2、RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,
*这是默认的生命周期;
* 3、RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
*
* 一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解,比如@Deprecated使用RUNTIME注解
* 如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;
* 如果只是做一些检查性的操作,比如 @Override 和 @Deprecated,使用SOURCE 注解。
*/
@Retention(RetentionPolicy.RUNTIME)
/**
* 作用在字段上
* TYPE - 作用在类上面
* FILED - 作用在属性上面
* METHOD - 作用在方法上
* CONSTRUCTION - 作用在构造器上
* PARAM - 作用在方法参数上
* 允许多种的情况是 @Target({ElementType.FIELD,ElementType.METHOD})
*/
@Target(ElementType.FIELD)
/**
* 对应校验类
*/
@Constraint(validatedBy = IsUrlValidator.class)
public @interface IsUrl {
/**
* 是否 强校验
* @return
*/
boolean required() default true;
/**
* 校验不通过返回信息
* @return
*/
String message() default "请输入正确的url";
/**
* 所属分组,即在有分组的情况下,只校验所在分组参数
* @return
*/
Class>[] groups() default {};
/**
* 主要是针对bean,很少使用
*
* @return 负载
*/
Class extends Payload>[] payload() default {};
}
校验类
校验类需要实现
ConstraintValidator
接口,第一个泛型为注解,第二个为校验的数据类型。实现这个接口必须要重写
isValid()
方法,在其中实现主要的校验逻辑。public class IsUrlValidator implements ConstraintValidator {
private boolean isRequired;
/**
* 初始化,获取是否强校验
* @param constraintAnnotation
*/
@Override
public void initialize(IsUrl constraintAnnotation) {
isRequired = constraintAnnotation.required();
}@Override
public boolean isValid(String s, ConstraintValidatorContext context) {
if (!isRequired){
return true;
}else {
UrlValidator validator = UrlValidator.getInstance();
return validator.isValid(s);
}
}
}
使用自定义注解
创建
Insert
、Update
分组别用于区分和开启校验用于分组的类需要继承
javax.validation.groups.Default
接口public interface Update extends Default {}
public interface Insert extends Default {}
【SpringBoot自定义校验注解】创建一个
WebSite
类,对其中url
、alternateUrl
进行校验,这个字段分别属于Insert
分组、Update
分组的时候进行字段校验。public class WebSite {
/**
* id
*/
private Integer id;
/**
* 网站名称
*/
private String name;
/**
* 网址
*/
@IsUrl(groups = Insert.class)
private String url;
/**
* 备用网址
*/
@IsUrl(groups = Update.class)
private String alternateUrl;
}
具体校验方式如下,在insert接口对
Insert
分组进行校验,也就是校验url
属性,在updateAlternate接口对Update
分组进行校验,也就是对alternateUrl
字段进行校验。@RestController
@RequestMapping("/website")
public class WebSiteController {
@RequestMapping("/insert")
public void insert(@RequestBody @Validated(Insert.class) WebSite site){
System.out.println(site);
}@RequestMapping("/updateAlternate")
public void updateAlternateUrl(@RequestBody @Validated(Update.class) WebSite site){
System.out.println(site);
}
}
若校验不通过,代码会抛出
MethodArgumentNotValidException
异常,我们实现一个统一异常处理类来处理这个异常报错,并返回校验提示信息。@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
// 处理接口参数数据格式错误异常
@ExceptionHandler(value = https://www.it610.com/article/MethodArgumentNotValidException.class)
@ResponseBody
public Object errorHandler(HttpServletRequest request, MethodArgumentNotValidException e) {
List allErrors = e.getBindingResult().getAllErrors();
String message = allErrors.stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(";
"));
log.error("{}请求,发生参数校验异常:{}",request.getServletPath(),message);
return message;
}
}
使用http工具调用接口,返回相关信息
首先使用一个错误的
url
参数调用 insert
接口,校验不通过,但是调用updateAlternate
接口可以通过。POST http://localhost:8080/website/insert
Content-Type: application/json
{
"id": 1,
"name": "百度",
"url":"htps://www.baidu.com/",
"alternateUrl":"https://www.baidu.com/"
}###POST http://localhost:8080/website/updateAlternate
Content-Type: application/json
{
"id": 1,
"name": "百度",
"url":"htps://www.baidu.com/",
"alternateUrl":"https://www.baidu.com/"
}
调用
insert
接口的返回及日志打印如下HTTP/1.1 200
Content-Type: text/plain;
charset=UTF-8
Content-Length: 21
Date: Wed, 02 Mar 2022 15:30:23
GMTKeep-Alive: timeout=60
Connection: keep-alive请输入正确的url
--------------------------------------
xxx.GlobalExceptionHandler : /website/insert请求,发生参数校验异常:请输入正确的url
推荐阅读
- #|SpringBoot集成Elasticseach
- Springboot基于Redisson实现Redis分布式可重入锁【案例到源码分析】
- 解决springboot环境切换失效的问题
- mybatis和springboot整合
- java|节后上班第一天公司要你用SpringBoot实现万能文件在线预览
- 神经网络|构建自定义 CNN 模型(识别 COVID-19)
- 计算机毕业设计|Java项目(基于springboot+vue的学生宿舍管理系统—计算机毕业设计)
- 技术笔记|SpringBoot 静态资源访问
- SpringBoot返回Json对象报错(返回对象为空{})
- JavaScript|JavaScript 自定义对象