Springboot中使用spring-boot-starter-validation
引言
在日常项目中,偶尔会有后段接口需要对入参进行参数校验的过程,springboot官方提供了对应的校验依赖,现在总结记录一下在使用的过程中会遇到很多坑
在使用此依赖时,我的项目版本为:
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
其中的日志平台可能与当前项目中的日志平台冲突,导致在运行时报错
若报:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:~/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.17.0/log4j-slf4j-impl-2.17.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:~/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
Exception in thread "main" java.lang.ExceptionInInitializerError
at com.main(App.java:16)
Caused by: org.apache.logging.log4j.LoggingException: log4j-slf4j-impl cannot be present with log4j-to-slf4j
at org.apache.logging.slf4j.Log4jLoggerFactory.validateContext(Log4jLoggerFactory.java:60)
at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:44)
at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:33)
at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:53)
at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:33)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:363)
at org.apache.commons.logging.LogAdapter$Slf4jAdapter.createLocationAwareLog(LogAdapter.java:130)
at org.apache.commons.logging.LogAdapter.createLog(LogAdapter.java:91)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:67)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:59)
at org.springframework.boot.SpringApplication.<clinit>(SpringApplication.java:196)
... 1 more
则剔除
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
若报:
Exception in thread "main" java.lang.ExceptionInInitializerError
at com.main(App.java:16)
Caused by: org.apache.logging.log4j.LoggingException: log4j-slf4j-impl cannot be present with log4j-to-slf4j
at org.apache.logging.slf4j.Log4jLoggerFactory.validateContext(Log4jLoggerFactory.java:60)
at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:44)
at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:33)
at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:53)
at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:33)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:363)
at org.apache.commons.logging.LogAdapter$Slf4jAdapter.createLocationAwareLog(LogAdapter.java:130)
at org.apache.commons.logging.LogAdapter.createLog(LogAdapter.java:91)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:67)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:59)
at org.springframework.boot.SpringApplication.<clinit>(SpringApplication.java:196)
... 1 more
则剔除
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
</exclusion>
完整依赖如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
使用
对于GET请求
首先在要进行校验的Controller类上添加 org.springframework.validation.annotation的 @Validated 注解,然后在需要校验的参数上添加对应的校验注解,如@NotNull,@NotEmpty等,例如
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Slf4j
@Validated
@RestController
@RequestMapping("/validated`")
public class ValidatedController{
@GetMapping("/get/string")
public String validatedGet(@NotEmpty(message = "这里是错误后的校验信息") String param) {
return "返回结果";
}
@GetMapping("/get/integer")
public String validatedGet(@NotNull(message = "这里是错误后的校验信息") Integer param) {
return "返回结果";
}
}
对 localDateTime 的校验比较特殊,因为前端传输的格式大部分都类似于 yyyy-MM-dd HH:mm:ss,后台接受时,因为不符合yyyy-MM-ddTHH:mm:ss,所以导致正确的时间也会校验成错误的选项,因此需要进行额外的参数设置
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
@Slf4j
@Validated
@RestController
@RequestMapping("/validated`")
public class ValidatedController{
@GetMapping("/get/time")
public String validatedGet(@NotNull(message = "这里是错误后的校验信息") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
@NotNull(message = "这里是错误后的校验信息") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {
return "返回结果";
}
}
对于POST请求
post请求不需要在类上添加注解,但是需要在入参中添加 @Validated ,同时将规则添加到对应的实体类中
import lombok.extern.slf4j.Slf4j;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequestMapping("/validated`")
public class ValidatedController{
@PostMapping("/post/eternity")
public String validatedGet(@RequestBody @Validated ValidatedVO vo) {
return "返回结果";
}
}
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
// 省略get和set
public class ValidatedVO{
@NotEmpty(message = "这里是错误后的校验信息")
private String param;
@NotNull(message="这里是错误后的校验信息")
private Integer param2;
}
处理报错
添加了校验规则后,如果不符合校验规则,框架会走默认的报错,如果需要自定义报错信息,可以通过@RestControllerAdvice 来实现
import lombok.extern.slf4j.Slf4j;
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.RestControllerAdvice;
import javax.validation.ConstraintViolationException;
@Slf4j
@RestControllerAdvice
public class ControllerExceptionHandler {
/**
* 处理请求参数格式错误 @RequestBody上validate失败后抛出的异常是MethodArgumentNotValidException异常。
*
* @param ex 错误信息
*/
@ExceptionHandler({MethodArgumentNotValidException.class})
public String handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
BindingResult bindingResult = ex.getBindingResult();
StringBuilder sb = new StringBuilder("校验失败:");
for (FieldError fieldError : bindingResult.getFieldErrors()) {
sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", ");
}
return sb.toString();
}
/**
* 处理请求参数格式错误 @RequestParam上validate失败后抛出的异常是javax.validation.ConstraintViolationException
*
* @param ex 错误信息
*/
@ExceptionHandler({ConstraintViolationException.class})
public String handleConstraintViolationException(ConstraintViolationException ex) {
return ex.getMessage();
}
}
注意
在使用这个参数校验时,出现了死活也监听不到错误的情况。此处需要注意,要放置在controller这个包的上层,否则会出现扫不到的情况

浙公网安备 33010602011771号