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项目



rescue mode操作方法_web.xml

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


 

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


1. <user>  
2. 1</id>  
3.     <name>liweinan</name>  
4. </user>


 

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



rescue mode操作方法_web.xml

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. "user" type="userType"
5. "userType">  
6.     <xsd:sequence>  
7. "id" type="xsd:int"
8. "name" type="xsd:string"
9.     </xsd:sequence>  
10.   </xsd:complexType>  
11. </xsd:schema>
  1.   



 

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



rescue mode操作方法_web.xml

1. xjc user.xsd


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



rescue mode操作方法_web.xml

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类的内容:



rescue mode操作方法_web.xml

1. package
2.   
3. import
4. import
5. import
6. import
7.   
8. @XmlAccessorType(XmlAccessType.FIELD)  
9. @XmlType(name = "userType", propOrder = {  
10. "id",  
11. "name"
12. })  
13. public class
14.   
15. protected int
16. @XmlElement(required = true)  
17. protected
18.   
19. /**
20.      * Gets the value of the id property.
21.      * 
22.      */
23. public int
24. return
25.     }  
26.   
27. /**
28.      * Sets the value of the id property.
29.      * 
30.      */
31. public void setId(int
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
44. return
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
56. this.name = value;  
57.     }  
58.   
59. }



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



rescue mode操作方法_web.xml

1. package
2.   
3. import
4. import
5. import
6. import
7.   
8. import
9. import
10. import
11. import
12. import
13. import
14. import
15. import
16.   
17. @Path("/users")  
18. public class
19.   
20. private
21. new
22. private AtomicInteger idGenerator = new
23.   
24. @POST
25. @Consumes("application/xml")  
26. public
27.         user.setId(idGenerator.incrementAndGet());  
28.         userStore.put(user.getId(), user);  
29. " 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
39.         UserType u = userStore.get(id);  
40. if (u == null) {  
41. throw new
42.                 Response.Status.NOT_FOUND);  
43.         }  
44. return
45.     }  
46.   
47. }



 

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


1. package
2.   
3. import
4. import
5.   
6. import
7.   
8. public class BluedashResteasyApplication extends
9. private Set<Object> singletons = new
10. private Set<Class<?>> classes = new
11.   
12. public
13. //      classes.add(UserServlet.class);
14. new
15.     }  
16.   
17. @Override
18. public
19. return
20.     }  
21.   
22. @Override
23. public
24. return
25.     }  
26. }


 

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



rescue mode操作方法_web.xml

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. class>org.jboss.resteasy.plugins.server.  
16. class>  
17.     </listener>  
18.   
19.     <servlet>  
20.         <servlet-name>Resteasy</servlet-name>  
21. class>org.jboss.resteasy.plugins.server.servlet.  
22. 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


1. package
2.   
3. import
4. import
5. import
6. import
7.   
8. import
9.   
10. public class TestUserAPI extends
11. public static final
12. "http://127.0.0.1:8080/try-resteasy/users";  
13.   
14. public void testCreateUserAndGetUser() throws
15.         URL url =   
16. new
17.         HttpURLConnection connection =   
18.             (HttpURLConnection) url.openConnection();  
19. "POST");  
20. "Content-Type", "application/xml");  
21. true);  
22. false);  
23. 1000);  
24.   
25. "<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服务器,来把我们的服务和测试跑起来:


1. <project xmlns="http://maven.apache.org/POM/4.0.0"
2. "http://www.w3.org/2001/XMLSchema-instance"
3. //maven.apache.org/POM/4.0.0 
4. http://maven.apache.org/maven-v4_0_0.xsd">
5. 4.0.0</modelVersion>  
6.   <groupId>org.bluedash</groupId>  
7. try-resteasy</artifactId>  
8.   <packaging>war</packaging>  
9. 1.0-SNAPSHOT</version>  
10. try-resteasy Maven Webapp</name>  
11. //maven.apache.org</url>
12.    <repositories>  
13.         <repository>  
14.             <id>JBossMavenRepo</id>  
15.             <name>JBoss Maven2 repo</name>  
16. //repository.jboss.org/maven2</url>
17.             <releases>  
18. true</enabled>  
19.             </releases>  
20.             <snapshots>  
21. false</enabled>  
22.             </snapshots>  
23.         </repository>  
24.     </repositories>  
25.     <dependencies>  
26.         <dependency>  
27.             <groupId>junit</groupId>  
28.             <artifactId>junit</artifactId>  
29. 4.4</version>  
30.             <scope>test</scope>  
31.         </dependency>  
32.         <dependency>  
33.             <groupId>org.jboss.resteasy</groupId>  
34.             <artifactId>resteasy-jaxrs</artifactId>  
35. 1.2.RC1</version>  
36.         </dependency>  
37.         <dependency>  
38.             <groupId>org.jboss.resteasy</groupId>  
39.             <artifactId>resteasy-jaxb-provider</artifactId>  
40. 1.2.RC1</version>  
41.         </dependency>  
42.         <dependency>  
43.             <groupId>javax.servlet</groupId>  
44.             <artifactId>servlet-api</artifactId>  
45. 2.4</version>  
46.         </dependency>  
47.     </dependencies>  
48.     <build>  
49. try-resteasy</finalName>  
50.         <plugins>  
51.             <plugin>  
52.                 <groupId>org.apache.maven.plugins</groupId>  
53.                 <artifactId>maven-compiler-plugin</artifactId>  
54.                 <configuration>  
55. 1.6</source>  
56. 1.6</target>  
57. 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>
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. 6.1.15</version>  
91.                 <configuration>  
92. 5</scanIntervalSeconds>  
93.                     <stopKey>foo</stopKey>  
94. 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. 5</scanIntervalSeconds>  
105. 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是否正确运行。执行下述命令


1. mvn integration-test



 执行结果如下:


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
7.   
8. Results :  
9.   
10. Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

 

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