spring - 在 Spring Boot 控制器中验证 HTTP POST 请求中的请求正文是否为空
问题描述
我正在替换 Spring Boot REST 控制器中对 POST 请求的输入的手动验证。JSR-303 Spring Bean Validation 用于验证请求正文中的实例变量,并且按预期工作。验证请求正文中的对象不为空的推荐方法是什么?
我试过了:
注释整个对象,例如:@NotNull @Valid @RequestBody Foo foo
用 @NotNull 注释整个类
我正在更换:
@PostMapping...
public ResponseEntity<Map<String, Object>> editFoo(
@RequestBody Foo foo, ...) {
if(foo == null) {
return (new ResponseEntity<>(headers, HttpStatus.BAD_REQUEST));
}
}
具有等效的 Bean 验证:
@PostMapping...
public ResponseEntity<Map<String, Object>> editFoo(
@Valid @RequestBody Foo foo, ...) {
...
}
我尝试通过以下方式对控制器方法进行单元测试:
// Arrange
Foo foo = null;
String requestBody = objectMapper.writeValueAsString(foo);
// Act + assert
mockMvc
.perform(
post("/end_point")
.contentType("application/json")
.content(requestBody))
.andExpect(status().isBadRequest());
我期望一个 MethodArgumentNotValidException 由 @ControllerAdvice 处理此异常,但在执行单元测试时我得到 HttpMessageNotReadableException 。我的问题:
- 是否有必要测试请求正文是否为空?
- 如果 1. 为真,那么 Bean Validation 应该如何做到这一点?
解决方案
看到您的代码,您已经检查了正文是否为空。实际上@RequestBody
有一个默认参数required
,默认为 true。所以不需要 Bean 验证!
您的主要问题似乎在您的测试中。首先,最好编写一个测试来验证您的端点在 null 上的行为。
但是,在您的测试中,您没有通过 null。您尝试null
使用objectMapper
. 您正在编写的对象似乎不是有效的 json。因此,当您发送此正文时,Spring 说它无法读取消息,也就是您的请求正文,因为您说它是application/json
内容,但其中没有 json。
要测试空正文,只需在测试中发送您的请求,只需删除该.content(requestBody)
行即可!
--- 编辑 1 我以为是因为正文而拒绝了该消息,但实际上它似乎对我立即起作用。这是我的控制器和测试,因此您可以与完整代码进行比较:
@RestController()
@RequestMapping("end_point")
public class TestController {
@PostMapping
public ResponseEntity<Map<String, Object>> editFoo(@RequestBody Foo foo) {
// if(foo == null) {
// return (new ResponseEntity<>(new HashMap<>(), HttpStatus.BAD_REQUEST));
// }
return (new ResponseEntity<>(new HashMap<>(), HttpStatus.OK));
}
}
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class TestControllerTest {
@Autowired
private MockMvc mvc;
@Autowired
private ObjectMapper objectMapper;
@Test
public void test_body_is_null() throws Exception {
Foo foo = null;
String requestBody = objectMapper.writeValueAsString(foo);
// Act + assert
mvc
.perform(
post("/end_point")
.contentType("application/json")
.content(requestBody))
.andExpect(status().isBadRequest());
}
}
这是使用 Spring Boot 2.1.6.RELEASE 制作的
--- 编辑 2 如果您想在此处使用 null 验证作为记录,这里是控制器的片段:
@RestController()
@RequestMapping("end_point")
@Validated
public class TestController {
@PostMapping
public ResponseEntity<Map<String, Object>> editFoo(@NotNull @RequestBody(required = false) Foo foo) {
return (new ResponseEntity<>(new HashMap<>(), HttpStatus.OK));
}
}
首先,您必须将主体的 required 设置为 false,因为默认值为 true。然后您必须在请求正文和控制器上添加@NotNull
注释。@Validated
在这里,如果您启动测试,您将看到请求失败并显示:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.validation.ConstraintViolationException: editFoo.foo: must not be null
正如您所说,@ControllerAdvice
您可以根据需要映射异常!
推荐阅读
- python - netmiko:send_config_from_file:显示设备证书时执行中断
- javascript - JavaScript - 通过 websocket 将 ArrayBuffer 数据发送到后端 [guacamole]
- rust - 如何在rust中将u128转换为u64?
- html - Bootstrap 年数自动递增
- spring-boot - SpringBoot-JPA:“传递给持久化的分离实体”-OneToMany 双向
- git - 我可以在 git 中使用基于 ID 的 GitHub 提供的 noreply 地址吗?
- shell - 如何在 shell 脚本上使用 gnuplot 命令
- javascript - C3.js 水平条形图 - 与条形一起突出显示特定的 x 轴刻度
- tensorflow - 无法将 tensorflow.python.data.ops.dataset_ops.PrefetchDataset 类型的参数解释为迭代过程中的 TFF 值
- excel - 如何在excel中将月份和日期添加到编号的年份?