一波带走,SpringBoot中的各种参数校验方案汇总
1、前言
在控制器类的方法里自己写校验逻辑代码当然也可以,只是代码比较丑陋,有点"low"。业界有更好的处理方法,分别阐述如下。 2、PathVariable校验
用法是:路径变量:正则表达式。当请求URI不满足正则表达式时,客户端将收到404错误码。不方便的地方是,不能通过捕获异常的方式,向前端返回统一的、自定义格式的响应参数。 3、方法参数校验@GetMapping("/validate1") @ResponseBody public String validate1( @Size(min = 1,max = 10,message = "姓名长度必须为1到10")@RequestParam("name") String name, @Min(value = 10,message = "年龄最小为10")@Max(value = 100,message = "年龄最大为100") @RequestParam("age") Integer age) { return "validate1"; }
如果前端传递的参数不满足规则,则抛出异常。注解Size、Min、Max来自validation-api.jar,更多注解参见 相关标准 小节。4、表单对象/VO对象校验
当参数是VO时,可以在VO类的属性上添加校验注解。
其中,Future注解要求必须是相对当前时间来讲"未来的"某个时间。
5、自定义校验规则5.1 自定义注解校验
需要自定义一个注解类和一个校验类。
使用我们自定义的注解:
5.2 分组校验
/** * 使用Defaul分组进行验证 * @param resume * @return */ @PostMapping("/validate5") public String addUser(@Validated(value = Resume.Default.class) @RequestBody Resume resume) { return "validate5"; } /** * 使用Default、Update分组进行验证 * @param resume * @return */ @PutMapping("/validate6") public String updateUser(@Validated(value = {Resume.Update.class, Resume.Default.class}) @RequestBody Resume resume) { return "validate6"; }
建立了两个分组,名称分别为Default、Update。POST方法提交时使用Defaut分组的校验规则,PUT方法提交时同时使用两个分组规则。 6、异常拦截器
通过设置全局异常处理器,统一向前端返回校验失败信息。 import com.scj.springbootdemo.WebResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.CollectionUtils; import org.springframework.validation.ObjectError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import java.util.List; import java.util.Set; /** * 全局异常处理器 */ @ControllerAdvice public class GlobalExceptionHandler { private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** * 用来处理bean validation异常 * @param ex * @return */ @ExceptionHandler(ConstraintViolationException.class) @ResponseBody public WebResult resolveConstraintViolationException(ConstraintViolationException ex){ WebResult errorWebResult = new WebResult(WebResult.FAILED); Set> constraintViolations = ex.getConstraintViolations(); if(!CollectionUtils.isEmpty(constraintViolations)){ StringBuilder msgBuilder = new StringBuilder(); for(ConstraintViolation constraintViolation :constraintViolations){ msgBuilder.append(constraintViolation.getMessage()).append(","); } String errorMessage = msgBuilder.toString(); if(errorMessage.length()>1){ errorMessage = errorMessage.substring(0,errorMessage.length()-1); } errorWebResult.setInfo(errorMessage); return errorWebResult; } errorWebResult.setInfo(ex.getMessage()); return errorWebResult; } @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseBody public WebResult resolveMethodArgumentNotValidException(MethodArgumentNotValidException ex){ WebResult errorWebResult = new WebResult(WebResult.FAILED); List objectErrors = ex.getBindingResult().getAllErrors(); if(!CollectionUtils.isEmpty(objectErrors)) { StringBuilder msgBuilder = new StringBuilder(); for (ObjectError objectError : objectErrors) { msgBuilder.append(objectError.getDefaultMessage()).append(","); } String errorMessage = msgBuilder.toString(); if (errorMessage.length() > 1) { errorMessage = errorMessage.substring(0, errorMessage.length() - 1); } errorWebResult.setInfo(errorMessage); return errorWebResult; } errorWebResult.setInfo(ex.getMessage()); return errorWebResult; } }7、相关标准
JSR 303 是Bean验证的规范 ,Hibernate Validator 是该规范的参考实现,它除了实现规范要求的注解外,还额外实现了一些注解。
validation-api-1.1.0.jar 包括如下约束注解:
hibernate-validator-5.3.6.jar 包括如下约束注解:
8、同时校验2个或更多个字段/参数
常见的场景之一是,查询某信息时要输入开始时间和结束时间。显然,结束时间要 开始时间。可以在查询VO类上使用自定义注解,下面的例子来自这里。划重点:@ValidAddress使用在类上。