Spring3 RESTful Web服务

Spring 3提供了对RESTful Web服务的支持。 在本教程中,我们将向您展示如何在Spring中实现RESTful Web服务 ,或者如何将现有的Spring服务公开为RESTful Web服务 。 为了使事情变得更有趣,我们将从上一篇关于Spring GWT Hibernate JPA Infinispan HornetQ集成的文章的 开头继续 。 我们将使用GWTSpringInfinispanHornetQ项目,并将“ employeeService” CRUD功能公开为RESTful Web服务 。 当然,您可以参考本文,只是了解如何将Spring服务公开为RESTful Web服务

实现RESTful Web服务的最流行的方法是Sun的JAX-RS规范。 有几个支持JAX-RS的项目,例如CXFJerseyRESTEasyRestlet 。 他们中的大多数人还提供Spring支持。 Spring不直接支持JAX-RS ,而是将RESTful功能添加到了Spring MVC本身。 如果您不熟悉Spring MVC框架,请在此处查阅Spring文档的相应章节。 对于不耐烦的人,下面简要概述。

Spring MVC代表模型视图控制器。 它有助于构建灵活且松散耦合的Web应用程序。 模型-视图-控制器设计模式可确保多层Web应用程序中关注点(业务逻辑,表示逻辑和导航逻辑)的分离。 “控制器”负责接收来自用户的请求并调用后端服务。 模型负责封装应用程序数据。 视图使用模型对象将响应呈现给用户。 简而言之 :

将请求发送到Spring MVC Framework时,将发生以下事件序列。

  • “ DispatcherServlet”首先收到请求
  • “ DispatcherServlet”查询“ HandlerMapping”并调用与请求关联的“ Controller”
  • “控制器”通过调用适当的服务方法来处理请求,并将“ ModeAndView”对象返回到“ DispatcherServlet”。 “ ModeAndView”对象包含模型数据和视图名称
  • “ DispatcherServlet”将视图名称发送到“ ViewResolver”以查找要调用的实际“视图”
  • “ DispatcherServlet”将模型对象传递给“视图”以呈现结果
  • 在模型数据的帮助下,“视图”呈现结果并将其返回给用户

聊够了! 让我们弄脏双手!

我们将需要“ cglib”字节码生成库和“ asm”字节码操作框架,以便Spring能够将AOP方面正确地应用于“ Controller”对象。 我们将使用“CGLIB” 2.2版本,您可以下载在这里和在“asm”二进制分发版,你可以下载在这里 。 在“ asm”二进制发行版的/ lib / all文件夹下找到asm-all-3.3.jar,并将asm-all-3.3.jar和cglib-2.2.jar都放置在项目的/ war / WEB-INF / lib文件夹下。

最后,我们将需要Jackson JSON处理器。 我们将使用1.5.3版的“核心”和“映射器”发行版,您可以从此处下载。 将两个jackson-core-asl-1.5.3.jar
和项目的/ war / WEB-INF / lib文件夹下的jackson-mapper-asl-1.5.3.jar。

我们必须照顾我们的Eclipse项目的依赖性。 以下jar应包含在项目的Java构建路径中:

  • org.springframework.web-3.0.1.RELEASE-A.jar

如上所述,“ DispatcherServlet”是一个用于管理整个请求处理过程的servlet。 与其他任何servlet一样,它需要在Web部署描述符或我们的应用程序中进行配置。 在/ war / WEB-INF文件夹下找到“ web.xml”文件,然后添加以下内容:

<servlet>
 <servlet-name>dispatcher</servlet-name>
 <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class>
 <load-on-startup>2</load-on-startup>
</servlet>

