天天看點

[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

以上測試已經通過,可以按自己的需求進行更改;如有疑問,請留言。