尽管Spring MVC框架在很早以前就通过注解和其他的API特性添加了RESTful的功能,但是对RESTfu web service的支持却是比较晚才添加到Spring MVC中的。一些JAX-RS实现(如Restlet,RESTEasy和Jersey)已经支持RESTful web service,但是Spring社区直到Spring 3.0才支持RESTful web service特性。本文中我们会讨论Spring 3.0对开发RESTful web service的支持,查看其提供的类和注解。
首先让我们简单的复习一下。RESTful web service是使用REST原则创建和访问的web service。RESTful web service是使用HTTP没方法来执行操作的,能够很容易的通过URI进行访问。HTTP方法POST,GET,PUT和DELETE能够被映射到创建、读取、更新和删除(CRUD)操作。
使用JAX-RS的RESTful Web Service
JAX-RS是一个Java编程的API(JSR 311),是Java EE平台的一部分。JAX-RS被设计用来简化使用REST原则和架构的Java应用程序的开发。通过使用注解,JAX-RS开发人员能够将POJO暴露为web资源。和其他的Java web应用程序一样,JAX-RS应用程序被打包为WAR文件,并布署在支持Java Servlet API的容器上。
在Java中开发JAX-RS应用程序的方法之一就是使用Jersey。Jersey是一个开源的、质量良好的JAX-RS参考实现。Jersey实现了所有的API,并且提供了能够快速简便的开发REST类型的Java web service的注解。它还使用自己定义的API(如Jersey Client API)提供了很多附加的特性。对于RESTful web service,Jersey使用的是名为Grizzly的web 服务器。对该容器的请求会被一个Grizzly Servlet处理,该Servlet的全名是com.sun.jersey.spi.container.servlet.ServletContainer.
使用Spring编写RESTful web service
使用Spring MVC对RESTful web service的支持,Java开发人员能够使用继承自Spring的MVC框架的注解来构建RESTful的应用程序。对于RESTful应用程序的客户端的支持是RestTemplate API提供的,该API在概念上和JdbcTemplate或JmsTemplate十分类似。REST功能是HttpConverters类提供的,该类帮助将对象转换成HTTP请求或回应中的representation,或者是相反的过程。为了完成对象和XML之间的映射,Spring提供了MarshallingHttpMessageConverter类。
Spring web MVC使用了DispatcherServlet来将请求分发给处理器。默认的处理器是使用@Controller和@RequestMapping注解标明的。这两个注解在使用Spring开发RESTful的应用程序扮演了主要的角色,实际上这两个注解和另外一个注解#PathVariable构成了Spring中RESTful功能的基础。注解@Controller被用来将一个POJO标记为控制器,注解@RequestMapping用来将请求映射到类或处理器方法。
Spring控制器和RESTful web service
控制器对应Spring web MVC中的C。它们帮助处理用户输入,并为用户将输入通过视图(view)转换为模型(model)。控制器可以通过@controller注解来声明。通常,我们在一个类的顶端使用该注解来上面这个特定的类是控制器。
复制代码
注解@RequestMapping并不要求被使用在类级别上,它也可以被使用在方法级别上。根据absolute路径,控制器会调用合适的方法。
URI模板
一个URI模板是一个将URI作为字符串保持的模板。通常,一个URI模板会含有变量,当这些变量被值替换的时候,URI模板就变成了实际的URI。我们可以在@RequestMapping注解中使用URI模板。
例如,URI http://www.helloworld.com/users/ {username}就是一个URI模板,允许使用实际的用户名来替换username,例如 http://www.helloworld.com/users/john 。处理器将实际的UIR和URI模板进行比较并替换其中的参数。
复制代码
Spring注解 : @PathVariable
注解@PathVariable被用来将UIR模板变量和方法参数绑定到一起。在前面的例子中,可以使用@PathVariable注解就爱那个URI模板变量username和方法参数userName绑定到一起。使用了@PathVariable声明的方法参数的类型并不一定要是字符串,可以是原始类型,如int,long,double等。
复制代码
可以将多个URI模板变量绑定到方法的参数中,如:
复制代码
URI模板变量也可以来找相对路径:
复制代码
参数化的添加如myParam=paramValue也是被支持的,这样只有参数等于给定的参数值的请求才会被映射。
Spring注解 : @RequestParam
注解@RequestParam被用来将请求参数和方法参数绑定在一起。注解@RequestBody用来表明参数被绑定到HTTP request body中的值。在发送回应的时候,注解@ResponseBody能够白用来将值返回到HTTPrquest body中。
复制代码
Spring中的RESTful客户端
我们前面提到过,RestTemplate是用来在客户端访问RESTful服务的类。仅管和其他的Spring中的模板类很相似,我们还是可以通过提供回调方法和配置HttpMessageConverter类来客户化该模板。客户端的操作可以完全使用RestTemplate和HttpMessageConveter类来执行。
RestTemplate类
在Java中,Jakarta Commons HttpClient类被用来调用RESTful服务。对于普通的操作,HttpClient的executeMethod被用来执行对应6种HTTP方法的高层次的操作。RestTemplate提供了一组方法来确保REST的最佳实践。RestTemplate类提供的这些方法对应的HTTP方法是:
RestTemplate类的方法名传递的含义很简单。第一部分是其对应的HTTP方法的名字;第二部分表明了返回的值。例如getForObject方法,该方法会执行GET操作并从HTTP response中返回一个对象(HTTP response被转换成对象类型)。同样的,postForLocation方法执行一个POST操作并返回一个HTTP location header,指明了新创建的对象的位置。
RestTemplate类的方法接受一个字符串类型的URL。RestTemplate对象可以使用默认的构造函数来创建,客户使用java.net包中的API来创建HTTP request。下面是一个客户使用RestTemplate类访问RESTful web service的例子
复制代码
HTTP Message转换器
发送给RestTemplate方法的对象以及从RestTemplate方法返回的对象被HttpMessageConverter接口转换成HTTP消息——HTTP request和HTTP response。该接口有以下的方法:
boolean canRead(Class<?>clazz, MediaType mediaType):用来判定给定的类和媒体类型能否被转换器读
boolean canWrite(Class<?> clazz, MediaType mediaType):用来判定给定的类和媒体类型能否被转换器写
List<MediaType> getSupportedMediaTypes():返回一个支持的MediaType对象的列表
T read(Class<T> clazz, HttpInputMessage inputMessage):从给定的inputMessage中读取对象并返回该对象
void write(T t, HttpOutputMessage outputMessage):将给定的对象写入给定的outputMessage中。
对MIME类型的转换器是默认生效的。我们也可以编写客户自己的转换器。下面的表格中列出了默认的转换器的实例:
总结
RESTful web service最适合于需要无状态的web service的情况,这种情况下基于REST的价格提供了更好的性能和缓存选择。本文中我们介绍了Spring框架对构建RESTful web service提供的良好的支持,使得可以使用注解和象RestTemplate这样API简单而优雅的构建一个RESTful web service。
首先让我们简单的复习一下。RESTful web service是使用REST原则创建和访问的web service。RESTful web service是使用HTTP没方法来执行操作的,能够很容易的通过URI进行访问。HTTP方法POST,GET,PUT和DELETE能够被映射到创建、读取、更新和删除(CRUD)操作。
使用JAX-RS的RESTful Web Service
JAX-RS是一个Java编程的API(JSR 311),是Java EE平台的一部分。JAX-RS被设计用来简化使用REST原则和架构的Java应用程序的开发。通过使用注解,JAX-RS开发人员能够将POJO暴露为web资源。和其他的Java web应用程序一样,JAX-RS应用程序被打包为WAR文件,并布署在支持Java Servlet API的容器上。
在Java中开发JAX-RS应用程序的方法之一就是使用Jersey。Jersey是一个开源的、质量良好的JAX-RS参考实现。Jersey实现了所有的API,并且提供了能够快速简便的开发REST类型的Java web service的注解。它还使用自己定义的API(如Jersey Client API)提供了很多附加的特性。对于RESTful web service,Jersey使用的是名为Grizzly的web 服务器。对该容器的请求会被一个Grizzly Servlet处理,该Servlet的全名是com.sun.jersey.spi.container.servlet.ServletContainer.
使用Spring编写RESTful web service
使用Spring MVC对RESTful web service的支持,Java开发人员能够使用继承自Spring的MVC框架的注解来构建RESTful的应用程序。对于RESTful应用程序的客户端的支持是RestTemplate API提供的,该API在概念上和JdbcTemplate或JmsTemplate十分类似。REST功能是HttpConverters类提供的,该类帮助将对象转换成HTTP请求或回应中的representation,或者是相反的过程。为了完成对象和XML之间的映射,Spring提供了MarshallingHttpMessageConverter类。
Spring web MVC使用了DispatcherServlet来将请求分发给处理器。默认的处理器是使用@Controller和@RequestMapping注解标明的。这两个注解在使用Spring开发RESTful的应用程序扮演了主要的角色,实际上这两个注解和另外一个注解#PathVariable构成了Spring中RESTful功能的基础。注解@Controller被用来将一个POJO标记为控制器,注解@RequestMapping用来将请求映射到类或处理器方法。
Spring控制器和RESTful web service
控制器对应Spring web MVC中的C。它们帮助处理用户输入,并为用户将输入通过视图(view)转换为模型(model)。控制器可以通过@controller注解来声明。通常,我们在一个类的顶端使用该注解来上面这个特定的类是控制器。
- @Controller
- public class StockController {
- private final Stock stock;
- @AutoWired
- public StockController(Stock stock) {
- this.stock = stock;
- }
- @RequestMapping("/")
- public void stockInfo() {
- }
- @RequestMapping("/stockdetails")
- public String getStockDetails() {
- return this.stock.getStockDetails();
- }
- }
URI模板
一个URI模板是一个将URI作为字符串保持的模板。通常,一个URI模板会含有变量,当这些变量被值替换的时候,URI模板就变成了实际的URI。我们可以在@RequestMapping注解中使用URI模板。
例如,URI http://www.helloworld.com/users/ {username}就是一个URI模板,允许使用实际的用户名来替换username,例如 http://www.helloworld.com/users/john 。处理器将实际的UIR和URI模板进行比较并替换其中的参数。
- @RequestMapping(value="/users/{username}", method=RequestMethod.GET)
- public String sayHello(Model model) {
- ......
- return "Hello, Welcome!";
- }
Spring注解 : @PathVariable
注解@PathVariable被用来将UIR模板变量和方法参数绑定到一起。在前面的例子中,可以使用@PathVariable注解就爱那个URI模板变量username和方法参数userName绑定到一起。使用了@PathVariable声明的方法参数的类型并不一定要是字符串,可以是原始类型,如int,long,double等。
- @RequestMapping(value="/users/{username}", method=RequestMethod.GET)
- public String sayHello(@PathVariable("username") String userName, Model model) {
- ......
- return "Hello "+userName+", Welcome!";
- }
- @RequestMapping(value="/users/{username}/city/{cityname}", method=RequestMethod.GET)
- public String sayHello(@PathVariable("username") String userName, @PathVariable("cityname") String cityName, Model model) {
- ......
- }
- @Controller
- @RequestMapping(value="/users/{username}")
- public class SayHelloController {
- @RequestMapping(value="/city/{cityname}")
- public String sayHello(@PathVariable("username") String userName, @PathVariable("cityname") String cityName, Model model) {
- ......
- }
- }
Spring注解 : @RequestParam
注解@RequestParam被用来将请求参数和方法参数绑定在一起。注解@RequestBody用来表明参数被绑定到HTTP request body中的值。在发送回应的时候,注解@ResponseBody能够白用来将值返回到HTTPrquest body中。
- @Controller
- @RequestMapping("/stockquote")
- public class StockController {
- .....
- @RequestMapping(method=RequestMethod.GET)
- public double getStockPrice(@RequestParam("stockSymbol") String stockSymbol, Model model) {
- ...
- model.setAttribute("stockSymbol", stockSymbol);
- ...
- }
- .....
- .....
- }
Spring中的RESTful客户端
我们前面提到过,RestTemplate是用来在客户端访问RESTful服务的类。仅管和其他的Spring中的模板类很相似,我们还是可以通过提供回调方法和配置HttpMessageConverter类来客户化该模板。客户端的操作可以完全使用RestTemplate和HttpMessageConveter类来执行。
RestTemplate类
在Java中,Jakarta Commons HttpClient类被用来调用RESTful服务。对于普通的操作,HttpClient的executeMethod被用来执行对应6种HTTP方法的高层次的操作。RestTemplate提供了一组方法来确保REST的最佳实践。RestTemplate类提供的这些方法对应的HTTP方法是:
HTTP方法 | RestTemplate方法 |
GET | getForObject getForEntity |
POST | postForLocation(String url, Object request, String... urlVariables) postForObject(String url, Object request, Class<t> responseType, String...urlVariables) |
PUT | put(String url, Object request, String...urlVariables) |
DELETE | delete |
HEAD | headForHeaders(String url, String... urlVariables) |
OPTIONS | optionsForAllow(String url, String... urlVariables) |
RestTemplate类的方法名传递的含义很简单。第一部分是其对应的HTTP方法的名字;第二部分表明了返回的值。例如getForObject方法,该方法会执行GET操作并从HTTP response中返回一个对象(HTTP response被转换成对象类型)。同样的,postForLocation方法执行一个POST操作并返回一个HTTP location header,指明了新创建的对象的位置。
RestTemplate类的方法接受一个字符串类型的URL。RestTemplate对象可以使用默认的构造函数来创建,客户使用java.net包中的API来创建HTTP request。下面是一个客户使用RestTemplate类访问RESTful web service的例子
- ........
- String uri = "http://stock.com/stockdata/{symbol}/stockquote";
- RestTemplate template = new RestTemplate();
- StockQuote sq = new StockQuote();
- ........
- URI location = template.postForLocation(uri, sq, "INFY");
- ........
HTTP Message转换器
发送给RestTemplate方法的对象以及从RestTemplate方法返回的对象被HttpMessageConverter接口转换成HTTP消息——HTTP request和HTTP response。该接口有以下的方法:
boolean canRead(Class<?>clazz, MediaType mediaType):用来判定给定的类和媒体类型能否被转换器读
boolean canWrite(Class<?> clazz, MediaType mediaType):用来判定给定的类和媒体类型能否被转换器写
List<MediaType> getSupportedMediaTypes():返回一个支持的MediaType对象的列表
T read(Class<T> clazz, HttpInputMessage inputMessage):从给定的inputMessage中读取对象并返回该对象
void write(T t, HttpOutputMessage outputMessage):将给定的对象写入给定的outputMessage中。
对MIME类型的转换器是默认生效的。我们也可以编写客户自己的转换器。下面的表格中列出了默认的转换器的实例:
转换器 | 详细 |
ByteArrayHttpMessageConverter | 能够从HTTP message中读写byte数组的转换器 支持所有的MIME类型*/*,默认使用application/octet-stream进行写 |
StringHttpMessageConverter | 从HTTP message中读写String对象的转换器 支持MIME类型text/*,默认使用text/plain进行写 |
FormHttpMessageConverter | 从HTTP message中读写表单数据 默认支持MIME类型application/x-www-form-urlencoded |
SourceHttpMessageConverter | 可以从HTTP message中读写javax.xml.transform.Source的转换器。支持的Source只有DOMSource,SAXSource和StreamSource 默认支持的MIME类型是text/xml和application/xml。 |
MarshallingHttpMessageConverter | 可以使用Spring的Marshaller和UnMarshaller来读写xml的转换器 默认支持的MIME类型是text/xml和application/xml。 |
MappingJacksonHttpMessageConverter | 可以使用Jackson ObjectMapper读取JSON的转换器 默认支持的MIME类型是application/json |
BufferedImageHttpMessageConverter | 可以从HTTP message读写java.awt.image.BufferedImage的转换器 支持所有Java I/O API支持的MIME类型 |
总结
RESTful web service最适合于需要无状态的web service的情况,这种情况下基于REST的价格提供了更好的性能和缓存选择。本文中我们介绍了Spring框架对构建RESTful web service提供的良好的支持,使得可以使用注解和象RestTemplate这样API简单而优雅的构建一个RESTful web service。