使用Spring MVC创建REST API

近几年来,以信息为中心的表述性状态转移(Representational Statae Transfer,REST)已成为替换传统的SOAP Web服务的流行方案。SOAP一般会关注行为和处理,而REST关注的是要处理的数据。

1.了解REST

1.1 REST的基础知识

首先,REST与RPC几乎没有任何关系。RPC是面向服务的,并关注于行为和动作;而REST是面向资源的,强调描述应用程序的事物和名词。
将其首字母缩写拆分为不同的构成部分来理解:

  • 表述性(Representational):REST资源实际上可以用各种形式来进行表述,包括XML,JSON甚至HTML——最适合资源使用者的任意形式;
  • 状态(State):当使用REST的时候,我们更专注资源的状态而不是对资源采取的行为;
  • 转移(Transfer):REST涉及到转移资源数据,它以某种表述性形式从一个应用转移到另一个应用。

简洁地讲,REST就是将资源的状态以最适合客户端或服务端的形式从服务器端转移到客户端(或者反过来)。
在REST中,资源通过URL进行识别和定位。至于RESTful URL的结构并没有严格的规则,但是URL应该能够识别资源,而不是简单的发一条命令到服务器上。再次强调,关注的核心是事物,而不是行为。
REST中会有行为,它们通过HTTP方法来定义。这些HTTP方法通常会匹配为如下的CRUD动作:

  • Create: POST
  • Read: GET
  • Update: PUT或PATCH
  • Delete:DELETE

1.2 Spring是如何支持REST

当前的4.0版本中,Spring支持以下方式来创建REST资源:

  • 控制器可以处理所有的HTTP方法,包含四个主要的REST方法:GET、PUT、DELETE以及POST。Spring3.2及以上版本还支持PATCH方法;
  • 借助@PathVariable注解,控制器能够处理参数化的URL(将变量输入作为URL的一部分)
  • 借助Spring的视图和视图解析器,资源能够以多种形式进行表述,包括将模型数据渲染为XML、JSON、Atom以及RSS的View实现;
  • 可以使用ContentNegotiatingViewResolver来选择最适合客户端的表述;
  • 借助@ResposeBody注解和各种HttpMethodConverter实现,能够替换基于视图的渲染方式;
  • 类似的,@RequestBody注解以及HttpMethodConverter实现可以将传入的HTTP数据转化为传入控制器处理方法的Java对象;
  • 借助RestTemplate,Spring应用能够方便地使用REST资源。

- 创建第一个REST端点

表述是REST中很重要的一个方面。它是关于客户端和服务端针对某一资源是如何通信的。
控制器本身通常并不关心资源如何表述。控制器以Java对象的方式来处理资源。控制器完成了它的工作之后,资源才会被转化成最适合客户端的形式。
Spring提供了两种方法将资源的Java表述形式转换为发送给客户端的表述形式:

  • 内容协商(Content negotiation):选择一个视图,它能够将模型渲染为呈现给客户端的表述形式;
  • 消息转换器(Message conversion):通过一个消息转换器将控制器所返回的对象转换为呈现给客户端的表述形式。

2.1 协商资源表述

Spring的ContentNegotiatingViewResolver是一个特殊的视图解析器,他考虑到了客户端所需要的内容类型。
要理解ContentNegotiatingViewResolver是如何工作的,这涉及内容协商的两个步骤:

  • 确定请求的媒体类型;
  • 找到适合请求媒体类型的最佳视图。

确定请求的媒体类型
ContentNegotiatingViewResolver将会考虑到请求的Accept头部信息并使用它所请求的媒体类型,但是它会首先查看URL的文件扩展名。如果URL在结尾处有文件扩展名的话,ContentNegotiatingViewResolver将会基于该扩展名确定所需的类型。如果扩展名是“.json”的话,那么所需的内容类型必须是“application/json”。如果扩展名是“.xml”,那么哭护短请求的就是“application/xml”。当然,“.html”扩展名表明客户端所需的资源表述为HTML(text/html)。
如果根据文件扩展名不能得到任何媒体类型的话,那就会考虑请求中的Accept头部信息。在这种情况下,Accept头部信息中的值就表明了客户端想要的MIME类型,没有必要再去查找了。
最后,如果没有Accept头部信息,并且扩展名也无法提供帮助的话,ContentNegotiatingViewResolver将会使用“/”作为默认的内容类型,这就意味着客户端必须要接受服务器发送的任何形式的表述。
一旦内容类型确定之后,ContentNegotiatingViewResolver就该将逻辑视图名解析为渲染模型的View。与Spring的其他视图解析器不同,ContentNegotiatingViewResolver本身不会解析视图。而是委托给其他的视图解析器,让他们来解析视图。
ContentNegotiatingViewResolver要求其他的视图解析器将逻辑视图名解析为视图。解析得到的每个视图都会放到一个列表中。这个列表装配完成后,ContentNegotiatingViewResolver会虚幻客户端请求的所有媒体类型,在候选的视图中查找能够产生对应内容类型的视图。第一个匹配的视图会用来渲染模型。

影响媒体类型的选择
上面,我们说到了确定所请求媒体类型的默认策略。但是通过为其设置一个ContentNegotiationManager,我们能够改变它的行为。借助ContentNegotiationManager我们所能做到的事情如下所示:

  • 指定默认的内容类型,如果根据请求无法得到内容类型的话,将会使用默认值
  • 通过请求参数指定内容类型
  • 忽视请求的Accept头部信息
  • 将请求的扩展名映射为特定的媒体类型
  • 将JAF(Java Activation Framework)作为根据扩展名查找媒体类型的备用方案

有三种配置ContentNegotiationManager的方法:

  • 直接声明一个ContentNegotiationManager类型的bean
  • 通过ContentNegotiationManagerFactoryBean间接创建bean
  • 重载WebMvcConfigurerAdapter的configureContentNegotiation()方法

第一种方法有一些复杂,除非有充分的原因,否则我们不会愿意这样做。后两种方案能够让创建ContentNegotiationManager更加简单。

通过XML使用ContentNegotiationManagerFactoryBean来创建和配置ContentNegotiationManager bean使用“application/json”作为默认的内容类型。

<bean id="contentNegotiationManager"
  class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"
  p:defaultContentType="applicatin/json">

ContentNegotiationManagerFactoryBean是FactoryBean的实现,所以他会创建一个ContentNegotiationManager bean。

使用Java配置,重写WebMvcConfigurerAdapter的configureContentNegotiation():

public class WebConfig extends WebMvcConfigurerAdapter{
   
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.defaultContentType(MediaType.APPLICATION_JSON);
    }
}

现在我们已经有了ContentNegotiationManager bean接下来把它注入到ContentNegotiatingViewResolver中即可。

    @Bean
    @Autowired
    public ViewResolver cnViewResolver(ContentNegotiationManager contentNegotiationManager){
        ContentNegotiatingViewResolver viewResolver = new ContentNegotiatingViewRes
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值