RESTEasy入门

RESTEasy是JBoss的开源项目之一,是一个RESTful Web Services框架。RESTEasy的开发者Bill Burke同时也是JAX-RS的J2EE标准制定者之一。JAX-RS是一个JCP制订的新标准,用于规范基于HTTP的RESTful Web Services的API。

我们已经有SOAP了,为什么需要Restful WebServices?用Bill自己的话来说:"如果是为了构建SOA应用,从技术选型的角度来讲,我相信REST比SOAP更具优势。开发人员会意识到使用传统方式有进行SOA架构有多复杂,更不用提使用这些做出来的接口了。这时他们就会发现Restful Web Services的光明之处。"

说了这么多,我们使用RESTEasy做一个项目玩玩看。首先创造一个maven1的web项目

Java代码   收藏代码
  1. mvn archetype:create -DgroupId=org.bluedash \    
  2.   
  3. -DartifactId=try-resteasy -DarchetypeArtifactId=maven-archetype-webapp   

 

准备工作完成后,我们就可以开始写代码了,假设我们要撰写一个处理客户信息的Web Service,它包含两个功能:一是添加用户信息;二是通过用户Id,获取某个用户的信息,而交互的方式是标准的WebService形式,数据交换格式为XML。假设一条用户包含两个属性:Id和用户名。那么我们设计交换的XML数据如下:

Java代码   收藏代码
  1. <user>  
  2.     <id>1</id>  
  3.     <name>liweinan</name>  
  4. </user>  

 

首先要做的就是把上述格式转换成XSD2,网上有在线工具可以帮助我们完成这一工作3,在此不详细展开。使用工具转换后,生成如下xsd文件:

Java代码   收藏代码
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified"  
  3. version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  
  4.   <xsd:element name="user" type="userType" />  
  5.   <xsd:complexType name="userType">  
  6.     <xsd:sequence>  
  7.       <xsd:element name="id" type="xsd:int" />  
  8.       <xsd:element name="name" type="xsd:string" />  
  9.     </xsd:sequence>  
  10.   </xsd:complexType>  
  11. </xsd:schema>  

 

有了xsd文件,我们便可以使用JDK自带工具的xjc将xsd转换成为Java的Class。将上述xsd文件存为 user.xsd,并使用如下命令进行转换:

Java代码   收藏代码
  1. xjc user.xsd  

 执行结束后我们会得到一系列的类文件:

Java代码   收藏代码
  1. Li-Weinans-MacBook-Pro:Desktop liweinan$ xjc user.xsd   
  2. parsing a schema...  
  3. compiling a schema...  
  4. generated/ObjectFactory.java  
  5. generated/UserType.java  

 

这样,我们的XML格式的交换数据便转化为面向对像的Java类了,是不是感觉有点像Hibernate的ORM理念?没错,将XML映射成成面向对象的数据类,这个过程叫做XML Binding,即XML绑定。这个过程也有J2EE标准,叫做JAXB4。而RESTEasy是全面支持JAXB的。可以说RESTEasy所支持的JAX-RS标准,当与JAXB标准结合在一起使用时,就可以发挥出最大优势,让程序员少写一堆一堆的代码。有关JAXB标准,会在独立的篇章中 详细讨论,在此先不展开。总之我们将生成的Java类放进项目中等候使用。我们可以看一下UserType类的内容:

Java代码   收藏代码
  1. package org.bluedash.resteasy;  
  2.   
  3. import javax.xml.bind.annotation.XmlAccessType;  
  4. import javax.xml.bind.annotation.XmlAccessorType;  
  5. import javax.xml.bind.annotation.XmlElement;  
  6. import javax.xml.bind.annotation.XmlType;  
  7.   
  8. @XmlAccessorType(XmlAccessType.FIELD)  
  9. @XmlType(name = "userType", propOrder = {  
  10.     "id",  
  11.     "name"  
  12. })  
  13. public class UserType {  
  14.   
  15.     protected int id;  
  16.     @XmlElement(required = true)  
  17.     protected String name;  
  18.   
  19.     /** 
  20.      * Gets the value of the id property. 
  21.      *  
  22.      */  
  23.     public int getId() {  
  24.         return id;  
  25.     }  
  26.   
  27.     /** 
  28.      * Sets the value of the id property. 
  29.      *  
  30.      */  
  31.     public void setId(int value) {  
  32.         this.id = value;  
  33.     }  
  34.   
  35.     /** 
  36.      * Gets the value of the name property. 
  37.      *  
  38.      * @return  
  39.      *     possible object is 
  40.      *     {@link String } 
  41.      *      
  42.      */  
  43.     public String getName() {  
  44.         return name;  
  45.     }  
  46.   
  47.     /** 
  48.      * Sets the value of the name property. 
  49.      *  
  50.      * @param value 
  51.      *     allowed object is 
  52.      *     {@link String } 
  53.      *      
  54.      */  
  55.     public void setName(String value) {  
  56.         this.name = value;  
  57.     }  
  58.   
  59. }  

 可以看到,XML格式就是通过一些JAXB的标记被映射成了Java类。我们没写什么代码,已经把数据模型定义清楚了。接下来我们撰写最核心的WebService API。我们的WebService包含两个接口:一个是添加用户接口createUser,另一个是获取用户接口getUser:

