Spring REST API整理

来源:互联网 发布:网络教育的特征 编辑:程序博客网 时间:2024/06/10 19:12

REST (Representational State Transfer),以数据交互为主要内容所设计的系统服务。通过URL来作为资源识别的依据。

Spring MVC充分支持了REST,有两种实现方式:

  1. 协商资源表述,通过ContentNegotiatingViewResolver来向请求方传递合适资源表述形式
  2. 使用HTTP信息转换器,即Message Converter来将资源(即控制器产生的数据)转换为服务与客户端的表述形式,并传递给请求方

第一种模式比较复杂,一般实现REST系统通过第二种方式,更直接更易配置。

使用HTTP信息转换器

在使用HTTP信息转换器的过程中,最重要的两个元素为:

  • 数据(控制器所产生的结果)
  • 消息转换器(message converter)

Spring MVC在配置的时候会默认注册一系列消息转换器,其中最主要的有:

  • MappingJackson2HttpMessageConverter:
    用来转化JSON和类型化的对象或非类型化的HashMap,需要Jackson 2 JSON包
  • Jaxb2RootElementHttpMessageConverter
    用来在XML(text/xml或application/xml)和使用JAXB2注解的对象间互相读取和写入,需要JAXB v2包

只要message converter所依赖的jar包存在于类路径下,这些message converter就会被注册如Spring MVC的上下文中。

Controller产生的数据具体将调用哪一张message converter是由客户请求中的Accept头信息来决定的。

@ResponseBody和@RequestBody

  • @ResponseBody

使用@ResponseBody标注Controller一个具体方法时,程序会告诉Spring MVC跳过视图解析过程,并且去根据请求头中的Accept信息来调用对应的message converter将数据转化客户用需要的资源表达形式。

另外我们可以@RequestMapping注解的produce声明属性里来明确表示一个方法只处理符合某个特定Accept的请求。

  • @RequestBody
    与@ResponseBody相对应的是@RequestBody,该注解用来标注Controller中某个方法的一个参数。Spring MVC会根据客户请求头中的Content-Type来选取具体的message converter将请求中附带的信息转化成具体的对象。

类似地,我们可以在@RequestMapping注解的consumes声明属性里来明确表示一个方法只处理符合某个特定Content-Type的请求。

@RestController

@RestController是用来标注一个controller类的注解,它结合了@Controller与@ResponseBody,表示该controller下的所有方法均为REST API。

提供资源之外的其他类容

一个好的REST API不仅可以向用户提供所需要的资源,还可以提供一些元信息。

  1. @ResponseStatus
    如果仅仅需要提供一个HTTP状态码,那么只需要在响应的方法上面加上@ResponseStatus状态码。例如在@ExceptionHandler处理方法上添加@ResponseStatus(HttpStatus.NOT_FOUND)等。

  2. 控制器方法返回ResponseEntity对象
    控制器方法中可以返回一个ResponseEntity对象,这个对象不仅可以包含资源体,还可以设置返回的HTTP状态码,设置header中的信息等。

@RequestMapping(method=RequestMethod.POST, consumes="application/json")  @ResponseStatus(HttpStatus.CREATED)  public ResponseEntity<Spittle> saveSpittle(@RequestBody Spittle spittle, UriComponentsBuilder ucb) {    Spittle saved = spittleRepository.save(spittle);    HttpHeaders headers = new HttpHeaders();    URI locationUri = ucb.path("/spittles/")        .path(String.valueOf(saved.getId()))        .build()        .toUri();    headers.setLocation(locationUri);    ResponseEntity<Spittle> responseEntity = new ResponseEntity<Spittle>(saved, headers, HttpStatus.CREATED);    return responseEntity;  }
  1. 通过异常处理器来应对错误场景,这样处理器方法就能只关注正常的状况了
@ExceptionHandler(SpittleNotFoundException.class)  @ResponseStatus(HttpStatus.NOT_FOUND)  public @ResponseBody Error spittleNotFound(SpittleNotFoundException e) {    long spittleId = e.getSpittleId();    return new Error(4, "Spittle [" + spittleId + "] not found");  }

通过RestTemplate来实现客户端对Rest API调用

不借助RestTemplate来编写客户端(需要使用Apache HTTP Client):

public Profile fetchFacebookProfile(String id){      try{          HttpClient client = HttpClients.createDefault();          HttpGet request = new HttpGet("http://graph.facebook.com/" + id);          request.setHeader("Accept", "application/json");          HttpResponse response = client.execute(request);          HttpEntity entity = response.getEntity();          ObjectMapper mapper = new ObjectMapper();          return mapper.readValue(entity.getContent(), Profile.class);      } catch (IOException e) {          throw new RuntimeException(e);      }  }

通过借助RestTemplate,我们可以避开繁琐的模版式编程。

RestTemplate提供了11个大独立方法,其中10种每个有三个重载,1个有6个重载。

  • delete() – 在特定的URL上对资源执行HTTP DELETE操作
  • exchange() – 在URL上执行特定的HTTP方法,返回包含对象的ResponseEntity,这个对象是从响应体中映射得到的
  • execute() – 在URL上执行特定的HTTP 方法,返回一个从响应体映射得到的对象
  • getForEntity() – 放松一个HTTP GET请求,返回的ResponseEntity包含了响应体所映射成的对象
  • getForObject() – 发送一个HTTP GET请求,返回的请求体将映射为一个对象
  • headForHeaders() – 发送HTTP HEAD请求,返回包含特定资源URL 的HTTP 头
  • optionsForAllow() – 发送HTTP OPTIONS请求,返回对特定URL的Allow头信息
  • postForEntity() – POST数据到一个URL,返回一个对象的ResponseEntity,这个对象是从响应体中映射得到的
  • postForLocation() – POST数据到一个URL,返回新创建资源的URL
  • postForObject() – POST数据到一个URL,返回根据响应体匹配形成的对象
  • put() – PUT资源到特定的URL

getForObject()与getForEntity()唯一区别是一个直接返回根据response而转化的对象,而后者返回的是一个HttpEntity,不仅仅包含转化的对象,还有response中header的信息。

相同的区别也适用postForObject()与postForEntity()。

getForObject()示例:

public Profile fetchFacebookProfile(String id){    RestTemplate rest = new RestTemplate(); //此处new,也可以通过注入    return rest.getForObject("http://graph.facebook.com/{id}", Profile.class, id)}

exchange()方法可以设置Request的header信息,它是最灵活的方法。其实getxxxx或者postxxxx背后调用的都是exchange()方法。

原创粉丝点击