使用dubbox构建web service

开发环境:windows 8.1 +maven 3.3.9+idea 16.1 +jdk 1.7+dubbox 2.8.4+zookeeper3.4.6 + tomcat 8

搭建步骤:

一、环境准备

 

    1、安装jdk1.7、idea 16、tomcat8(我使用的发布dubbox的方式是tomcat,其他方式参考:

       http://dangdangdotcom.github.io/dubbox/rest.html)、zookeeper单节点(集群也可以)

    2、安装本地maven、下载dubbox最新源码包(https://github.com/dangdangdotcom/dubbox)

    3、确认jdk、idea、maven安装成功后,配置idea、jdk、tomcat以及maven的关联;

   再将下载的dubbox-master解压后导入idea中,然后单击项目,右键 使用maven reimport,重新构建dubbox项目

    4、构建项目完成后(需要2h左右),dos命令行进入dubbox-master的目录下,执行mvn clean install -Dmaven.test.skip

       等待mvn编译生成有结构的jar包,jar包的目录是你本地maven库的根目录:

    

二、开始开发(确保以上环境都已经安装和配置成功)

  1、打开idea16、新建一个web app的maven项目:dubbox-restful

   同时修改目录结构:

  

2、将编译好的dubbox包(alibaba)放在maven库的com目录下(或者不改变路径,直接修改pom.xml引入,但是本人不推荐使用)。

  

3、pom.xml中引入相关的依赖包,pom内容如下:

<projectxmlns="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>dubbox-restful</groupId>
  <artifactId>com.webservice</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>com.webservice Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.7</java.version>
    <!--add  maven release-->
    
<maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
    <encoding>UTF-8</encoding>
  </properties>
  <dependencies>
    <!-- dubbox -->
    
<dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>dubbo</artifactId>
      <version>2.8.4</version>
    </dependency>
    <!-- cxf -->
    
<dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-frontend-jaxrs</artifactId>
      <version>3.0.0-milestone1</version>
    </dependency>
    <!--zookeeper-->
    
<dependency>
      <groupId>org.apache.zookeeper</groupId>
      <artifactId>zookeeper</artifactId>
      <version>3.4.6</version>
    </dependency>
    <!-- jetty -->
    
<dependency>
      <groupId>org.mortbay.jetty</groupId>
      <artifactId>jetty-util</artifactId>
      <version>6.1.26</version>
    </dependency>
    <dependency>
      <groupId>org.mortbay.jetty</groupId>
      <artifactId>jetty</artifactId>
      <version>6.1.26</version>
    </dependency>
    <dependency>
      <groupId>org.jboss.resteasy</groupId>
      <artifactId>resteasy-jaxrs</artifactId>
      <version>3.0.7.Final</version>
    </dependency>
    <dependency>
      <groupId>org.jboss.resteasy</groupId>
      <artifactId>resteasy-client</artifactId>
      <version>3.0.7.Final</version>
    </dependency>
    <dependency>
      <groupId>javax.validation</groupId>
      <artifactId>validation-api</artifactId>
      <version>1.0.0.GA</version>
    </dependency>

    <!-- 如果要使用json序列化 -->
    
<dependency>
      <groupId>org.jboss.resteasy</groupId>
      <artifactId>resteasy-jackson-provider</artifactId>
      <version>3.0.7.Final</version>
    </dependency>

    <!-- 如果要使用xml序列化 -->
    
<dependency>
      <groupId>org.jboss.resteasy</groupId>
      <artifactId>resteasy-jaxb-provider</artifactId>
      <version>3.0.7.Final</version>
    </dependency>

    <!-- 如果要使用netty server -->
    
<dependency>
      <groupId>org.jboss.resteasy</groupId>
      <artifactId>resteasy-netty</artifactId>
      <version>3.0.7.Final</version>
    </dependency>
    <dependency>
      <groupId>com.101tec</groupId>
      <artifactId>zkclient</artifactId>
      <version>0.2</version>
    </dependency>
    <!-- zookeeper -->
    
<dependency>
      <groupId>org.apache.zookeeper</groupId>
      <artifactId>zookeeper</artifactId>
      <version>3.3.6</version>
      <exclusions>
        <exclusion>
          <groupId>log4j</groupId>
          <artifactId>log4j</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <!-- log -->
    
<dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.21</version>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.16</version>
    </dependency>
    <!--gson-->
    
<dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.7</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <finalName>com.webservice</finalName>
  </build>
</project>

 

4、编写代码,目录结构如下:

 

文件bean结构中的内容依次如下:

(1)GsonInfo.java 

package enn.bean;
import java.io.Serializable;
/**
 * Document:本类作用---->解析json字符串
 * User: yangjf
 * Date: 2016/7/17  19:59
 */

public class GsonInfoimplementsSerializable{
    private String id;
    private String name;
    public GsonInfo(){}
    public GsonInfo(String id, String name) {
        this.id= id;
        this.name= name;
    }

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id= id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name= name;
    }
    @Override
    publicString toString() {
        return "GsonInfo{"+
                "id='" +id+ '\''+
                ", name='" +name+ '\''+
                '}';
    }
}

(2)MessageInfo.Java

package enn.bean;
import java.io.Serializable;
/**
 * Document:本类作用---->
 * User: yangjf
 * Date: 2016/7/17  20:17
 */

public class MessageInfoimplementsSerializable {
    private GsonInfo message;
    public MessageInfo(){}
    public MessageInfo(GsonInfo message) {
        this.message= message;
    }
    public GsonInfo getMessage() {
        return message;
    }
    public void setMessage(GsonInfo message) {
        this.message= message;
    }
    @Override
    publicString toString() {
        return "MessageInfo{"+
                "message=" +message+
                '}';
    }
}

(3)ResultInfo.java

package enn.bean;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;

/**
 * Document:本类作用---->返回给客户端的结果类
 * User: yangjf
 * Date: 2016/7/17  18:06
 * 注意:必需添加@XmlRootElement注解和序列化,否则GET方法返回值为空
 */

@XmlRootElement
public class ResultInfoimplementsSerializable{
    private String result;//该名称是返回的gson串的一个key
    
privateStringstatus;//该名称是返回的gson串的一个key
    
publicResultInfo(){}
    public ResultInfo(String result, String status) {
        this.result= result;
        this.status= status;
    }
    public String getResult() {
        return result;
    }
    public void setResult(String result) {
        this.result= result;
    }
    public String getStatus() {
        return status;
    }
    public void setStatus(String status) {
        this.status= status;
    }
}

service结构中的类如下:

(1)接口类:IUserService.java

package enn.service.interfaces;
import enn.bean.ResultInfo;
import javax.ws.rs.QueryParam;
/**
 * Document:本类作用---->测试用户访问的接口类
 * User: yangjf
 * Date: 2016/7/17  18:03
 */

public interface IUserService {
    /**获取信息,注解代表请求的参数名称*/
    
publicResultInfo getUserInfo(@QueryParam("id")String id,@QueryParam("name")String name)throwsException;
    /**实现POST请求*/
    //由于Post方法不需要添加@QueryParam,
    // 所以如果添加了@QueryParam会导致空指针异常,message名称可以任意取名,但是要和实现类中一致
    
publicResultInfo getPostUserInfo(String message)throwsException;
}

 

(2)实现类:IUserServiceImpl.java

package enn.service.impl;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import enn.bean.GsonInfo;
import enn.bean.MessageInfo;
import enn.bean.ResultInfo;
import enn.service.interfaces.IUserService;
import javax.ws.rs.*;
/**
 * Document:本类作用---->查询的实现类
 * User: yangjf
 * Date: 2016/7/17  18:11
 */

@Path("/services/user")/**一级访问目录*/
public class IUserServiceImplimplementsIUserService {
    @GET
    @Path("getUser")/**二级访问目录*/
//    @Produces({"application/json;charset=UTF-8"})/**指定返回值类型是json格式*/
    
@Produces({"text/xml;charset=UTF-8"})/**指定返回值类型是xml格式格式*/
    
publicResultInfo getUserInfo(@QueryParam("id") String id,@QueryParam("name") String name)throwsException {
        ResultInfo resultInfo=new ResultInfo(id,name);
        try{
            System.out.println("id:"+id);
            System.out.println("name:"+name);
        }catch(Exception e){
            e.printStackTrace();
            resultInfo=new ResultInfo("123456","cassie");
        }
        return resultInfo;/**如果指定xml格式返回值,那么该名称即是xml的头文件表签名称*/
    
}
    @POST
    @Path("/getPostuser")
    @Produces({"application/json;charset=UTF-8"})
    public ResultInfo getPostUserInfo(String message)throwsException {
        System.out.println("获取到的message:"+message);
        GsonBuilder gb=new GsonBuilder();
        Gson gson=gb.create();
        MessageInfo gsonInfo=gson.fromJson(message,MessageInfo.class);
        ResultInfo resultInfo=new ResultInfo(gsonInfo.getMessage().getId(),gsonInfo.getMessage().getName());
        return resultInfo;
    }
}

 

resource结构中的配置文件:

(1)dubbo-server-restful.xml(注意:spring的配置文件中的空格不能去掉!!)

<?xml version="1.0"encoding="UTF-8"?>
<beansxmlns="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"
>
    <!-- 提供方应用信息,用于计算依赖关系主要用于dubbox内部消费时使用 -->
    
<dubbo:applicationname="hello-user"/>
    <!-- zookeeper注册地址可以是列表,以逗号分割: -->
    
<dubbo:registryaddress="zookeeper://192.168.1.101:2181"/>
    <!--<dubbo:provider protocol="webservice" />-->
    <!-- 用dubbo协议在端口暴露服务端口可以按规则任意指定 -->
    
<dubbo:protocolname="rest"  port="9000"/>
    <!-- 声明需要暴露的服务接口 -->
    
<dubbo:serviceprotocol="rest"interface="enn.service.interfaces.IUserService"ref="userService"/>
    <!-- 和本地bean一样实现服务 -->
    
<beanid="userService"class="enn.service.impl.IUserServiceImpl"/>
</beans>

 

(2)log4j.properties

log4j.rootLogger=INFO,console
#log4j.additivity.org.apache=true
# console

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Threshold
=WARN
log4j.appender.console.ImmediateFlush
=true
log4j.appender.console.Target
=System.err
log4j.appender.console.layout
=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern
=[%-5p] %d %m %x %n

 

test目录结构文件内容

(1)HttpUrlTest.java测试get/post请求的类

package services;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
/**
 * Document:本类作用---->访问web service(get和post方式)
 * User: yangjf
 * Date: 2016/7/17  18:27
 */

public class HttpUrlTest {
    /**测试get方式请求url*/
    
@Test
    public  voidtestGet() {
        String urlString="http://localhost:9000/services/user/getUser?id=12&name=lisi";
        BufferedReader br=null;
        try{
            //创建url请求
            
URL url=newURL(urlString);
            //连接请求协议
            
HttpURLConnection _url=(HttpURLConnection)url.openConnection();
            //设置请求方法
            
_url.setRequestMethod("GET");
            //设置请求开启连接
            
_url.connect();
            //写入请求参数,记得把字节流转换成字符流
            
br=newBufferedReader(newInputStreamReader(_url.getInputStream()));//_url.getInputStream()是URL返回的流
            //实现读入内存的操作
            
String content="";
            StringBuffer ss=new StringBuffer();
            while((content=br.readLine())!=null){
                ss.append(content);
            }
            System.out.println(ss.toString());
        }catch(Exception e){
            throw new RuntimeException(e);
        }finally{
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**测试Post方式请求Url*/
    
@Test
    public voidtestPost()throwsException{
         String APPLICATION_JSON = "application/json";
         String CONTENT_TYPE_TEXT_JSON = "text/json";
         String urlPost="http://localhost:9000/services/user/getPostuser";
        String json="{\"message\":{\"id\":\"001\",\"name\":\"guo\"}}";
        // 将JSON进行UTF-8编码,以便传输中文
        
String encoderJson = URLEncoder.encode(json, HTTP.UTF_8);
//        String encoderJson = json;
        
DefaultHttpClient httpClient =newDefaultHttpClient();
        HttpPost httpPost = new HttpPost(urlPost);
        httpPost.addHeader(HTTP.CONTENT_TYPE, APPLICATION_JSON);
        StringEntity se = new StringEntity(encoderJson);
        se.setContentType(CONTENT_TYPE_TEXT_JSON);//请求内容格式
        
se.setContentEncoding(newBasicHeader(HTTP.CONTENT_TYPE, APPLICATION_JSON));
        httpPost.setEntity(se);
        HttpResponse response = httpClient.execute(httpPost);
        String result= EntityUtils.toString(response.getEntity());
        System.out.println("返回结果:"+result);
    }
}

(2)TestGson.java生成json的类

package services;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import enn.bean.GsonInfo;
import enn.bean.MessageInfo;
/**
 * Document:本类作用---->测试生成json串
 * User: yangjf
 * Date: 2016/7/17  20:04
 */

public class TestGson {
    public static void main(String[] args) {
        GsonInfo gin=new GsonInfo("001","guo");
        MessageInfo ms=new MessageInfo(gin);
        GsonBuilder gb=new GsonBuilder();
        Gson gson=gb.create();
        System.out.println(gson.toJson(ms));//{"message":{"id":"001","name":"guo"}}
    
}
}

(3)httpTest :httpclient方式调用webservice(get方式)

package services;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import java.io.IOException;
import java.io.InputStream;
/**
 * httpclient方式调用webservice(get方式)
 */

public class httpTest {
    public static void main(String[] args)throwsClientProtocolException, IOException {
        //访问的url
        
HttpGet get = new HttpGet("http://localhost:9000/services/user/getUser?id=12&name=lisi");
        HttpClient httpclient = new DefaultHttpClient();
        get.addHeader("ACCEPT","text/xml");// 如果指定返回值是json:get.addHeader("ACCEPT", "application/json");
        
HttpResponse response = httpclient.execute(get);
        //获取返回值
        
InputStream ins = response.getEntity().getContent();
        byte[] b = new byte[1024];
        StringBuilder sb = new StringBuilder();
        while (ins.read(b) != -1) {
            sb.append(new String(b,"UTF-8"));
        }
        System.out.println("返回值内容:"+sb.toString());
    }
}

 

web.xml文件配置

<!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>contextConfigLocation</param-name>
    <param-value>classpath:demo/dubbo-server-restful.xml</param-value>
  </context-param>
  <!--spring的配置-->
  
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <!--dubbo 服务根路径-->
  
<servlet>
    <servlet-name>dubbo</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>dubbo</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

 

三、Tomcat运行web service,实现访问

1、添加项目到tomcat

 

 

 

 

 启动zookeeper------>再启动tomcat

 

如果发现以下内容,说明启动成功,可以访问了。

 

 

四、测试访问web service(浏览器和java代码访问)

1、火狐rest client访问

  (1)get方式

 

  (2)post方式

 

 

2、java 代码实现请求(get和post)

(1)get方式

执行HttpUrlTest.java中的 public  voidtestGet() 方法

(2)Post方式

   执行HttpUrlTest.java中的public voidtestPost()方法

 

可能遇到的问题:

1、Get方式url访问报错:

浏览器输入:http://localhost:9000/services/user/getUser?id=12&name=lisi

错误:Could not find MessageBodyWriter for response object of type:

      enn.bean.ResultInfo of media type: text/xml;charset=UTF-8

 

解决:在返回对象类中添加注解@XmlRootElement即可解决

 

2、POST方式请求报空指针异常

注意:需要在火狐中添加restClient,然后

Post请求需要添加请求头:

Accept       =    application/json

Content-Type =    application/json;charset=UTF-8

 

 

Body中添加:{"message":{"id":"001","name":"guo"}}

 

 

另一种问题解决:

 

以上测试已经通过,可以按自己的需求进行更改;如有疑问,请留言。

 

 

 

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