通过REST风格体系架构,请求和响应都是基于资源表示的传输来构建的。资源是通过全局ID来标识的,这些ID一般使用的是一个统一资源标识符(URI)。客户端应用使用HTTP方法(如,GET、POST、PUT或DELETE)来操作一个或多个资源。通常,GET是用于获取或列出一个或多个资源,POST用于创建,PUT用于更新或替换,而DELETE则用于删除资源。
例如,GET http://host/context/employees/12345将获取ID为12345的员工的表示。这个响应表示可以是包含详细的员工信息的XML或ATOM,或者是具有更好UI的JSP/HTML页面。您看到哪种表示方式取决于服务器端实现和您的客户端请求的MIME类型。
RESTful Web Service是一个使用HTTP和REST原理实现的Web Service。通常,一个RESTful Web Service将定义基本资源URI、它所支持的表示/响应MIME,以及它所支持的操作。
本文将介绍如何使用Spring创建Java实现的服务器端RESTful Web Services。这个例子将使用浏览器、curl和Firefox插件RESTClient作为发出请求的客户端。
本文假定您是熟悉REST基本知识的。
Spring 3的REST支持
在Spring框架支持REST之前,人们会使用其他几种实现技术来创建Java RESTful Web Services,如Restlet、RestEasy和Jersey。Jersey是其中最值得注意的,它是JAX-RS(JSR 311)的参考实现。
Spring是一个得到广泛应用的Java EE框架,它在版本3以后就增加了RESTful Web Services开发的支持。虽然,对REST的支持并不是JAX-RS的一种实现,但是它具有比标准定义更多的特性。REST支持被无缝整合到Spring的MVC层,它可以很容易应用到使用Spring构建的应用中。
Spring REST支持的主要特性包括:
- 注释,如@RequestMapping 和 @PathVariable,支持资源标识和URL映射
- ContentNegotiatingViewResolver支持为不同的MIME/内容类型使用不同的表示方式
- 使用相似的编程模型无缝地整合到原始的 MVC 层
创建一个示例RESTful Web Service
本节中的例子将演示Spring 3环境的创建过程,并创建一个可以部署到Tomcat中的“Hello World”应用。然后我们再完成一个更复杂的应用来了解Spring 3 REST支持的重要概念,如多种MIME类型表示支持和JAXB支持。另外,本文还使用一些代码片断来帮助理解这些概念。
Hello World:使用Spring 3 REST支持
要创建这个例子所使用的开发环境,您需要:
- IDE:Eclipse IDE for JEE (v3.4+)
- Java SE5 以上
- Web 容器:Apache Tomcat 6.0(Jetty或其他容器也可)
- Spring 3框架(v3.0.3是本文编写时的最新版本)
- 其他程序库:JAXB 2、JSTL、commons-logging
在 Eclipse 中创建一个Web应用,然后设置Tomcat 6作为它的运行环境。然后,您需要设置web.xml文件来激活Spring
WebApplicationContext。这个例子将Spring bean配置分成两个文件:rest-servlet.xml 包含与MVC/REST有关的配置,rest-context.xml包含服务级别的配置(如数据源 beans)。清单 1 显示了web.xml中的Spring配置的部分。
清单 1. 在web.xml中激活Spring WebApplicationContext
以下是引用片段: <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/rest-context.xml </param-value> </context-param> <!– This listener will load other application context file in addition to rest-servlet.xml –> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <servlet> <servlet-name>rest</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>rest</servlet-name> <url-pattern>/service/*</url-pattern> </servlet-mapping> |
在rest-servlet.xml文件中创建Spring MVC的相关配置(Controller、View、View Resolver)。清单 2 显示了其中最重要的部分。
清单 2. 在rest-servlet.xml文件中创建Spring MVC配置
以下是引用片段: <context:component-scan base-package=”dw.spring3.rest.controller” /> <!–To enable @RequestMapping process on type level and method level–> <bean class=”org.springframework.web.servlet.mvc.annotation .DefaultAnnotationHandlerMapping” /> <bean class=”org.springframework.web.servlet.mvc.annotation .AnnotationMethodHandlerAdapter” /> <!–Use JAXB OXM marshaller to marshall/unmarshall following class–> <bean id=”jaxbMarshaller” class=”org.springframework.oxm.jaxb.Jaxb2Marshaller”> <property name=”classesToBeBound”> <list> <value>dw.spring3.rest.bean.Employee</value> <value>dw.spring3.rest.bean.EmployeeList</value> </list> </property> </bean> <bean id=”employees” class= “org.springframework.web.servlet.view.xml.MarshallingView”> <constructor-arg ref=”jaxbMarshaller” /> </bean> <bean id=”viewResolver” class= “org.springframework.web.servlet.view.BeanNameViewResolver” /> |
上面的代码中:
Component-scan启用对带有Spring注释的类进行自动扫描,在实践中,它将检查控制器类中所定义的@Controller注释。
DefaultAnnotationHanlderMappings和AnnotationMethodHandlerAdapter使用@ReqeustMapping注释的类或函数的beans由Spring处理这个注释将在下一节进行详细介绍。
Jaxb2Mashaller定义使用JAXB 2进行对象XML映射(OXM)的编组器(marshaller)和解组器(unmarshaller )
MashallingView定义一个使用Jaxb2Mashaller的XML表示view
BeanNameViewResolver使用用户指定的bean名称定义一个视图解析器
本例将使用名为“employees”的MarshallingView。
这样就完成了Spring的相关配置。下一步是编写一个控制器来处理用户请求。清单3显示的是控制器类。
清单 3. dw.spring3.rest.controller.EmployeeController
以下是引用片段: @Controller publicclass EmployeeController { @RequestMapping(method=RequestMethod.GET, value=”/employee/{id}”) public ModelAndView getEmployee(@PathVariable String id) { Employee e = employeeDS.get(Long.parseLong(id)); return new ModelAndView(XML_VIEW_NAME, “object”, e); } } |
@RequestMapping注释是Spring REST特性的关键所在。它指定所注释的方法将处理哪个HTTP方法(RequestMethod.GET)和哪个URI(/employee/{id})。注意:
- 对于{id}占位符,使用@PathVariable注释可以将{}内的值注入到函数的参数。
- XML_VIEW_NAME为employees,这是rest-servlet.xml中定义的视图名称。
- employeeDS是一个基于内存的数据源,它的实现已经超出本文写作范围。
在上面的代码中:
- RequestMethod.<Method>的值确定所注释的函数应该处理哪个HTTP方法。
- 通过@RequestBody,HTTP请求的主体内容可以作为一个参数注入。
- 在本例中,主体内容是表示员工信息的XML数据。我们使用JAXB 2来将XML解组为Java Bean,然后将它存储。一个示例请求主体可以是: <employee><id>3</id><name>guest</name></employee>
- 其他可以注入到函数参数的有用的注释有@PathVariable、@RequestParm等等。
资源集合
通常,您还需要操作批量的资源。例如,您可能希望获取所有员工的信息而不只是一个员工的信息。您可以采取类似于之前情况的方法实现;您所需要做的修改就是将URI从/employee修改成/employees。员工的复数形式能够正确反映批量的语义。清单5显示了这种实现方法。
清单 5. EmployeeController的getAllEmployees
以下是引用片段: @RequestMapping(method=RequestMethod.GET, value=”/employees”) public ModelAndView getEmployees() { List<Employee> employees = employeeDS.getAll(); EmployeeList list = new EmployeeList(employees); return new ModelAndView(XML_VIEW_NAME, “employees”, list); } |
您需要为Employee集合声明一个包装类。这个包装类是JAXB 2所需要的,因为它无法正确地编组java.util.List类。清单6显示了 EmployeeList类。
清单 6. dw.spring3.rest.bean.EmployeeList
以下是引用片段: @XmlRootElement(name=”employees”) public class EmployeeList { private int count; private List<Employee> employees; public EmployeeList() {} public EmployeeList(List<Employee> employees) { this.employees = employees; this.count = employees.size(); } public int getCount() { return count; } public void setCount(int count) { this.count = count; } @XmlElement(name=”employee”) public List<Employee> getEmployees() { return employees; } public void setEmployees(List<Employee> employees) { this.employees = employees; } } |
内容协商
REST服务的另一个常用特性是它们能够根据请求产生不同的表示。例如,如果客户端请求所有员工的HTML/text表示方式,那么服务器就应该为用户产生一个符合语法规则的HTML页面。如果客户端请求的是员工的application/XML表示方式,那么服务器就应该产生一个XML 结果。其他受欢迎的表示方式还有ATOM和PDF。
Spring 3引入了一个名为ContentNegotiatingViewResolver的新视图解析器。它可以根据请求的内容类型(请求头中的Accept属性)或URI后缀来切换视图解析器。下面的例子使用ContentNegotiatingViewResolver来实现多种表示方式的支持。
在rest-servlet.xml文件中,用注释去掉原来定义的 viewResolver。而使用ContentNegotiatingViewResolver来替代它,如清单 7所示。
清单 7. 定义内容协商
以下是引用片段: <bean class=”org.springframework.web.servlet.view .ContentNegotiatingViewResolver”> <property name=”mediaTypes”> <map> <entry key=”xml” value=”application/xml”/> <entry key=”html” value=”text/html”/> </map> </property> <property name=”viewResolvers”> <list> <bean class=”org.springframework.web.servlet.view .BeanNameViewResolver”/> <bean class=”org.springframework.web.servlet.view .UrlBasedViewResolver”> <property name=”viewClass” value= “org.springframework.web.servlet.view.JstlView”/> <property name=”prefix” value=”/WEB-INF/jsp/”/> <property name=”suffix” value=”.jsp”/> </bean> </list> </property> </bean> |
这个定义显示了处理两种请求内容的支持:application/xml和text/html。这段代码也定义了两个视图解析器:其中 BeanNameViewResolver是负责处理application/xml的,而另一个UrlBasedViewResolver则负责处理text/html。
与REST服务通信的客户端
现目前为止,您已经开发一个简单的支持对员工信息的CRUD(增删查改)操作的RESTful Web Service。接下来这一节将介绍如何与这个服务进行通信。您将使用curl来测试这个REST服务。
您也可以使用名为RESTClient的Firefox插件来测试REST服务。它很容易使用且带有良好的UI。
使用curl
Curl是一个流行的能以HTTP和HTTPS协议向服务器发送请求的命令行工具。Curl是Linux?和Mac?上的一个内置工具。对于Windows?平台,您可以另外下载这个工具。
要初始化查询所有员工信息的第一个curl命令,您可以输入: curl–HAccept:application/xml
http://localhost:8080/rest/service/employees
它的响应将是XML格式的,并且包含所有的员工信息,如图 1 所示。
图 1. XML方式表示的所有员工信息
您也可以在浏览器上尝试访问相同的URL。这时,头信息中的Accept为text/html,所以浏览器会显示employees.jsp中定义的一个表格。图 2 显示的是这种情况。
图 2. HTML方式表示的所有员工信息
要将一个新的员工信息 POST 到服务器上,我们可以使用下面的代码。清单 4 中的 addEmployee() 代码将会使用请求体并将它解组为 Employee 对象。
以下是引用片段: curl -X POST -HContent-type:application/xml –data “<employee><id>3</id><name>guest</name><email>guest@ibm.com</employee>” http://localhost:8080/rest/service/employee |
这样就添加了一个新的员工信息。您可以使用第一个例子来验证员工列表。
PUT方法类似于POST。
以下是引用片段: curl -X PUT -HContent-type:application/xml –data “<employee><id>3</id><name>guest3</name><email>guest3@ibm.com</employee>” http://localhost:8080/rest/service/employee/3 |
上面的代码修改了ID为3的员工数据。
结束语
现在Spring 3已经在它的MVC层上支持REST了,您可以使用Spring API和注释来开发RESTful Web Services了。本文的示例向您介绍了如何使用一些能够帮您简化开发Java服务器端RESTful Web Services的Spring 3的新特性。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号

TechTarget
官方微博

TechTarget中国
相关推荐
-
SAP收购CallidusCloud 与Salesforce竞争
一直被称为后台办公巨头的SAP现在似乎也想在前台办公大展拳脚。 最新的迹象是SAP收购CallidusClou […]
-
API管理工具能否弥补REST与Web服务之间的鸿沟?
随着企业学习如何通过RESTful利用现有服务,API管理工具正在引起轰动。API管理工具能否弥补REST与Web服务之间的鸿沟?
-
API设计如龙生九子 各不相同
IT咨询管理公司CA Technologies对API产业做了个问卷调查,问卷内容涉及API设计风格以及管理部署的新动向。调查结果表明,JSON与XML可谓两分天下。
-
弹性资源对传统的REST架构构成挑战了吗?
组件化应用程序需要机制来将组件传递到下一个工作地。从一开始,人们对连接流程及其实施就有不同的观点。可以证明,SOA阵营是由RPC和SOAP的软件接口发展而形成的。