menu

Spring MVC 与客户端的交换数据

Posted on 28/04/2020

HttpMessageConverter<T>

HttpMessageConverter<T>是Spring中一个重要的接口,能够将请求信息转换为T实例对象,或将T实例对象输出为响应信息。该接口中声明的方法如下:

public interface HttpMessageConverter<T> {
  // 转换器是否可以将请求信息(类型为meidaType)转换为clazz类型对象
  Boolean canRead(Class<?> clazz, MediaType mediaType);
  // 转换器是否可以将clazz类型对象写到响应信息
  Boolean canWrite(Class<?> clazz, MedizType mediaType);
  // 转换器支持的媒体类型
  List<MediaType> getSupportedMediaType();
  // 将请求信息转换为T实例对象
  T read(Class<? extends T> clazz, HttpInputMessage inputMessage);
  // 将T实例对象写入到响应信息
  void write(T t, MediaType mediaType, HttpOutputMessage outputMessage);
}

根据上述接口方法签名可知,转换器在将请求信息转换为Java对象,或将Java对象写入到响应信息中,需要如下两个信息:

  • MediaType,通过请求的Content-Type或Accept属性获得。
  • Class<?>,根据方法签名获得,或者通过HttpEntityResponseEntity的泛型获得。

DispatcherServlet默认安装的RequestMappingHandlerAdapterHandlerAdapter的实现类,RequestMappingHandlerAdapter内部使用HttpMessageConverter<T>,将请求信息转换为Java对象,或将Java对象写入到响应信息。

SpringMVC中默认实现了多种转换器,根据请求的属性和方法签名,自动选择合适的转换器进行转换。这是一种策略模式。

数据准备

public class Car {
    private String brand;
    private String series;
    private double price;
}

@RequestBody@ResponseBody

将请求信息转换为 JavaBean

    @RequestMapping("/request1")
    @ResponseBody
    public Car request1(@RequestBody Car car) {
        car.setPrice(300.0);
        return car;
    }
$ curl -X post --data '{"brand":"BMW","series":"520","price":50000.0}' --header 'Content-Type:application/json' localhost:8080/request1
// 返回结果
$ {"brand":"BMW","series":"520","price":300.0}

@RequestBody@ResponseBody不一定需要同时使用。

将请求信息转换为Map

    @RequestMapping("/request2")
    @ResponseBody
    public void request2(@RequestBody String car) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> carMap = 
          mapper.readValue(car, new TypeReference<Map<String, Object>>() {});
        System.out.println(carMap);
    }

在终端输入上述 curl 命令后,服务端将打印出结果:

{brand=BMW, series=520, price=50000.0}

HttpEntity<T>ResponseEntity<T>

@RequestBody可以获得请求报文体中的内容,这点HttpEntity<T>与之相似,同时HttpEntity<T>还可以获得报文头的信息。

@RequestMapping("/request3")
public void request3(HttpEntity<Car> entity) {
  Car car = entity.getBody();
}

ResponseEntity<T>用法

@RequestMapping("/request4")
public ResponseEntity<Car> request() {
  Car car = new Car();
  // setting...
  ResponseEntity<Car> entity = 
    new ResponseEntity<>(car, HttpStatus.Ok);
  return entity;
}

@RestController

@Restcontroller = @ResponseBody + @Controller

该注解支持 REST 风格应用的开发。

Top