使用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庫的根目錄:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5yM1MjN1cTMyYmY5gjY1MjNzYzXxITMxQTMzAzLcFTMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
二、開始開發(確定以上環境都已經安裝和配置成功)
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"}}
另一種問題解決:
以上測試已經通過,可以按自己的需求進行更改;如有疑問,請留言。