有谁知道为什么 @Valid 因 javax.validation 而失败并与 spring 启动器验证一起使用
Does anyone know why @Valid fails with javax.validation and works with spring starter validation
我有以下控制器:
@PostMapping( "v1/libraryEvent" )
public ResponseEntity<LibraryEvent> postLibraryEvent( @RequestBody @Valid LibraryEvent libraryEvent )
throws JsonProcessingException
{
//Does some stuff
}
其中使用了此依赖项,其中包括:
import javax.validation.Valid;
LibraryEvent DTO 如下所示:
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class LibraryEvent
{
private Integer libraryEventId;
private LibraryEventType libraryEventType;
@Valid
@NotNull
private Book book;
}
图书馆事件中的书如下:
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class Book
{
@NotNull
private Integer bookId;
@NotNull
private String bookName;
@NotNull
private String bookAuthor;
}
我也有这个测试,它使用 MockMvc 向控制器发送模拟请求以测试那个:
@Test
void postLibraryEvent_4xx() throws Exception {
//given
final Book book = Book.builder()
.bookId( null )
.bookAuthor( null )
.bookName( "Kafka using spring boot" )
.build();
final LibraryEvent libraryEvent = LibraryEvent.builder()
.book( book )
.build();
final String json = objectMapper.writeValueAsString( libraryEvent );
mockMvc.perform(post("/v1/libraryEvent")
.content(json)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.status().is4xxClientError());
}
到目前为止一切都很好,问题是在我的 build.gradle
中我使用了 javax.validation 依赖项,当我 运行 使用该依赖项进行测试时, @Valid
注释不起作用,因为它返回 HttpStatus.OK (200) 而不是 Bad request (400),这应该是,因为这本书的 id 和作者被传递为 null。这就是我的 gradle 文件的依赖项部分是如何使用 javax:
设置的
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'javax.validation:validation-api:2.0.1.Final'
testImplementation 'org.awaitility:awaitility:4.0.3'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation ('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
我通过用 spring 启动启动器验证替换 javax 依赖项解决了这个问题,一旦我 运行 在更改后再次测试,它通过了 @Valid
控制器工作,因为测试返回 4XX HTTP 状态。我的 gradle 现在看起来像这样:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
testImplementation 'org.awaitility:awaitility:4.0.3'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation ('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
但这很奇怪,因为 spring 验证应该使用与 javax 使用相同的验证,或者至少 @Valid
应该以相同的方式运行。所以我的问题是,任何人都可以向我解释 javax 验证和 spring 验证之间的区别是什么,以及为什么 javax 失败,而不是 spring 验证?
提前致谢!
https://docs.spring.io/spring-framework/docs/5.3.9/reference/html/core.html#validation-beanvalidation-spring 的 Spring 文档给出了以下引导 Bean 验证提供程序的示例:
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
@Configuration
public class AppConfig {
@Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
}
然后继续评论:
A Bean Validation provider, such as the Hibernate Validator, is expected to be present in the classpath and is automatically detected.
spring-boot-starter-validation 依赖项似乎只做这两件事。
我有以下控制器:
@PostMapping( "v1/libraryEvent" )
public ResponseEntity<LibraryEvent> postLibraryEvent( @RequestBody @Valid LibraryEvent libraryEvent )
throws JsonProcessingException
{
//Does some stuff
}
其中使用了此依赖项,其中包括:
import javax.validation.Valid;
LibraryEvent DTO 如下所示:
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class LibraryEvent
{
private Integer libraryEventId;
private LibraryEventType libraryEventType;
@Valid
@NotNull
private Book book;
}
图书馆事件中的书如下:
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class Book
{
@NotNull
private Integer bookId;
@NotNull
private String bookName;
@NotNull
private String bookAuthor;
}
我也有这个测试,它使用 MockMvc 向控制器发送模拟请求以测试那个:
@Test
void postLibraryEvent_4xx() throws Exception {
//given
final Book book = Book.builder()
.bookId( null )
.bookAuthor( null )
.bookName( "Kafka using spring boot" )
.build();
final LibraryEvent libraryEvent = LibraryEvent.builder()
.book( book )
.build();
final String json = objectMapper.writeValueAsString( libraryEvent );
mockMvc.perform(post("/v1/libraryEvent")
.content(json)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.status().is4xxClientError());
}
到目前为止一切都很好,问题是在我的 build.gradle
中我使用了 javax.validation 依赖项,当我 运行 使用该依赖项进行测试时, @Valid
注释不起作用,因为它返回 HttpStatus.OK (200) 而不是 Bad request (400),这应该是,因为这本书的 id 和作者被传递为 null。这就是我的 gradle 文件的依赖项部分是如何使用 javax:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'javax.validation:validation-api:2.0.1.Final'
testImplementation 'org.awaitility:awaitility:4.0.3'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation ('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
我通过用 spring 启动启动器验证替换 javax 依赖项解决了这个问题,一旦我 运行 在更改后再次测试,它通过了 @Valid
控制器工作,因为测试返回 4XX HTTP 状态。我的 gradle 现在看起来像这样:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
testImplementation 'org.awaitility:awaitility:4.0.3'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation ('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
但这很奇怪,因为 spring 验证应该使用与 javax 使用相同的验证,或者至少 @Valid
应该以相同的方式运行。所以我的问题是,任何人都可以向我解释 javax 验证和 spring 验证之间的区别是什么,以及为什么 javax 失败,而不是 spring 验证?
提前致谢!
https://docs.spring.io/spring-framework/docs/5.3.9/reference/html/core.html#validation-beanvalidation-spring 的 Spring 文档给出了以下引导 Bean 验证提供程序的示例:
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
@Configuration
public class AppConfig {
@Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
}
然后继续评论:
A Bean Validation provider, such as the Hibernate Validator, is expected to be present in the classpath and is automatically detected.
spring-boot-starter-validation 依赖项似乎只做这两件事。