2023-06-18  阅读(4)
原文作者:代码有毒 mrcode 原文地址:https://mrcode.blog.csdn.net/article/details/81502532

处理创建请求

本节内容

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

Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文