Java代码   收藏代码
  1. package org.bluedash.resteasy;  
  2.   
  3. import java.net.URI;  
  4. import java.util.Map;  
  5. import java.util.concurrent.ConcurrentHashMap;  
  6. import java.util.concurrent.atomic.AtomicInteger;  
  7.   
  8. import javax.ws.rs.Consumes;  
  9. import javax.ws.rs.GET;  
  10. import javax.ws.rs.POST;  
  11. import javax.ws.rs.Path;  
  12. import javax.ws.rs.PathParam;  
  13. import javax.ws.rs.Produces;  
  14. import javax.ws.rs.WebApplicationException;  
  15. import javax.ws.rs.core.Response;  
  16.   
  17. @Path ("/users")  
  18. public class UserServlet {  
  19.   
  20.     private Map<Integer, UserType> userStore =   
  21.         new ConcurrentHashMap<Integer, UserType>();  
  22.     private AtomicInteger idGenerator = new AtomicInteger();  
  23.   
  24.     @POST   
  25.     @Consumes("application/xml")  
  26.     public Response createUser(UserType user) {  
  27.         user.setId(idGenerator.incrementAndGet());  
  28.         userStore.put(user.getId(), user);  
  29.         System.out.println(user.getName() + " created: "   
  30.             + user.getId());  
  31.         return Response.created(URI.create("/users/"   
  32.             + user.getId())).build();  
  33.     }  
  34.   
  35.     @GET   
  36.     @Path ("{id}")  
  37.     @Produces("application/xml")  
  38.     public UserType getUser(@PathParam("id"int id) {  
  39.         UserType u = userStore.get(id);  
  40.         if (u == null) {  
  41.             throw new WebApplicationException(  
  42.                 Response.Status.NOT_FOUND);  
  43.         }  
  44.         return u;  
  45.     }  
  46.   
  47. }  

 

用几个简单的JAX-RS标记,便把普通的函数变成了WebService接口。而这些标记将由RESTEasy支持生效。接下来我们将要进行RESTEasy的配置工作。RESTEasy的配置方法有多种多样,可以和Spring等容器集成,也可以独立运行,因为我们用的Servlet的形式使RESTEasy进行工作,这也是最主流的方式,因此在这里使用web容器来加载它,首先定义一个配置类:

Java代码   收藏代码
  1. package org.bluedash.resteasy;  
  2.   
  3. import java.util.HashSet;  
  4. import java.util.Set;  
  5.   
  6. import javax.ws.rs.core.Application;  
  7.   
  8. public class BluedashResteasyApplication extends Application {  
  9.     private Set<Object> singletons = new HashSet<Object>();  
  10.     private Set<Class<?>> classes = new HashSet<Class<?>>();  
  11.   
  12.     public BluedashResteasyApplication() {  
  13. //      classes.add(UserServlet.class);  
  14.         singletons.add(new UserServlet());  
  15.     }  
  16.   
  17.     @Override  
  18.     public Set<Class<?>> getClasses() {  
  19.         return classes;  
  20.     }  
  21.   
  22.     @Override  
  23.     public Set<Object> getSingletons() {  
  24.         return singletons;  
  25.     }  
  26. }  

 

这个类扩展JAX-RS的Application接口,用于封装我们的WebService API方法。我们可以看到JAX-RS支持两种封装方法,一种是classes封装,由容器管理WebServices类的实例化和销毁等动作,一个线程一个实例,开发者不需要关心线程安全问题。但这种方法可能比较浪费资源。如果开发者想自己管理线程安全,共线程共用一个WebServices实例,那么就用singletons封装。我们在这里用的singletons封装,这也就解释了为什么我们在 UserServlet中使用了ConcurrentHashMap和AtomicInteger这些保障线程安全的类。接下来就是在web.xml中启动RESTEasy:

Java代码   收藏代码
  1. <!DOCTYPE web-app PUBLIC  
  2.  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"  
  3.  "http://java.sun.com/dtd/web-app_2_3.dtd" >  
  4.   
  5. <web-app>  
  6.     <display-name>Archetype Created Web Application</display-name>  
  7.   
  8.     <context-param>  
  9.         <param-name>javax.ws.rs.core.Application</param-name>  
  10.         <param-value>org.bluedash.resteasy.  
  11.         BluedashResteasyApplication</param-value>  
  12.     </context-param>  
  13.   
  14.     <listener>  
  15.         <listener-class>org.jboss.resteasy.plugins.server.  
  16.         servlet.ResteasyBootstrap</listener-class>  
  17.     </listener>  
  18.   
  19.     <servlet>  
  20.         <servlet-name>Resteasy</servlet-name>  
  21.         <servlet-class>org.jboss.resteasy.plugins.server.servlet.  
  22.         HttpServletDispatcher</servlet-class>  
  23.     </servlet>  
  24.   
  25.     <servlet-mapping>  
  26.         <servlet-name>Resteasy</servlet-name>  
  27.         <url-pattern>/*</url-pattern>  
  28.     </servlet-mapping>  
  29. </web-app>  

 没错,就是这么简单,这样,我们的WebService就完成了!还差点什么呢?嗯,还差一个Test Case来使用我们的WebService接口,并验证它的正确性,让我们来写一个TestUserAPI

Java代码   收藏代码
  1. package org.bluedash.resteasy.test.integration.test;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.OutputStream;  
  5. import java.net.HttpURLConnection;  
  6. import java.net.URL;  
  7.   
  8. import junit.framework.TestCase;  
  9.   
  10. public class TestUserAPI extends TestCase {  
  11.     public static final String USER_API =   
  12.         "http://127.0.0.1:8080/try-resteasy/users";  
  13.   
  14.     public void testCreateUserAndGetUser() throws IOException {  
  15.         URL url =   
  16.             new URL(USER_API);  
  17.         HttpURLConnection connection =   
  18.             (HttpURLConnection) url.openConnection();  
  19.         connection.setRequestMethod("POST");  
  20.         connection.setRequestProperty("Content-Type""application/xml");  
  21.         connection.setDoOutput(true);  
  22.         connection.setInstanceFollowRedirects(false);  
  23.         connection.setConnectTimeout(1000);  
  24.   
  25.         String userXML = "<user><name>liweinan</name></user>";  
  26.         OutputStream os = connection.getOutputStream();  
  27.         os.write(userXML.getBytes());  
  28.         os.flush();  
  29.   
  30.         assertEquals(HttpURLConnection.HTTP_CREATED, connection  
  31.                 .getResponseCode());          
  32.         connection.disconnect();  
  33.   
  34.     }  
  35. }  

 

一切都已经准备就绪,最后我们要配置一下Maven,让它下载所需的RESTEasy等库,然后配置Maven使用Jetty Web服务器,来把我们的服务和测试跑起来:

Java代码   收藏代码
  1. <project xmlns="http://maven.apache.org/POM/4.0.0"   
  2.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  3.   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0   
  4. http://maven.apache.org/maven-v4_0_0.xsd">  
  5.   <modelVersion>4.0.0</modelVersion>  
  6.   <groupId>org.bluedash</groupId>  
  7.   <artifactId>try-resteasy</artifactId>  
  8.   <packaging>war</packaging>  
  9.   <version>1.0-SNAPSHOT</version>  
  10.   <name>try-resteasy Maven Webapp</name>  
  11.   <url>http://maven.apache.org</url>  
  12.    <repositories>  
  13.         <repository>  
  14.             <id>JBossMavenRepo</id>  
  15.             <name>JBoss Maven2 repo</name>  
  16.             <url>http://repository.jboss.org/maven2</url>  
  17.             <releases>  
  18.                 <enabled>true</enabled>  
  19.             </releases>  
  20.             <snapshots>  
  21.                 <enabled>false</enabled>  
  22.             </snapshots>  
  23.         </repository>  
  24.     </repositories>  
  25.     <dependencies>  
  26.         <dependency>  
  27.             <groupId>junit</groupId>  
  28.             <artifactId>junit</artifactId>  
  29.             <version>4.4</version>  
  30.             <scope>test</scope>  
  31.         </dependency>  
  32.         <dependency>  
  33.             <groupId>org.jboss.resteasy</groupId>  
  34.             <artifactId>resteasy-jaxrs</artifactId>  
  35.             <version>1.2.RC1</version>  
  36.         </dependency>  
  37.         <dependency>  
  38.             <groupId>org.jboss.resteasy</groupId>  
  39.             <artifactId>resteasy-jaxb-provider</artifactId>  
  40.             <version>1.2.RC1</version>  
  41.         </dependency>  
  42.         <dependency>  
  43.             <groupId>javax.servlet</groupId>  
  44.             <artifactId>servlet-api</artifactId>  
  45.             <version>2.4</version>  
  46.         </dependency>  
  47.     </dependencies>  
  48.     <build>  
  49.         <finalName>try-resteasy</finalName>  
  50.         <plugins>  
  51.             <plugin>  
  52.                 <groupId>org.apache.maven.plugins</groupId>  
  53.                 <artifactId>maven-compiler-plugin</artifactId>  
  54.                 <configuration>  
  55.                     <source>1.6</source>  
  56.                     <target>1.6</target>  
  57.                     <encoding>UTF-8</encoding>  
  58.                 </configuration>  
  59.             </plugin>  
  60.             <plugin>  
  61.                 <groupId>org.apache.maven.plugins</groupId>  
  62.                 <artifactId>maven-surefire-plugin</artifactId>  
  63.                 <configuration>  
  64.                     <excludes>  
  65.                         <exclude>**/integration/**</exclude> 
  66.                     </excludes> 
  67.                 </configuration> 
  68.                 <executions> 
  69.                     <execution> 
  70.                         <id>integration-tests</id> 
  71.                         <phase>integration-test</phase> 
  72.                         <goals> 
  73.                             <goal>test</goal> 
  74.                         </goals> 
  75.                         <configuration> 
  76.                             <skip>false</skip> 
  77.                             <excludes> 
  78.                                 <exclude>none</exclude> 
  79.                             </excludes> 
  80.                             <includes> 
  81.                                 <include>**/integration/**</include>  
  82.                             </includes>  
  83.                         </configuration>  
  84.                     </execution>  
  85.                 </executions>  
  86.             </plugin>  
  87.             <plugin>  
  88.                 <groupId>org.mortbay.jetty</groupId>  
  89.                 <artifactId>maven-jetty-plugin</artifactId>  
  90.                 <version>6.1.15</version>  
  91.                 <configuration>  
  92.                     <scanIntervalSeconds>5</scanIntervalSeconds>  
  93.                     <stopKey>foo</stopKey>  
  94.                     <stopPort>9999</stopPort>  
  95.                 </configuration>  
  96.                 <executions>  
  97.                     <execution>  
  98.                         <id>start-jetty</id>  
  99.                         <phase>pre-integration-test</phase>  
  100.                         <goals>  
  101.                             <goal>run</goal>  
  102.                         </goals>  
  103.                         <configuration>  
  104.                             <scanIntervalSeconds>5</scanIntervalSeconds>  
  105.                             <daemon>true</daemon>  
  106.                         </configuration>  
  107.                     </execution>  
  108.                     <execution>  
  109.                         <id>stop-jetty</id>  
  110.                         <phase>post-integration-test</phase>  
  111.                         <goals>  
  112.                             <goal>stop</goal>  
  113.                         </goals>  
  114.                     </execution>  
  115.                 </executions>  
  116.             </plugin>  
  117.         </plugins>  
  118.     </build>  
  119. </project>  

 

有关Maven的配置就不详细展开了。配置完成后我们便可以运行单元测试,看看WebServices是否正确运行。执行下述命令

Java代码   收藏代码
  1. mvn integration-test  

 执行结果如下:

Java代码   收藏代码
  1. -------------------------------------------------------  
  2.  T E S T S  
  3. -------------------------------------------------------  
  4. Running org.bluedash.resteasy.test.integration.test.TestUserAPI  
  5. liweinan created: 1  
  6. Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.372 sec  
  7.   
  8. Results :  
  9.   
  10. Tests run: 1, Failures: 0, Errors: 0, Skipped: 0  

 

可以看到,我们的测试按预期执行成功了。这篇文章中,我简单向大家介绍了RESTEasy的初步使用方法,希望对大家在架构SOA应用时,有所帮助。JAX-RS标准做为J2EE家庭中相对较新的一员,其应用前景是十分广阔的。


你可能感兴趣的:(RESTEasy入门)