Dubbox的rest风格调用例子

Dubbo是一个被国内很多互联网公司广泛使用的开源分布式服务框架,即使从国际视野来看应该也是一个非常全面的SOA基础框架。 作为一个重要的技术研究课题,在当当网我们根据自身的需求,为Dubbo实现了一些新的功能,并将其命名为Dubbox(即Dubbo eXtensions)

本例中使用jetty server,若本例中其中使用某些alibaba的jar包无法在网上下载,可直接下载源码 git clone https://github.com/dangdangdotcom/dubbox 将其安装到本地库中。

1、编写pom.xml,内容较多,其中包括jetty等

<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.hode</groupId>
	<artifactId>dubbox</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<spring.version>4.0.2.RELEASE</spring.version>
		<log4j.version>1.2.17</log4j.version>
	</properties>
	
	<dependencies>
		
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>${log4j.version}</version>
		</dependency>
		
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.6.1</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.6.1</version>
		</dependency>
		
		<dependency>
            <groupId>javax.ws.rs</groupId>
            <artifactId>javax.ws.rs-api</artifactId>
            <version>2.0.1</version>
        </dependency>
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-asl</artifactId>
            <version>1.9.12</version>
        </dependency>
		
		<!--  dubbo start -->
		<dependency> 
		    <groupId>com.alibaba</groupId> 
		    <artifactId>dubbo</artifactId> 
		    <version>2.8.4</version> 
		    <exclusions> 
		        <exclusion> 
		            <groupId>org.springframework</groupId> 
		            <artifactId>spring</artifactId> 
		        </exclusion> 
		    </exclusions> 
		</dependency>
		
		<!--  dubbo end  -->
		
		<!-- zookeeper start --> 
		<dependency>
			<groupId>org.apache.zookeeper</groupId>
			<artifactId>zookeeper</artifactId>
			<version>3.5.0-alpha</version>
		</dependency>
		
		<dependency>
		    <groupId>com.101tec</groupId>
		    <artifactId>zkclient</artifactId>
		    <version>0.8</version>
		</dependency>
		<!-- zookeeper end -->
		
		<dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-jaxrs</artifactId>
            <version>3.0.10.Final</version>
        </dependency>

        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-client</artifactId>
            <version>3.0.10.Final</version>
        </dependency>

        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-netty</artifactId>
            <version>3.0.10.Final</version>
        </dependency>

        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-jdk-http</artifactId>
            <version>3.0.10.Final</version>
        </dependency>

        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-jackson-provider</artifactId>
            <version>3.0.10.Final</version>
        </dependency>

        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-jaxb-provider</artifactId>
            <version>3.0.10.Final</version>
        </dependency>
        
        <dependency>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>jetty</artifactId>
            <version>6.1.26</version>
            <exclusions>
                <exclusion>
                    <groupId>org.mortbay.jetty</groupId>
                    <artifactId>servlet-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.0.0.GA</version>
        </dependency>
		
		<!-- jetty begin -->
		<dependency>
			<groupId>org.eclipse.jetty</groupId>
			<artifactId>jetty-server</artifactId>
			<version>8.0.0.M3</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.eclipse.jetty</groupId>
			<artifactId>jetty-webapp</artifactId>
			<version>8.0.0.M3</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.eclipse.jetty</groupId>
			<artifactId>jetty-servlet</artifactId>
			<version>8.0.0.M3</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.eclipse.jetty</groupId>
			<artifactId>jetty-io</artifactId>
			<version>8.0.0.M3</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.eclipse.jetty</groupId>
			<artifactId>jetty-util</artifactId>
			<version>8.0.0.M3</version>
			<scope>provided</scope>
		</dependency>
		
		<dependency>
			<groupId>org.mortbay.jetty</groupId>
			<artifactId>jsp-2.1-glassfish</artifactId>
			<version>2.1.v20100127</version>
			<scope>provided</scope>
		</dependency>
		<!-- jetty end -->
		
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

