在项目中引入hibernate-validator,在springboot项目中,可以直接引入对应的starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
然后创建一个全局异常处理类
import com.xiaomifeng1010.response.R;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Path;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 全局异常处理器
* @author
* @version 1.0
* @date: 2020/12/12
*/
@Order(value = Ordered.HIGHEST_PRECEDENCE)
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* @description: json对象参数验证
* @author:
* @date: 2022/2/19
* @param exception
* @return: R
**/
@ExceptionHandler(value = MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleValidException(MethodArgumentNotValidException exception) {
BindingResult result = exception.getBindingResult();
String errorMessage= StringUtils.EMPTY;
if (result.hasErrors()) {
errorMessage= result.getFieldErrors().stream().map(FieldError::getDefaultMessage).collect(Collectors.toList()).toString();
log.error("请求对象[{}]验证错误信息{}",result.getFieldErrors().get(0).getObjectName(),errorMessage);
}
return R.fail(HttpStatus.BAD_REQUEST.value(),errorMessage);
}
/**
* 统一处理请求参数校验(实体对象传参)
*
* @param e BindException
* @return
*/
@ExceptionHandler(BindException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleBindException(BindException e) {
StringBuilder message = new StringBuilder();
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
for (FieldError error : fieldErrors) {
message.append(error.getField()).append(error.getDefaultMessage()).append(",");
}
message = new StringBuilder(message.substring(0, message.length() - 1));
return R.fail(HttpStatus.BAD_REQUEST.value(),message.toString());
}
/**
* 统一处理请求参数校验(普通传参)
*
* @param e ConstraintViolationException
* @return
*/
@ExceptionHandler(value = ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleConstraintViolationException(ConstraintViolationException e) {
StringBuilder message = new StringBuilder();
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
for (ConstraintViolation<?> violation : violations) {
Path path = violation.getPropertyPath();
String[] pathArr = StringUtils.splitByWholeSeparatorPreserveAllTokens(path.toString(), ".");
message.append(pathArr[1]).append(violation.getMessage()).append(",");
}
message = new StringBuilder(message.substring(0, message.length() - 1));
return R.fail(HttpStatus.BAD_REQUEST.value(),message.toString());
}
}
R对象为封装的统一的接口响应对象
接着可以写一个controller测试一下几种参数类型验证会被哪个handler拦截处理
package com.xiaomifeng1010.controller;
import com.xiaomifeng1010.test.Student;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
/**
* @author xiaomifeng1010
* @version 1.0
* @date: 2021/12/28 16:31
* @Description
*/
@Api("测试验证参数")
@RestController
@Validated
public class TestController {
@ApiOperation("测试请求参数string类型")
@PostMapping("/hello")
public String test(@RequestParam("name") @NotBlank(message = "姓名不能为空") String name){
return name;
}
@ApiOperation("测试请求参数bean类型,表单参数较多,直接与java对象的属性名绑定")
@PostMapping("/helloBean")
public String testBeanParam(@Valid Student student){
return student.getName();
}
@ApiOperation("测试请求参数为json类型")
@PostMapping("/helloJson")
public String testJson(@Valid @RequestBody Student student){
return student.getName();
}
}
Student类
import lombok.Data;
import javax.validation.constraints.Min;
import javax.validation.constraints.PastOrPresent;
import javax.validation.constraints.Size;
import java.util.Date;
/**
* @author xiaomifeng1010
* @version 1.0
* @date: 2021/8/5 13:41
* @Description
*/
@Data
public class Student {
@Size(min = 3,max = 10,message = "名字长度范围为3-10")
String name;
@Min(value = 1,message = "年龄不能小于1岁")
Integer age;
String idCard;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@PastOrPresent(message = "生日不能早于今天")
Date birthDay;
}
然后在knife4j在线文档中测试,或者在postman中测试
先测试第一个接口方法,在name参数值中敲一个空格,然后项目断点会进入异常处理类中
是抛出的ConstraintViolationException这个异常
接着再测试第二个接口参数,多个参数,用一个对象接收
抛出的是绑定异常BindingException
然后测试请求体为json格式的数据
抛出的异常为MethodArgumentNotValidException