使用表示状态传输(REST)样式体系结构,围绕资源表示的传输构建请求和响应。 资源由通常使用统一资源标识符(URI)的全局ID标识。 客户端应用程序使用HTTP方法(例如GET,POST,PUT或DELETE)来操纵资源或资源集合。 通常,GET方法用于获取或列出资源或资源集合,POST用于创建资源,PUT用于更新或替换,DELETE用于删除资源。
例如, GET http://host/context/employees/12345
获取ID为GET http://host/context/employees/12345
的员工的表示形式 。响应表示形式可以是包含详细员工信息的XML或ATOM,也可以是JSP / HTML提供更好UI的页面。 您将看到哪种表示形式取决于服务器端实现和客户端请求的MIME类型。
RESTful Web服务是使用HTTP和REST原理实现的Web服务。 通常,RESTful Web服务将定义基本资源URI,其支持的表示/响应MIME类型以及其支持的操作。
在本文中,学习如何使用Spring来构建Java服务器端RESTful Web服务。 该示例将为发出请求的客户端使用浏览器,curl和Firefox插件RESTClient 。 您可以下载本文中使用的源代码。
本文假定您熟悉REST基础。
Spring 3 REST支持
在Spring框架支持REST之前,人们使用其他几种实现(例如Restlet,RestEasy和Jersey)来帮助在Java世界中构建RESTful Web服务。 在组中最重要的泽西岛是JAX-RS(JSR 311)的参考实现。
Spring是一个广泛使用的Java EE框架,在发行版3中增加了对构建RESTful Web服务的支持。尽管REST支持不是JAX-RS的实现,但它具有的功能比规范定义的更多。 REST支持无缝集成到Spring的MVC层中,并且可以由使用Spring构建的应用程序轻松采用。
Spring REST支持的主要功能包括:
- 注释,例如
@RequestMapping
和@PathVariable
,以支持资源标识和URI映射 -
ContentNegotiatingViewResolver
以支持具有不同MIME /内容类型的不同表示形式 - 通过类似的编程模型无缝集成到原始MVC层中
构建示例RESTful Web服务
本节中的示例将介绍如何设置Spring 3环境并创建可以集成到Tomcat中的“ Hello world”应用程序,然后我们通过一个更复杂的应用程序来介绍Spring 3 REST支持的要点,例如多个MIME。类型表示支持和JAXB支持。代码段帮助说明概念。您可以下载本文的所有示例代码。
Hello World:使用Spring 3 REST支持
要设置示例的开发环境,您需要:
- 一个IDE:适用于JEE的Eclipse IDE(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处理服务级配置(例如数据源bean)。 清单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" />
在上面的代码中:
-
对具有Spring批注的类启用自动扫描
实际上,它用于检测在控制器类中定义的@Controller
批注。 -
Bean将在要由Spring处理的类或方法上进行
@ReqeustMapping
批注
下一节将详细讨论该注释。 - 定义使用JAXB 2进行对象XML映射(OXM)的编组器/解组器
-
定义一个利用Jaxb2Mashaller的XML表示
view
-
使用用户指定的Bean名称定义视图解析器
该示例将使用MarshallingView
名称“ employees”。
Component-scan
DefaultAnnotationHanlderMappings
和AnnotationMethodHandlerAdapter
Jaxb2Mashaller
MashallingView
BeanNameViewResolver
这样就完成了与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));
returnnew 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
是一个基于内存的简单数据源,其实现不在本文讨论范围之内。
将Web应用程序发布到Tomcat。 此时,您可以打开浏览器并输入http://<host>:<port>/<appcontext>/service/employee/1
。 浏览器应显示ID为1的员工的XML视图。
继续阅读以了解有关Spring REST支持的更多功能。
方法
使用诸如GET,POST,PUT和DELETE之类的HTTP方法来操纵资源。 以前,您学习了如何使用GET
方法检索员工信息。 现在,我们将进行POST,PUT和DELETE。
使用@RequestMapping
批注的功能,用于处理不同方法的代码非常相似。 清单4显示了EmployeeController
类的代码片段。
清单4. dw.spring3.rest.controller中的EmployeeController
@RequestMapping(method=RequestMethod.POST, value="/employee")
public ModelAndView addEmployee(@RequestBody String body) {
Source source = new StreamSource(new StringReader(body));
Employee e = (Employee) jaxb2Mashaller.unmarshal(source);
employeeDS.add(e);
returnnew ModelAndView(XML_VIEW_NAME, "object", e);
}
@RequestMapping(method=RequestMethod.PUT, value="/employee/{id}")
public ModelAndView updateEmployee(@RequestBody String body) {
Source source = new StreamSource(new StringReader(body));
Employee e = (Employee) jaxb2Mashaller.unmarshal(source);
employeeDS.update(e);
returnnew ModelAndView(XML_VIEW_NAME, "object", e);
}
@RequestMapping(method=RequestMethod.DELETE, value="/employee/{id}")
public ModelAndView removeEmployee(@PathVariable String id) {
employeeDS.remove(Long.parseLong(id));
List<Employee> employees = employeeDS.getAll();
EmployeeList list = new EmployeeList(employees);
returnnew ModelAndView(XML_VIEW_NAME, "employees", list);
}
在上面的代码中:
-
RequestMethod.<Method>
值标识带注释的方法应处理的HTTP方法。 - 使用
@RequestBody
,可以将HTTP请求的正文内容作为参数注入。在示例中,主体是代表员工的XML数据。 我们使用JAXB 2将XML解组到Java bean,然后将其持久化。 样本请求正文可以是:
<employee><id>3</id><name>guest</name></employee>
- 可以注入到方法参数中的其他有用的注释是
@PathVariable
,@RequestParm
@PathVariable
等。 Spring文档提供了注释的完整列表(请参阅参考资料 )。
资源收集
通常,您还需要操纵一组资源。 例如,您可能希望获取所有员工信息,而不是仅获取个人信息。 这可以与先前的情况类似地实现; 您需要更改的只是从/ employee到/ employees的URI。 员工的复数形式适合集合语义。 清单5显示了实现。
清单5. EmployeeController中的getAllEmployees
@RequestMapping(method=RequestMethod.GET, value="/employees")
public ModelAndView getEmployees() {
List<Employee> employees = employeeDS.getAll();
EmployeeList list = new EmployeeList(employees);
returnnew ModelAndView(XML_VIEW_NAME, "employees", list);
}
您需要为Employee集合声明包装器类。 JAXB 2需要包装器类,因为它无法正确编组java.util.List类。 清单6显示了EmployeeList
类。
清单6. dw.spring3.rest.bean中的EmployeeList类
@XmlRootElement(name="employees")
publicclass EmployeeList {
privateint count;
private List<Employee> employees;
public EmployeeList() {}
public EmployeeList(List<Employee> employees) {
this.employees = employees;
this.count = employees.size();
}
publicint getCount() {
return count;
}
publicvoid setCount(int count) {
this.count = count;
}
@XmlElement(name="employee")
public List<Employee> getEmployees() {
return employees;
}
publicvoid setEmployees(List<Employee> employees) {
this.employees = employees;
}
}
内容协商
REST服务的另一个共同特征是,它们可以根据请求生成不同的表示形式。 例如,如果客户端请求所有员工HTML /文本表示,则服务器应为用户生成格式正确HTML页面。 如果客户端请求员工的应用程序/ 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
。 该代码还定义了两个视图解析器:一个用于处理application / xml的BeanNameViewResolver
和一个用于处理text / html的UrlBasedViewResolver
。
实际上,当您在浏览器中输入http://<host>:<port>/<appcontext>/service/employees
时,它会为员工请求text/html
。 然后UrlBasedViewResolver
将生效,Spring将选择/WEB-INF/jsp/employees.jsp作为其视图。 当您添加请求标头Accept:application/xml
并调用请求时, BeanNameViewResolver
将生效。 根据清单5中的代码,它将使用名为employees
的视图来表示,这是已定义的JAXB 2 marshaller视图。
getAllEmployees()
的控制器代码不会更改。 employee.jsp页面将使用名为employees
的模型对象来呈现自身。 清单8显示了employee.jsp的代码片段。
清单8. / WEB-INF / jsp中的employees.jsp
<table border=1>
<thead><tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
</tr></thead>
<c:forEach var="employee" items="${employees.employees}">
<tr>
<td>${employee.id}</td>
<td>${employee.name}</td>
<td>${employee.email}</td>
</tr>
</c:forEach>
</table>
与REST服务通信的客户端
到目前为止,您已经开发了一个简单的RESTful Web服务,该服务支持员工的CRUD(创建,读取,更新和删除)操作。 本节探讨如何与服务进行通信。 您将使用curl测试REST服务。
您还可以使用名为RESTClient的Firefox插件来测试REST服务。 它易于使用并且具有良好的UI。 请参阅参考资料以获取下载信息。
使用卷曲
Curl是一种流行的命令行工具,可以使用HTTP和HTTPS协议将请求发送到服务器。 这是与RESTful Web服务进行通信的有用工具,因为它可以通过任何HTTP方法发送内容。 Curl是Linux®和Mac®上的内置实用程序。 对于Windows®平台,您可以下载该工具(请参阅参考资料 )。
要初始化将获取所有雇员的第一个curl命令,请输入:
curl –HAccept:application/xml
http://localhost:8080/rest/service/employees
响应将采用XML格式,并将包含所有员工,如图1所示。
图1.所有员工的XML表示
您也可以在浏览器中尝试相同的URL。 在这种情况下,Accept标头指定text / html,因此将显示employee.jsp中定义的表。 图2显示了一个示例。
图2.所有员工HTML表示
要将新员工过帐到服务器,请使用以下代码。 清单4中的addEmployee()
代码将使用请求正文并将其解组到Employee
对象。
curl -X POST -HContent-type:application/xml --data
"<employee><id>3</id><name>guest</name><email>guest@ibm.com</email></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</email></employee>"
http://localhost:8080/rest/service/employee/3
上面的代码更新ID为3的员工数据。
摘要
现在,Spring 3在其MVC层中支持REST,您可以使用Spring API和注释来构建RESTful Web服务。 在本文中,示例向您展示了如何使用Spring 3的一些新功能,这些功能将帮助您轻松构建Java服务器端RESTful Web服务。
翻译自: https://www.ibm.com/developerworks/web/library/wa-spring3webserv/index.html