SpringBoot自定义校验注解

2022-03-03  本文已影响0人  Java编程日记

校验注解的作用
系统执行业务逻辑之前,会对输入数据进行校验,检测数据是否有效合法的。所以我们可能会写大量的 if else 等判断逻辑,特别是在不同方法出现相同的数据时,校验的逻辑代码会反复出现,导致代码冗余,阅读性和可维护性极差。

自定义校验注解
引入依赖
Hibernate框架中有一个组件 hibernate-validator 专门用于数据校验,在平常的Spring项目中虽然数据层不使用Hibernate做 ORM 框架,但是 hibernate-validator 也经常被集成来做数据校验。

<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.7.Final</version>
</dependency>
下面我们写一个用于 URL 校验的注解,实现一个简单的网站信息管理的 URL 校验,做校验的方式我们也使用现成的apache工具包中提供的校验工具。

<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.7</version>
</dependency>
实现注解
校验注解

/**

}
校验类

校验类需要实现 ConstraintValidator<T,E> 接口,第一个泛型为注解,第二个为校验的数据类型。

实现这个接口必须要重写 isValid() 方法,在其中实现主要的校验逻辑。

public class IsUrlValidator implements ConstraintValidator<IsUrl,String> {
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 {}
创建一个 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 = MethodArgumentNotValidException.class)
@ResponseBody
public Object errorHandler(HttpServletRequest request, MethodArgumentNotValidException e) {
List<ObjectError> 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

上一篇 下一篇

猜你喜欢

热点阅读