天天看点

[Webservice基础]-- java使用idea、dubbox、cxf构建web service

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

mvn clean install -Dmaven.test.skip;

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

[Webservice基础]-- java使用idea、dubbox、cxf构建web service

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

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

   同时修改目录结构:

[Webservice基础]-- java使用idea、dubbox、cxf构建web service

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

[Webservice基础]-- java使用idea、dubbox、cxf构建web service

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、编写代码,目录结构如下:

[Webservice基础]-- java使用idea、dubbox、cxf构建web service

文件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

[Webservice基础]-- java使用idea、dubbox、cxf构建web service
[Webservice基础]-- java使用idea、dubbox、cxf构建web service
[Webservice基础]-- java使用idea、dubbox、cxf构建web service
[Webservice基础]-- java使用idea、dubbox、cxf构建web service

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

[Webservice基础]-- java使用idea、dubbox、cxf构建web service

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

[Webservice基础]-- java使用idea、dubbox、cxf构建web service

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

1、火狐rest client访问

  (1)get方式

[Webservice基础]-- java使用idea、dubbox、cxf构建web service

  (2)post方式

[Webservice基础]-- java使用idea、dubbox、cxf构建web service

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

[Webservice基础]-- java使用idea、dubbox、cxf构建web service
[Webservice基础]-- java使用idea、dubbox、cxf构建web service

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

[Webservice基础]-- java使用idea、dubbox、cxf构建web service

另一种问题解决:

[Webservice基础]-- java使用idea、dubbox、cxf构建web service

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