REST的基本原理
RPC是面向服务的,并关注于行为和动作.REST是面向资源的,强调描述应用程序的事物和名词.
为了理解REST是什么,我们将首字母拆分为不同的组成部分来理解:
- 表述性(Representational)-REST资源实际上可以用各种形式来表述,包括XML,JSON,html,适合资源使用者的任意形式.
- 状态(State)-当使用REST时,我们更关注资源的状态而不是对资源采取的行为.
- 转移(Transfer)-Rest涉及转移资源数据.它以某一种表述性形式从一个应用转移到了一个应用.
跟简介的讲,REST就是将资源的状态以最合适的形式从服务器端转移到客户端(或者反之) .Spring是如何支持REST的
spring有以下方式来开发REST资源:
- 控制器可以处理所有的HTTP方法:GET,POST,DELETE,PUT.
- 新的@PathVariable注解使得控制器能够处理参数化的URL(将变量输入作为URL的一部分).
- Spring的表单绑定JSP标签库的
<form:form>
标签以及新的HiddenHttpMethodFilter使得通过Delete和put提交表单请求成为可能,即便在某些浏览器中不支持这些HTTP方法. - 通过使用Spring的视图和视图解析器,资源可以以各种形式进行表述,包括将模型数据表现为XML,JSON,Atom和RSS的新视图实现.
- 可以使用新的ContentNegotiatingViewResolver来选择最适合客户端的表述.
- 基于视图的渲染可以使用新的@ResponseBody注解和各种HttpMethodConverter实现来达到.
- RestTemplate简化了客户端对REST资源的使用.
表述资源
Spring提供了2种方法将资源的java表述形式转换为发送给客户端的表述形式:
- 基于视图渲染进行协商
- HTTP消息转换器
协商资源表述
Spring的ContentNegotiatingViewResolver
是一个特殊的视图解析器,它考虑到了客户端所需要的内容类型.
它需要配置在Spring应用上下文中:12345678910<bean class="org.springfreamework.web.servlet.view.ContentNegotiatingViewResolver" ><property name="mediaTypes"><map><entry key="json" value="application/json" /><entry key="xml" value="text/xml" /><entry key="htm" value="text/html" /></map></property><property name="defaultContentType" value="text/html" /></bean>
但是ContentNegotiatingViewResolver
会首先考虑url的文件扩展名,如果url在结尾处有文件扩展名的话.它将扩展名与mideaTypes中的条目进行匹配,如果找到了匹配项,那么将会使用找到的媒体类型.
通过这种方式,文件扩展名将覆盖Accept头信息中的任何媒体类型.
如果文件扩展名不能匹配任何媒体类型,那么将会使用浏览器请中的Accept的头信息,如果请求中不包含Accept头部信息,那么将使用defaultContentType
属性设置的媒体类型.
影响如何选择媒体类型:
有几个选项会影响媒体默认选择策略:
- 将
favorPathExtension
属性设置为false,将会使得ContentNegotiatingViewResolver
忽略url路径的扩展名.- 将JAF(Java Activation Framework)添加到类路径下将会使得
ContentNegotiatingViewResolver
除了使用mediaTypes属性中的条目以外,在由路径扩展名确定媒体类型时还会还会借助JAF .- 如果你将favorParameter属性设置为true,并且请求中包含名为format参数,那么format参数的值将会与mediaTypes进行匹配(另外,参数名可以通过设置parameterName属性来选择).
- 将ignoreAcceptHeader设置为true,将忽略Accept信息.
所以我们一般按下面的配置:
查找视图
ContentNegotiatingViewResolver
会委托视图解析器来查找最适合客户端的视图,如果没有特别指明,将会使用应用程序中的所有视图解析器,但可以通过viewResolvers
属性明确声明它委托的视图解析器列表.
使用HTTP信息转换器
典型的Spring MVC控制器方法在结束时会将一些信息放在模型中,然后到达一个视图来为用户渲染这些数据.
但是,当控制器的工作是产生资源表述的时候,有一种更直接的方法可以绕过模型和数据.在这种风格的处理器方法中,控制器返回的对象将自动转化为适合客户端的表述行式.
要使用这种技术,需要将@ResponseBody注解添加到控制器处理方法上.
在响应体中返回资源状态
正常情况下,当处理方法返回Java对象时(除String外),这个对象会放在模型中,并在视图中渲染使用.但是如果处理器方法使用了@ResponseBody,那表明HTTP信息转换器机制会发挥作用.并将返回的对象转换为客户端需要的任意格式.
框架提供了主要media类型的具体实现,并使用客户端的RestTemplate
默认注册,在服务器端使用AnnotationMethodHandlerAdapter
。
StringHttpMessageConverter
StringHttpMessageConverter
实现类可以从HTTP请求和响应中读写String类型。默认地,这个转换器支持所有的文本media类型(*/*
),并使用text/plain
的Content-Type
来写。
FormHttpMessageConverter
FormHttpMessageConverter
实现类可以读写HTTP请求和响应中任何格式的数据。默认地,这个转换器读写的media类型是application/x-www-form-urlencoded
。格式化数据的读写都在MultiValueMap<String, String>
的集合中。
ByteArrayHttpMessageConverter
一个HttpMessageConverter
的实现可以从HTTP请求和响应中读写字节数组。默认地,这个转换器支持所有默认的media类型(*/*
)并使用application/octet-stream的Content-Type
写。这个可以通过设置supportedMediaTypes
属性重写,并可重写getContentType(byte[])
。
MarshallingHttpMessageConverter
HttpMessageConverter
的实现类可以使用org.springframework.oxm
包中的Marshaller
和Unmarshaller
抽象类读写XML。这个转换器在使用前需要一个Marshaller
和Unmarshaller
。这些可以通过构造器或bean属性注入。默认地这个构造器支持( text/xml)
和 ( application/xml)
。
MappingJackson2HttpMessageConverter
(or MappingJacksonHttpMessageConverter with Jackson 1.x)
HttpMessageConverter实现类可以使用Jackson’s ObjectMapper读写JSON。JSON映射可以通过Jackson提供的注解按需定制化。当需要将来的控制时,一个通用的ObjectMapper可以通过ObjectMapper属性注入,这发生在通用的JSON序列化或反序列化需要提供给指定类型的时候。默认地这个转换器支持(application/json).
SourceHttpMessageConverter
HttpMessageConverter实现类可以读写来自HTTP请求和响应的javax.xml.transform.Source。只支持DOMSource,SAXSource和StreamSource。默认地,这个转换器支持 ( text/xml) 和 ( application/xml)。
BufferedImageHttpMessageConverter
HttpMessageConverter实现类可以读写HTTP请求和响应的java.awt.image.BufferedImage。这个转换器读写由Java I/O API支持的media类型.
了解RestTemplate的操作
对于样板式的客户端代码,我们可以使用RestTemplate去简化代码.
get
1234public Spittle[] retrieveSpittlesForSpitter(String userName){RestTemplate restTemplate = new RestTemplate();return restTemplate.getForObject("http://localhost:8080/Spitter/spitters/{spitter}/spittles",spittle[].class,userName);}post
1234public Spitter postSpitterForObject(Spitter spitter){RestTemplate restTemplate = new RestTemplate();return restTemplate.postForObject("http://localhost:8080/Spitter/spitters",spitter,Spitter.class);}
delete 和 post方法就不一一说明了.用的不多.