2、在目录webapp/WEB-INF中创建文件 web.xml,内容如下

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
	xmlns="http://java.sun.mrm/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.mrm/xml/ns/j2ee http://java.sun.mrm/xml/ns/j2ee/web-app_2_4.xsd">

	<display-name>dubbox restful</display-name>
    
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:applicationContext-provider.xml</param-value>
    </context-param>

    <!--this listener must be defined before the spring listener-->
    <listener>
        <listener-class>com.alibaba.dubbo.remoting.http.servlet.BootstrapListener</listener-class>
    </listener>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>com.alibaba.dubbo.remoting.http.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

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

</web-app>


3、编写服务接口DemoService,服务类DemoServiceImpl,一个VO类User以及JettyServer

package com.hode.dubbo.provider;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.hode.model.User;

@Path("demo")
@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
@Produces({MediaType.APPLICATION_JSON + ";"+MediaType.CHARSET_PARAMETER+"=UTF-8",MediaType.TEXT_XML+";"+MediaType.CHARSET_PARAMETER+"=UTF-8"})
public interface DemoService {

	@POST
    @Path("sayHello")
	public String sayHello(String name);
	
	@POST
    @Path("checkUser")
	public User checkUser(User u);
	
}

package com.hode.dubbo.provider.impl;

import org.apache.log4j.Logger;

import com.hode.dubbo.provider.DemoService;
import com.hode.model.User;

public class DemoServiceImpl implements DemoService {

	private Logger log = Logger.getLogger(getClass());
	
	@Override
	public String sayHello(String name) {
		log.info("name = "+name);
		return "name is "+name;
	}

	@Override
	public User checkUser(User u) {
		log.info(u);
		u = new User();
		u.setName("hode");
		u.setAge(22);
		u.setHeight(168.0);
		return u;
	}

}

package com.hode.model;

import java.io.Serializable;
import java.util.Date;

public class User implements Serializable{

	private static final long serialVersionUID = -4144338689776613101L;

	private String name;
	
	private int age;
	
	private double height;
	
	private Date birthday;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public double getHeight() {
		return height;
	}

	public void setHeight(double height) {
		this.height = height;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + ", height=" + height
				+ ", birthday=" + birthday + "]";
	}
	
}

package com.hode;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;


public class JettyServer {

	public static void main(String[] args) throws Exception{
		Server server = new Server(80);
		WebAppContext context = new WebAppContext();  
        context.setContextPath("/");  
        context.setWar("src/main/webapp");  
        server.setHandler(context);  
        server.start();  
        server.join();
	}

}

4、编写spring配置文件applicationContext-provider.xml及log4j.properties, 其中使用了部分dubbox demo项目中的extension包内的类,可拷贝进去 代码如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
	
	<!-- Provider信息 -->
	<dubbo:application name="dubbox-hode-provider" owner="programer" organization="dubbox" />
	
	<!-- 使用zookeeper注册中心暴露服务地址 -->
	<dubbo:registry address="zookeeper://192.167.48.128:2181" />
	
	<dubbo:annotation package="com.hode.dubbo.provider" />
	
	<!-- 定义rest协议,本例演示使用jetty -->
	<dubbo:protocol name="rest" port="8888" threads="500" contextpath="services" server="jetty" accepts="500"
                    extension="com.alibaba.dubbo.demo.extension.TraceInterceptor,
                    com.alibaba.dubbo.demo.extension.TraceFilter,
                    com.alibaba.dubbo.demo.extension.ClientTraceFilter,
                    com.alibaba.dubbo.demo.extension.DynamicTraceBinding,
                    com.alibaba.dubbo.demo.extension.CustomExceptionMapper,
                    com.alibaba.dubbo.rpc.protocol.rest.support.LoggingFilter"/>
                    
	<!-- 声明需要暴露的服务接口 -->
	<dubbo:service interface="com.hode.dubbo.provider.DemoService" ref="demoService"  protocol="rest"/>
	
	<!-- 具体的实现bean -->
	<bean id="demoService" class="com.hode.dubbo.provider.impl.DemoServiceImpl" />
	
	