<servlet-mapping>
 <servlet-name>dispatcher</servlet-name>
 <url-pattern>/restServices/*</url-pattern>
</servlet-mapping>

默认情况下,“ DispatcherServlet”将查找名为“ {servlet-name} –servlet.xml”的文件以加载Spring MVC配置。 在我们的例子中是“ dispatcher-servlet.xml”。 在这里,我们将url –模式用作“ / restServices / *”,以便“ DispatcherServlet”仅处理指定模式下的所有传入请求。 创建一个“ dispatcher–servlet.xml”文件,并将其放在/ war / WEB-INF文件夹下,如下所示:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

<context:component-scan base-package="com.javacodegeeks.gwtspring.server.endpoints" />

<tx:annotation-driven />

<mvc:annotation-driven />

</beans>

这里要注意的事情:

  • 我们将“ context:component-scan”配置元素的base-package属性设置为我们的Spring MVC注释类将驻留的位置
  • 我们使用“ tx:annotation-driven”配置元素,以便能够向我们的MVC类注入事务行为
  • “ mvc:annotation-driven”是Spring 3的配置元素,可大大简化Spring MVC的设置。 该标签注册了将请求分派到@Controller注释类的所需的“ HandlerMapping”和“ HandlerAdapter”。 另外,它根据您的类路径中存在的内容应用合理的默认值。 这样的默认值包括(包括其他):
    • 支持使用@NumberFormat注释格式化数字字段
    • 如果类路径上有Joda Time,则支持使用@DateTimeFormat批注格式化Date,Calendar和Joda Time字段
    • 如果类路径上有JSR-303提供者,则支持使用@Valid注释验证@Controller注释的类输入
    • 如果类路径上包含JAXB ,则支持读写XML
    • 如果杰克逊在类路径上,则支持读写JSON

在项目的“服务器”包下创建一个“端点”子包。 就GWT而言,服务端点是服务器端组件,因此所有类都必须放在“服务器”包下。 在“端点”子包下,放置“ EmployeeServiceController”类,如下所示:

package com.javacodegeeks.gwtspring.server.endpoints;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.javacodegeeks.gwtspring.shared.dto.EmployeeDTO;
import com.javacodegeeks.gwtspring.shared.services.EmployeeService;

@Controller
@RequestMapping("/employeeService")
public class EmployeeServiceController {

 @Autowired
 EmployeeService employeeService;

 @RequestMapping(value = "/{id}", method = RequestMethod.GET)
 @ResponseBody
 public EmployeeDTO findEmployee(@PathVariable("id") long employeeId) {
  return employeeService.findEmployee(employeeId);
 }

 @RequestMapping(value = "/{id}/{name}/{surname}/{job}", method = RequestMethod.POST)
 @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
 public String saveEmployee(@PathVariable("id") long employeeId, @PathVariable String name, @PathVariable String surname, @PathVariable("job") String jobDescription) throws Exception {
  employeeService.saveEmployee(employeeId, name, surname, jobDescription);
  return "redirect:/restServices/employeeService/" + employeeId;
 }

 @RequestMapping(value = "/{id}/{name}/{surname}/{job}", method = RequestMethod.PUT)
 @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
 public String updateEmployee(@PathVariable("id") long employeeId, @PathVariable String name, @PathVariable String surname,  @PathVariable("job") String jobDescription) throws Exception {
  employeeService.updateEmployee(employeeId, name, surname, jobDescription);
  return "redirect:/restServices/employeeService/" + employeeId;
 }

 @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
 @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
 @ResponseBody
 public String deleteEmployee(@PathVariable("id") long employeeId) throws Exception {
  employeeService.deleteEmployee(employeeId);
  return "OK";
 }

}

我们提供“ EmployeeService”和“ EmployeeDTO”实现作为参考:

package com.javacodegeeks.gwtspring.server.services;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.javacodegeeks.gwtspring.server.dao.EmployeeDAO;
import com.javacodegeeks.gwtspring.server.utils.NotificationsProducer;
import com.javacodegeeks.gwtspring.shared.dto.EmployeeDTO;
import com.javacodegeeks.gwtspring.shared.services.EmployeeService;

@Service("employeeService")
public class EmployeeServiceImpl implements EmployeeService {

 @Autowired
 private EmployeeDAO employeeDAO;

 @Autowired
 NotificationsProducer notificationsProducer;

 @PostConstruct
 public void init() throws Exception {
 }

 @PreDestroy
 public void destroy() {
 }

 public EmployeeDTO findEmployee(long employeeId) {
  return employeeDAO.findById(employeeId);
 }

 @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
 public void saveEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception {

  EmployeeDTO employeeDTO = employeeDAO.findById(employeeId);

  if(employeeDTO == null) {
   employeeDTO = new EmployeeDTO(employeeId, name,surname, jobDescription);
   employeeDAO.persist(employeeDTO);
  }

 }

 @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
 public void updateEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception {

  EmployeeDTO employeeDTO = employeeDAO.findById(employeeId);

  if(employeeDTO != null) {
   employeeDTO.setEmployeeName(name);
   employeeDTO.setEmployeeSurname(surname);
   employeeDTO.setJob(jobDescription);
  }

}

 @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
 public void deleteEmployee(long employeeId) throws Exception {

  EmployeeDTO employeeDTO = employeeDAO.findById(employeeId);

  if(employeeDTO != null)
   employeeDAO.remove(employeeDTO);

 }

 @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
 public void saveOrUpdateEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception {

  EmployeeDTO employeeDTO = new EmployeeDTO(employeeId, name,surname, jobDescription);

  employeeDAO.merge(employeeDTO);

  notificationsProducer.sendNotification("Save Or Update Employee with values : \nID : " + employeeId + "\nName : " + name + "\nSurname : " + surname + "\nJob description : " + jobDescription);

 }

}

如您所见,“ EmployeeServiceController”充当“ employeeService”类的包装器类。 我们参考了实际的服务,并实现了直接调用服务功能的方法。 要将具有“控制器”功能的“ EmployeeServiceController”类注入,我们只需对其进行注释即可。 @Controller注释指定被注释的类是“ Controller”类,可用于“ DispatcherServlet”将请求委托给它。

在本教程的开始,我们谈到了“ DispatcherServlet”如何使用“ HandlerMappings”来选择适当的“ Controllers”以委派用户请求。 @RequestMapping批注用于将Web请求映射到特定的处理程序类和/或处理程序方法。 因此,通过在类型级别使用@RequestMapping(“ / employeeService”)批注,我们指示“ DispatcherServlet”将“ / employeeService”资源URI下的所有Web请求委托给“ EmployeeServiceController”实例。 此外,我们在方法级别使用@RequestMapping批注,以根据请求的资源URI将“ DispatcherServlet”委托范围缩小到特定操作。 您应该已经注意到@PathVariable注释的使用。 在Spring 3中,引入了通过@PathVariable注释使用URI模板的方法。 URI模板是一个URI –类似于字符串,包含一个或多个变量名。 当这些变量代替值时,模板将成为URI。 因此,对“ / employeeService / 1”资源URI的客户端HTTP GET请求将委派给我们的“ EmployeeServiceController”实例的“ findEmployee”操作,并且“ employeeId”参数的值将设置为1。

注意:仅当分派器中存在相应的“ HandlerMapping”(用于类型级别的注释)和/或“ HandlerAdapter”(用于方法级别的注释)时,才会处理@RequestMapping。 由于Spring 3 MVC的简化,在“ dispatcher-servlet.xml”中使用“ mvc:annotation-driven”配置元素可以满足我们的所有配置需求。

在本教程的开始,我们谈到了“控制器”如何通过调用适当的服务方法来处理每个请求并将“ ModeAndView”对象返回到“ DispatcherServlet”。 “ ModeAndView”对象包含模型数据和视图名称,以便正确地呈现给客户端。 这种行为并不总是令人满意的。 例如,在我们的示例中,我们想将服务响应序列化到HTTP响应主体。 可以将@ResponseBody批注放在方法上,并指示将返回类型直接写到HTTP响应主体(而不是放置在Model中或解释为视图名称)。 根据客户端接受的内容类型(信息来自客户端请求的“ Accept” HTTP Header字段),我们将返回服务回复的XML或JSON表示形式。 为此,我们通过Spring OXM模块和Jackson JSON处理器使用JAXB编组器和反编组器。

最后,您应该注意到“ saveEmployee”和“ updateEmployee”操作。 这两个没有@ResponseBody批注,并返回“ redirect:/ restServices / employeeService / + employeeId”字符串。 “ Controller”方法可以返回“特殊” String值,该值会向“ DispatcherServlet”发出命令。 使用上述重定向命令,“ DispatcherServlet”会将调用重定向到与指定URI资源关联的“ Controller”方法(在我们的示例中为“ findEmployee”操作)。 因此,当客户端发出“ saveEmployee”或“ updateEmployee”命令时,将收到刚刚插入或更新的“ employeeDTO”对象的XML或JSON表示作为答复。

下面我们介绍DTO类。

package com.javacodegeeks.gwtspring.shared.dto;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

@Cache (usage=CacheConcurrencyStrategy.TRANSACTIONAL)
@Entity
@XmlRootElement
@Table(name = "EMPLOYEE")
public class EmployeeDTO implements java.io.Serializable {

 private static final long serialVersionUID = 7440297955003302414L;

 @Id
 @Column(name="employee_id")
 private long employeeId;

 @Column(name="employee_name", nullable = false, length=30)
 private String employeeName;

 @Column(name="employee_surname", nullable = false, length=30)
 private String employeeSurname;

 @Column(name="job", length=50)
 private String job;

 public EmployeeDTO() {
 }

 public EmployeeDTO(int employeeId) {
  this.employeeId = employeeId;        
 }

 public EmployeeDTO(long employeeId, String employeeName, String employeeSurname,
 String job) {
  this.employeeId = employeeId;
  this.employeeName = employeeName;
  this.employeeSurname = employeeSurname;
  this.job = job;
 }

 public long getEmployeeId() {
  return employeeId;
 }

 public void setEmployeeId(long employeeId) {
  this.employeeId = employeeId;
 }

 public String getEmployeeName() {
  return employeeName;
 }

 public void setEmployeeName(String employeeName) {
  this.employeeName = employeeName;
 }

 public String getEmployeeSurname() {
  return employeeSurname;
 }

 public void setEmployeeSurname(String employeeSurname) {
  this.employeeSurname = employeeSurname;
 }

 public String getJob() {
  return job;
 }

 public void setJob(String job) {
  this.job = job;
 }
}

这里唯一需要注意的是,我们已经用@XmlRootElement注释对DTO类进行了注释,以便被JAXB编组器正确编组。

而已! 要部署Web应用程序,只需将/ war文件夹复制到Apache – Tomcat “ webapps”文件夹中。 您可以将war文件夹的名称更改为自己喜欢的名称,最好在项目名称后重命名,例如GWTSpringInfinispanHornetQRemoting

在午餐之前,应用程序不要忘记创建数据库模式,这里是“ javacodegeeks”。

在此示例中,我们使用了Apache Derby数据库版本10.6.1.0。 您可以在此处下载二进制发行版。 在发行版的/ lib目录下找到derby.jar并将其放置在项目的/ war / WEB-INF / lib目录下。 要使用Spring配置嵌入式数据库,请在/ war / WEB-INF目录下的applicationContext.xml中添加以下配置代码:

<bean id="dataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
 <property name="uniqueResourceName" value="javacodegeeks" />
 <property name="xaDataSourceClassName" value="org.apache.derby.jdbc.EmbeddedXADataSource" />
 <property name="xaProperties">
  <props>
   <prop key="databaseName">javacodegeeks</prop>
   <prop key="createDatabase">create</prop>
  </props>
 </property>
 <property name="maxPoolSize" value="50" />
 <property name="minPoolSize" value="20" />
</bean>

您可以下载RESTClient并测试“ employeeService”的REST接口,如下所示:

  • 发出“ http:// localhost:8080 / GWTSpringInfinispanHornetQRemoting / restServices / employeeService / 1 / myName / mySurname / myJob”的POST请求,然后应检索新创建的“ employeeDTO”的XML表示形式,如下所示:
<?xml version="1.0" encoding="UTF-8" standalone="yes">
<employeeDTO>
 <employeeId>1</employeeId>
 <employeeName>myName</employeeName>
 <employeeSurname>mySurname</employeeSurname>
 <job>myJob</job>
</employeeDTO>
  • 对http:// localhost:8080 / GWTSpringInfinispanHornetQRemoting / restServices / employeeService / 1发出GET请求,通过POST操作将收到相同的结果
  • 发出PUT请求,并从“ employeeDTO”对象更新您喜欢的任何字段。 该服务将以更新的“ employeeDTO” XML表示形式进行回复
  • 对http:// localhost:8080 / GWTSpringInfinispanHornetQRemoting / restServices / employeeService / 1发出DELETE请求,您将收到“确定”答复!
  • 在添加HTTP标头指令以将接受的内容类型定义为“ application / json”后,发出上述命令。 返回的“ employeeDTO”表示应如下所示:
{"employeeId":1,"employeeName":"myName","employeeSurname":"mySurname","job":"myJob"}

您可以从此处下载该项目(如开头所述,并且不包含先前的文章,所需的第三方库)

玩得开心!

贾斯汀

相关文章 :

翻译自: https://www.javacodegeeks.com/2010/06/spring-3-restful-web-services.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值