处理创建请求

在介绍 GET 请求之后,开始介绍如何使用 POST 请求。在 Restful 接口开发中,POST 请求的接口几乎是使用比较多的一种,因此在本章也会比较重要。在本小节中,将会说明 @RequestBody 注解的使用方法,然后,将对一些常用的知识点进行介绍。

@RequestBody注解

@RequestBody 注解:可以将请求体中的 JSON 字符串绑定到相应的 Bean 上,当然也可以将其分别绑定到对应的字符串上。这个注解常用来处理 content-type 不是默认的 application/x-www-form-urlencoded 编码的内容,比如,application/Json 或者 application/xml 等。一般情况下常用来处理 application/Json 类型。控制类代码如下所示。

@PostMapping("/user")
public User createInfo(@RequestBody User user) {
    System.out.println(user.getUsername());
    System.out.println(user.getPassword());
    user.setUsername("Bob");
    return user;
}

测试类代码如下所示。

@Test
public void whenCreateSuccess() throws Exception {
  String content="{\"username\":\"tom\",\"password\":\"123\"}";
  String result=mockMvc.perform(MockMvcRequestBuilders.post("/user")
         .contentType(MediaType.APPLICATION_JSON_UTF8)
         .content(content))
  .andExpect(MockMvcResultMatchers.status().isOk())
  .andReturn().getResponse().getContentAsString();
  System.out.println("result: "+result);
}

执行结果如图 3.8 所示。

image 2024 03 31 13 47 36 406
Figure 1. 图3.8 执行结果

程序使用了 @PostMapping 注解,这个注解是 @RequestMapping(method=RequestMeth od.POST) 的变体。同理还有 @GetMapping@PutMapping@DeleteMapping,简化了注解。

从执行结果可以看出,content 中的 Json 值通过 @RequestBody 映射到 userBean 了,所以在控制类中可以通过对象 GET 属性值。同样可以使用 SET 对属性进行修改、返回,具体效果可以看测试类中 Result 的值。

日期类型的处理

后台交互时,对时间的处理总是不太方便,在这里建议使用时间戳进行传递,然后前后台分别对时间戳进行转换。可以在 User 类中添加时间类型的字段用于演示。User.java 中的代码如下所示。

public class User {
   /*
      创建两个接口
   */
   public interface UserSimpleView{};
   public interface UserDetailView extends UserSimpleView{};
   private String username;
   private String password;
   private String id;
   private Date birthday;
   //Generate setters and getters//
   //……
}

控制类代码如下所示。

/**
  * @Desciption 测试日期类型
  */
@PostMapping("/user")
public User createInfo2(@RequestBody User user) {
    System.out.println(user.getUsername());
    System.out.println(user.getPassword());
    System.out.println(user.getBirthday());
    user.setUsername(“Bob”);
    return user;
}

测试类代码如下所示。

/**
  * @desciption 测试日期
  * @throws Exception
  */
@Test
public void whenCreateSuccess2() throws Exception {
  Date date=new Date();
  System.out.println("dateTime: "+date.getTime());
    String content="{\"username\":\"tom\",\"password\":\"123\",\"birthday\":"+date.getTime()+"}";
      String result=mockMvc.perform(MockMvcRequestBuilders. post("/user")
         .contentType(MediaType.APPLICATION_JSON_UTF8)
         .content(content))
  .andExpect(MockMvcResultMatchers.status().isOk())
  .andReturn().getResponse().getContentAsString();
  System.out.println("result: "+result);
}

日期处理结果如图 3.9 所示。

image 2024 03 31 13 50 32 093
Figure 2. 图3.9 日期处理结果

@Valid注解

在开发业务时,需要满足校验,然后才会进行后台服务处理。校验的程序第一步,对校验字段进行校验要求;第二步,在服务上添加 @Valid 注解。首先在字段上添加校验代码如下所示。

public class User {
    public interface UserSimpleView{};
    public interface UserDetailView extends UserSimpleView{};

    @NotBlank
    private String username;
    private String password;
    private String id;
    private Date birthday;
    //generate setters and getters
    //……
}

然后在控制类中添加校验,如下所示。

@PostMapping("/user")
public User createInfo3(@Valid @RequestBody User user) {
    System.out.println(user.getUsername());
    System.out.println(user.getPassword());
    user.setUsername("Bob");
    return user;
}

测试类代码如下所示。

@Test
public void whenCreateSuccess3() throws Exception {
   String content="{\"username\":null,\"password\":\"123\"}";
   String result=mockMvc.perform(MockMvcRequestBuilders.post("/user")
      .contentType(MediaType.APPLICATION_JSON_UTF8)
      .content(content))
      .andExpect(MockMvcResultMatchers.status().isOk())
      .andReturn().getResponse().getContentAsString();
   System.out.println("result: "+result);
}

执行结果如图 3.10 所示。

image 2024 03 31 13 52 45 371
Figure 3. 图3.10 执行结果

程序报错,说明没有通过校验。我们看到控制台没有输出任何和控制类有关的信息,说明程序没有进入控制类,所以 Valid 注解在没有通过校验时,不会进入后台服务。

BindingResult验证参数合法性

在上文的 @Valid 注解中,我们可以发现程序没有通过校验时,不会进入后台服务(就是获取不到效验错误消息),但在一些情况下需要进入后台进行一些操作,此时 BindingResult 就有用武之地了。

控制类代码如下所示。

@PostMapping("/user")
    public User createInfo4(@Valid @RequestBody User user,BindingResult errors) {
    if(errors.hasErrors()) {
    errors.getAllErrors().stream().forEach(error->System.out. println("error message: "+error.getDefaultMessage()));
    }
    System.out.println(user.getUsername());
    System.out.println(user.getPassword());
    user.setUsername(“Bob”);
    return user;
}

继续使用上面的测试类代码即可。执行结果如图 3.11 所示。

image 2024 03 31 13 59 20 884
Figure 4. 图3.11 BindingResult执行结果

在控制类代码中,使用 JDK1.8 的新特性 lambda 表达式进行输出。根据控制台结果,可以看到这里不仅通过了校验,而且程序进入了后台服务,将报错信息存入 BindingResult 对象。