本节内容
@requestBody
映射请求体到java方法参数,可以处理json格式的请求内容- 日期类型参数的处理
@Valid
和BindingResult验证请求参数的合法性并处理校验结果
@Test
public void whenCreateSuccess() throws Exception {
String content = "{\"username\":\"mrcode\",\"password\":null}";
mockMvc.perform(post("/user")
.contentType(APPLICATION_JSON_UTF8)
.content(content) // 传递json内容
)
.andExpect(status().isOk())
// 因为是创建,一般创建完成后需要返回创建的id
// 预期是返回1
.andExpect(jsonPath("$.id").value("1"));
}
运行测试用例返回
java.lang.AssertionError: Status
Expected :200
Actual :405
<Click to see difference>
405的原因是因为query方法占用了"/user"路径,但是是get请求,这里是post请求,所以报错不支持的方法
使用 @RequestBody
接收json内容
@PostMapping
public User create(@RequestBody User user) {
System.out.println(ReflectionToStringBuilder.toString(user, ToStringStyle.MULTI_LINE_STYLE));
user.setId("1");
return user;
}
解决办法是:传递时间戳,非unix时间戳,也就是毫秒数,可以使用new Date(毫秒数)还原成一个java日期的;
常规的解决办法是
com.example.demo.dto.User 中新增日期类型 private Date birthday;
编写测试用例
@Test
public void whenCreateSuccess() throws Exception {
// long time = new Date().getTime(); 等价于下面的
long birthday = Instant.now().toEpochMilli();
String content = "{\"username\":\"mrcode\",\"password\":null,\"birthday\":" + birthday + "}";
String contentAsString = mockMvc.perform(post("/user")
.contentType(APPLICATION_JSON_UTF8)
.content(content)
)
.andExpect(status().isOk())
// 因为是创建,一般创建完成后需要返回创建的id
// 预期是返回1
.andExpect(jsonPath("$.id").value("1"))
.andReturn().getResponse().getContentAsString();
System.out.println(contentAsString);
}
输出
// 测试用例输出
com.example.demo.dto.User@3f6f3cc[
id=<null>
username=mrcode
password=<null>
birthday=Thu Aug 02 09:54:04 GMT+08:00 2018
]
// api 中使用了 ReflectionToStringBuilder.toString 打印的输出
{"id":"1","username":"mrcode","password":null,"birthday":"2018-08-02T01:54:04.268+0000"}
这里发现,现在这个版本的jackson接收是接收时间戳,但是返回的时候却调用了local默认的格式化格式;这让人很蛋疼;
找了十几分钟,没有找到解决方案;以后再看看能不能返回时间戳;这里添加配置
application.yml
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
添加之后,响应变成了想要格式,但是接收(也就是前段传递)还是需要时间戳
对user对象Password限制不能为空
@javax.validation.constraints.NotBlank
private String password;
这里不是 org.hibernate.validator.constraints.NotBlank 在该注解上发现了过时描述。
Deprecated use the standard javax.validation.constraints.NotBlank constraint instead
虽然说这里用的注解是规范注解,使用的验证器 应该是 hibernate-validator-6.0.10.Final.jar版本提供的
api中增加``@Valid`
// javax.validation.Valid
@PostMapping
public User create(@Valid @RequestBody User user) {
用post请求的时候(可以用postman或则视频中讲解的谷歌插件 Restlet Client - REST API Testing ); Restlet Client - REST API Testing 这个谷歌插件可以去了解下,感觉挺好用的,可以项目分类和全部执行测试
{
"timestamp": "2018-08-02 10:41:13",
"status": 400,
"error": "Bad Request",
"errors": [
{
"codes": [
"NotBlank.user.password",
"NotBlank.password",
"NotBlank.java.lang.String",
"NotBlank"
],
"arguments": [
{
"codes": [
"user.password",
"password"
],
"arguments": null,
"defaultMessage": "password",
"code": "password"
}
],
"defaultMessage": "不能为空",
"objectName": "user",
"field": "password",
"rejectedValue": null,
"bindingFailure": false,
"code": "NotBlank"
}
],
"message": "Validation failed for object='user'. Error count: 1",
"path": "/user"
}
在上面我们的业务方法都没有进入,就被spring框架给拦截回去了。在实际开发中都是需要进入 我们的业务方法,添加BindingResult入参。能获取到所有的错误信息
@PostMapping
public User create(@Valid @RequestBody User user, BindingResult errors) {
if (errors.hasErrors()) {
// System.out.println(err.getDefaultMessage()); 能获取默认的错误信息
errors.getAllErrors().stream().forEach(System.out::println);
}
再次使用测试用例:打印出来的是这些。自己debug查看就能看到有详情
Field error in object 'user' on field 'password': rejected value [null]; codes [NotBlank.user.password,NotBlank.password,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.password,password]; arguments []; default message [password]]; default message [may not be empty]