</beans>
log4j.rootLogger=INFO,Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%-4r %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %-5p %c %x - %m%n

log4j.logger.com.hode = DEBUG
log4j.logger.com.alibaba = DEBUG

5、最后编写一个测试类,使用resttemplate完成测试,测试代码如下

package dubbox;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.client.RestTemplate;

import com.hode.model.User;

public class RestClientTest {

	static RestTemplate rt = new RestTemplate();
	
	public static void main(String[] args) {
		sayHello();
		checkUser();
	}
	
	public static void checkUser(){
		String url = "http://localhost:8888/services/demo/checkUser.json";
		User u = new User();
		u.setName("test-hode");
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		HttpEntity request = new HttpEntity(u, headers);
		User result = rt.postForObject(url, request, User.class);
		
		System.out.println(result);
	}
	
	public static void sayHello(){
		String url = "http://localhost:8888/services/demo/sayHello.json";
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		HttpEntity request = new HttpEntity("hode", headers);
		String result = rt.postForObject(url, request, String.class);
		
		System.out.println(result);
	}

}

6、启动并测试

先运行JettyServer,再运行RestClientTest,查看结果

截取部分日志如下

Request filter invoked
10965 2016-04-08 18:25:40,284 [156710276@qtp-1193471756-492] INFO  com.alibaba.dubbo.rpc.protocol.rest.support.LoggingFilter  -  [DUBBO] The HTTP headers are: 
Accept: application/json, text/plain, application/json, application/*+json, */*
Accept-Charset: big5, big5-hkscs, cesu-8, euc-jp, euc-kr, gb18030, gb2312, gbk, ibm-thai, ibm00858, ibm01140, ibm01141, ibm01142, ibm01143, ibm01144, ibm01145, ibm01146, ibm01147, ibm01148, ibm01149, ibm037, ibm1026, ibm1047, ibm273, ibm277, ibm278, ibm280, ibm284, ibm285, ibm290, ibm297, ibm420, ibm424, ibm437, ibm500, ibm775, ibm850, ibm852, ibm855, ibm857, ibm860, ibm861, ibm862, ibm863, ibm864, ibm865, ibm866, ibm868, ibm869, ibm870, ibm871, ibm918, iso-2022-cn, iso-2022-jp, iso-2022-jp-2, iso-2022-kr, iso-8859-1, iso-8859-13, iso-8859-15, iso-8859-2, iso-8859-3, iso-8859-4, iso-8859-5, iso-8859-6, iso-8859-7, iso-8859-8, iso-8859-9, jis_x0201, jis_x0212-1990, koi8-r, koi8-u, shift_jis, tis-620, us-ascii, utf-16, utf-16be, utf-16le, utf-32, utf-32be, utf-32le, utf-8, windows-1250, windows-1251, windows-1252, windows-1253, windows-1254, windows-1255, windows-1256, windows-1257, windows-1258, windows-31j, x-big5-hkscs-2001, x-big5-solaris, x-euc-jp-linux, x-euc-tw, x-eucjp-open, x-ibm1006, x-ibm1025, x-ibm1046, x-ibm1097, x-ibm1098, x-ibm1112, x-ibm1122, x-ibm1123, x-ibm1124, x-ibm1166, x-ibm1364, x-ibm1381, x-ibm1383, x-ibm300, x-ibm33722, x-ibm737, x-ibm833, x-ibm834, x-ibm856, x-ibm874, x-ibm875, x-ibm921, x-ibm922, x-ibm930, x-ibm933, x-ibm935, x-ibm937, x-ibm939, x-ibm942, x-ibm942c, x-ibm943, x-ibm943c, x-ibm948, x-ibm949, x-ibm949c, x-ibm950, x-ibm964, x-ibm970, x-iscii91, x-iso-2022-cn-cns, x-iso-2022-cn-gb, x-iso-8859-11, x-jis0208, x-jisautodetect, x-johab, x-macarabic, x-maccentraleurope, x-maccroatian, x-maccyrillic, x-macdingbat, x-macgreek, x-machebrew, x-maciceland, x-macroman, x-macromania, x-macsymbol, x-macthai, x-macturkish, x-macukraine, x-ms932_0213, x-ms950-hkscs, x-ms950-hkscs-xp, x-mswin-936, x-pck, x-sjis_0213, x-utf-16le-bom, x-utf-32be-bom, x-utf-32le-bom, x-windows-50220, x-windows-50221, x-windows-874, x-windows-949, x-windows-950, x-windows-iso2022jp
Connection: keep-alive
Content-Length: 4
Content-Type: application/json
Host: localhost:8888
User-Agent: Java/1.8.0_66
, dubbo version: 2.8.4, current host: 127.0.0.1
Reader interceptor invoked
Dynamic reader interceptor invoked
10966 2016-04-08 18:25:40,285 [156710276@qtp-1193471756-492] INFO  com.alibaba.dubbo.rpc.protocol.rest.support.LoggingFilter  -  [DUBBO] The contents of request body is: 
hode
, dubbo version: 2.8.4, current host: 127.0.0.1
10966 2016-04-08 18:25:40,285 [156710276@qtp-1193471756-492] INFO  com.hode.dubbo.provider.impl.DemoServiceImpl  - name = hode
10967 2016-04-08 18:25:40,286 [156710276@qtp-1193471756-492] INFO  com.alibaba.dubbo.rpc.protocol.rest.support.LoggingFilter  -  [DUBBO] The HTTP headers are: 
Content-Type: application/json;charset=UTF-8
, dubbo version: 2.8.4, current host: 127.0.0.1
Response filter invoked
Writer interceptor invoked
Dynamic writer interceptor invoked
10967 2016-04-08 18:25:40,286 [156710276@qtp-1193471756-492] INFO  com.alibaba.dubbo.rpc.protocol.rest.support.LoggingFilter  -  [DUBBO] The contents of response body is: 
name is hode
, dubbo version: 2.8.4, current host: 127.0.0.1
Request filter invoked
11066 2016-04-08 18:25:40,385 [156710276@qtp-1193471756-492] INFO  com.alibaba.dubbo.rpc.protocol.rest.support.LoggingFilter  -  [DUBBO] The HTTP headers are: 
Accept: application/json, application/json, application/*+json
Connection: keep-alive
Content-Length: 57
Content-Type: application/json
Host: localhost:8888
User-Agent: Java/1.8.0_66
, dubbo version: 2.8.4, current host: 127.0.0.1
Reader interceptor invoked
Dynamic reader interceptor invoked
11069 2016-04-08 18:25:40,388 [156710276@qtp-1193471756-492] INFO  com.alibaba.dubbo.rpc.protocol.rest.support.LoggingFilter  -  [DUBBO] The contents of request body is: 
{"name":"test-hode","age":0,"height":0.0,"birthday":null}
, dubbo version: 2.8.4, current host: 127.0.0.1
11070 2016-04-08 18:25:40,389 [156710276@qtp-1193471756-492] INFO  com.hode.dubbo.provider.impl.DemoServiceImpl  - User [name=test-hode, age=0, height=0.0, birthday=null]
11070 2016-04-08 18:25:40,389 [156710276@qtp-1193471756-492] INFO  com.alibaba.dubbo.rpc.protocol.rest.support.LoggingFilter  -  [DUBBO] The HTTP headers are: 
Content-Type: application/json;charset=UTF-8
, dubbo version: 2.8.4, current host: 127.0.0.1
Response filter invoked
Writer interceptor invoked
Dynamic writer interceptor invoked
11072 2016-04-08 18:25:40,391 [156710276@qtp-1193471756-492] INFO  com.alibaba.dubbo.rpc.protocol.rest.support.LoggingFilter  -  [DUBBO] The contents of response body is: 
{"name":"hode","age":22,"height":168.0,"birthday":null}
, dubbo version: 2.8.4, current host: 127.0.0.1

Demo代码下载

结束。


赞赏(Donation)
微信(Wechat Pay)

donation-wechatpay