zoukankan      html  css  js  c++  java
  • 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做一个项目玩玩看。

    首先创造一个maven的web项目:

    Java代码:

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

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

    <user>
    	<id>1</id>
    	<name>liweinan</name>
    </user>
    

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

    <?xml version="1.0" encoding="utf-8"?>
    <xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
    version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xsd:element name="user" type="userType" />
      <xsd:complexType name="userType">
        <xsd:sequence>
          <xsd:element name="id" type="xsd:int" />
          <xsd:element name="name" type="xsd:string" />
        </xsd:sequence>
      </xsd:complexType>
    </xsd:schema>
    

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

    xjc user.xsd
    

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

    Li-Weinans-MacBook-Pro:Desktop liweinan$ xjc user.xsd 
    parsing a schema...
    compiling a schema...
    generated/ObjectFactory.java
    generated/UserType.java
    

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

    package org.bluedash.resteasy;
    
    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlType;
    
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "userType", propOrder = {
        "id",
        "name"
    })
    public class UserType {
    
        protected int id;
        @XmlElement(required = true)
        protected String name;
    
        /**
         * Gets the value of the id property.
         * 
         */
        public int getId() {
            return id;
        }
    
        /**
         * Sets the value of the id property.
         * 
         */
        public void setId(int value) {
            this.id = value;
        }
    
        /**
         * Gets the value of the name property.
         * 
         * @return
         *     possible object is
         *     {@link String }
         *     
         */
        public String getName() {
            return name;
        }
    
        /**
         * Sets the value of the name property.
         * 
         * @param value
         *     allowed object is
         *     {@link String }
         *     
         */
        public void setName(String value) {
            this.name = value;
        }
    
    }
    

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

    package org.bluedash.resteasy;
    
    import java.net.URI;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.atomic.AtomicInteger;
    
    import javax.ws.rs.Consumes;
    import javax.ws.rs.GET;
    import javax.ws.rs.POST;
    import javax.ws.rs.Path;
    import javax.ws.rs.PathParam;
    import javax.ws.rs.Produces;
    import javax.ws.rs.WebApplicationException;
    import javax.ws.rs.core.Response;
    
    @Path("/users")
    public class UserServlet {
    
    	private Map<Integer, UserType> userStore = 
    		new ConcurrentHashMap<Integer, UserType>();
    	private AtomicInteger idGenerator = new AtomicInteger();
    
    	@POST
    	@Consumes("application/xml")
    	public Response createUser(UserType user) {
    		user.setId(idGenerator.incrementAndGet());
    		userStore.put(user.getId(), user);
    		System.out.println(user.getName() + " created: " 
    			+ user.getId());
    		return Response.created(URI.create("/users/" 
    			+ user.getId())).build();
    	}
    
    	@GET
    	@Path("{id}")
    	@Produces("application/xml")
    	public UserType getUser(@PathParam("id") int id) {
    		UserType u = userStore.get(id);
    		if (u == null) {
    			throw new WebApplicationException(
    				Response.Status.NOT_FOUND);
    		}
    		return u;
    	}
    
    }
    

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

    package org.bluedash.resteasy;
    
    import java.util.HashSet;
    import java.util.Set;
    
    import javax.ws.rs.core.Application;
    
    public class BluedashResteasyApplication extends Application {
    	private Set<Object> singletons = new HashSet<Object>();
    	private Set<Class<?>> classes = new HashSet<Class<?>>();
    
    	public BluedashResteasyApplication() {
    //		classes.add(UserServlet.class);
    		singletons.add(new UserServlet());
    	}
    
    	@Override
    	public Set<Class<?>> getClasses() {
    		return classes;
    	}
    
    	@Override
    	public Set<Object> getSingletons() {
    		return singletons;
    	}
    }
    

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

    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
    	<display-name>Archetype Created Web Application</display-name>
    
    	<context-param>
    		<param-name>javax.ws.rs.core.Application</param-name>
    		<param-value>org.bluedash.resteasy.
    		BluedashResteasyApplication</param-value>
    	</context-param>
    
    	<listener>
    		<listener-class>org.jboss.resteasy.plugins.server.
    		servlet.ResteasyBootstrap</listener-class>
    	</listener>
    
    	<servlet>
    		<servlet-name>Resteasy</servlet-name>
    		<servlet-class>org.jboss.resteasy.plugins.server.servlet.
    		HttpServletDispatcher</servlet-class>
    	</servlet>
    
    	<servlet-mapping>
    		<servlet-name>Resteasy</servlet-name>
    		<url-pattern>/*</url-pattern>
    	</servlet-mapping>
    </web-app>
    

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

    package org.bluedash.resteasy.test.integration.test;
    
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    import junit.framework.TestCase;
    
    public class TestUserAPI extends TestCase {
    	public static final String USER_API = 
    		"http://127.0.0.1:8080/try-resteasy/users";
    
    	public void testCreateUserAndGetUser() throws IOException {
    		URL url = 
    			new URL(USER_API);
    		HttpURLConnection connection = 
    			(HttpURLConnection) url.openConnection();
    		connection.setRequestMethod("POST");
    		connection.setRequestProperty("Content-Type", "application/xml");
    		connection.setDoOutput(true);
    		connection.setInstanceFollowRedirects(false);
    		connection.setConnectTimeout(1000);
    
    		String userXML = "<user><name>liweinan</name></user>";
    		OutputStream os = connection.getOutputStream();
    		os.write(userXML.getBytes());
    		os.flush();
    
    		assertEquals(HttpURLConnection.HTTP_CREATED, connection
    				.getResponseCode());		
    		connection.disconnect();
    
    	}
    }
    

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

    <project xmlns="http://maven.apache.org/POM/4.0.0" 
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
    http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>org.bluedash</groupId>
      <artifactId>try-resteasy</artifactId>
      <packaging>war</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>try-resteasy Maven Webapp</name>
      <url>http://maven.apache.org</url>
       <repositories>
            <repository>
                <id>JBossMavenRepo</id>
                <name>JBoss Maven2 repo</name>
                <url>http://repository.jboss.org/maven2</url>
                <releases>
                    <enabled>true</enabled>
                </releases>
                <snapshots>
                    <enabled>false</enabled>
                </snapshots>
            </repository>
        </repositories>
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.4</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.jboss.resteasy</groupId>
                <artifactId>resteasy-jaxrs</artifactId>
                <version>1.2.RC1</version>
            </dependency>
            <dependency>
                <groupId>org.jboss.resteasy</groupId>
                <artifactId>resteasy-jaxb-provider</artifactId>
                <version>1.2.RC1</version>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>2.4</version>
            </dependency>
        </dependencies>
        <build>
            <finalName>try-resteasy</finalName>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.6</source>
                        <target>1.6</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <configuration>
                        <excludes>
                            <exclude>**/integration/**</exclude>
                        </excludes>
                    </configuration>
                    <executions>
                        <execution>
                            <id>integration-tests</id>
                            <phase>integration-test</phase>
                            <goals>
                                <goal>test</goal>
                            </goals>
                            <configuration>
                                <skip>false</skip>
                                <excludes>
                                    <exclude>none</exclude>
                                </excludes>
                                <includes>
                                    <include>**/integration/**</include>
                                </includes>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.mortbay.jetty</groupId>
                    <artifactId>maven-jetty-plugin</artifactId>
                    <version>6.1.15</version>
                    <configuration>
                        <scanIntervalSeconds>5</scanIntervalSeconds>
                        <stopKey>foo</stopKey>
                        <stopPort>9999</stopPort>
                    </configuration>
                    <executions>
                        <execution>
                            <id>start-jetty</id>
                            <phase>pre-integration-test</phase>
                            <goals>
                                <goal>run</goal>
                            </goals>
                            <configuration>
                                <scanIntervalSeconds>5</scanIntervalSeconds>
                                <daemon>true</daemon>
                            </configuration>
                        </execution>
                        <execution>
                            <id>stop-jetty</id>
                            <phase>post-integration-test</phase>
                            <goals>
                                <goal>stop</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </project>
    

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

    mvn integration-test
    

    执行结果如下:

    -------------------------------------------------------
     T E S T S
    -------------------------------------------------------
    Running org.bluedash.resteasy.test.integration.test.TestUserAPI
    liweinan created: 1
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.372 sec
    
    Results :
    
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
    

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

  • 相关阅读:
    awk去重以某列重复的行
    awk 统计文件中按照某列统计某列的和(sum)
    使用jdk压缩war包
    histoty显示时间戳
    awk统计文件中某关键词出现次数
    Jbox帮助文档,默认的属性含义
    net之session漫谈及分布式session解决方案
    StackExchange.Redis 基本使用 (一) (转)
    Sql Server 表创建以及Ef浅谈
    数据验证(自定义特性)
  • 原文地址:https://www.cnblogs.com/xiohao/p/4773631.html
Copyright © 2011-2022 走看看