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

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

处理创建请求

本节内容

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值