【Spring Security OAuth2笔记系列】- 【使用Spring MVC开发RESTful API】 处理创建请求

处理创建请求

本节内容

  • @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

添加之后,响应变成了想要格式,但是接收(也就是前段传递)还是需要时间戳

@Valid使用

对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"
}

BindingResult 使用

在上面我们的业务方法都没有进入,就被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]

猜你喜欢

转载自blog.csdn.net/mr_zhuqiang/article/details/81666594