轉載:http://www.cnblogs.com/windwithlife/archive/2013/03/03/2942157.htmlphp
一,選擇一個合適的,Web開發環境:html
我選擇的是Eclipse for J2EE,固然你們能夠選擇MyEclipse我只是嫌最新版的MyEclipse Crack太煩,因此沒用它。當年我也是最喜歡它的喲。若是你手頭只有Eclipse for Java不要緊,安裝一個WTP就能夠了。java
a.首先建立一個Dynamic Web Project :linux
在建立的第一頁,Project Name 我用的是"MyServices"中要在Target Runtime中選擇一個容器服務器,我這裏測試環境下,選擇的是Tomcat ,若是沒有,能夠在右邊點擊「New Runtime"進行新增Tomcat 運行環境。web
在Project建立的最後一頁最好選中建立一個web.xml免得你去建立,缺省狀況下,這個web.xml只配置了歡迎頁面。如index.php等。spring
b.測試一下,是否這個環境能夠發佈Build後的代碼及網頁到Tomcat測試環境中運行:apache
在左邊的"Web Content"目錄下的」WEB-INF"子目錄,建立一個index.jsp文件進行測試。建立完成後,從新build項目,而後在右下方的Server Tab裏會自動列出你剛纔選擇的Tomcat發佈環境。你點擊這個Tomcat Serverjson
個人環境是Tomcat Server 7.0 而後右鍵菜單中選擇「Publish" 你會看到 服務器,及服務器下面你的項目右邊會由」Republish"變成「Synchronized" ,說明工程編譯結果都已成功發佈到Tomcat Server測試環境下了。瀏覽器
點擊Tomcat Server 7.0 選擇」Start" 服務啓動,你就能夠在你的網頁裏輸入「http://localhost:8080/MyServices/index.jsp"你就能夠看到你的網頁內容了。tomcat
由於這個網站插圖不方便,有時間再插一些圖示吧。
二,關於cxf 框架的運行時序的我的思考過程:
0.Tomcat啓動時,加載web.xml,根據web.xml的配置,把CXF 的Servlet 放到Tomcat的偵聽端口的映射中,同時也把Spring的Bean加載器也加載到Tomcat的進程空間中,Spring根據初始化的配置文件(好比application-context.xml),加載Bean對象。在加載過程當中,會根據配置文件中的xml中的xmlns進行分析(好比,...xmlns:jaxrs ="http://cxf.apache.com", 先到
spring的handlers配置文件中,根據「http://cxf.apache.com"字符串找到對映的handler組件,用這個組件加載全部配置文件中,以jawrs爲xml命名空間的配置部分,好比,<jaxrs:server id="services" address="/"> <jaxrs:serviceBeans> <bean class="com.services.rest.HelloWorld" /> </jaxrs:serviceBeans> <jaxrs:providers> 可參考:http://blog.csdn.net/javabenface/article/details/7441923)調用對應的加載器進行解釋加載,這裏調用cxf的加載器進行加載。cxf加載器會根據 beans.xml中對應的項加載最終實現的class文件,這些class在對應的java源文件編譯過程當中,根據java文件中的annomation標記符進行處理,使得這些class加載時造成正確的path 與對象的映射。
1.客戶端發出請求,經過XML/HTTP把請求及參數對象轉爲XML通過HTTP傳到Servlet容器中。
2.CXF會根據Path與對象的映射找到正確的對象,若是是Restful Web Service還會再根據映射找到Path中對應的執行方法。
三,建立一個基於CXF及Spring的SOAP Web Service:
1.建立Web Service 相關的類:
由於這種類型Web Service是SOA(面象服務架構)的,因此是提供一個遠程的RPC接口。因此首先要有一個接口,固然,在服務端要提供真正的服務,因此要有一個這個接口在服務端的實現。下面分別實現:
IHelloWorld.java:
package com.services.soap;
import javax.jws.WebParam;
import javax.jws.WebService;
@WebService
public interface IHelloWorld {
public String speakoutUserInfo(@WebParam(name = "param") ParamDTO obj);
}
HelloWorld.java:
package com.services.soap;
import javax.jws.WebService;
/** * * 使用@WebService指向Interface定義類便可. */
@WebService(endpointInterface = "com.services.soap.IHelloWorld")
public class HelloWorld implements IHelloWorld{
@Override
public String speakoutUserInfo(ParamDTO obj) {
// TODO Auto-generated method stub
return "hello";
}
}
上述的服務實現用到一個對象,這個對象能夠作爲參數遠程進行傳遞,通常叫作DTO(數據傳輸對象)。固然你能夠不用對象,用普通的數據類型這個實例一次性都表現一下。
ParamDTO.java:
package com.services.soap;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlType;
/**
* Web Service傳輸信息的DTO.
* 分離entity類與web service接口間的耦合,隔絕entity類的修改對接口的影響. 使用JAXB 2.0的annotation標註JAVA-XML映射,儘可能使用默認約定. *
*/
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "User")
public class ParamDTO {
protected Integer id;
protected String name;
public Integer getId() {
return id;
}
public void setId(Integer value) {
id = value;
}
public String getName() {
return name;
}
public void setName(String value) {
name = value;
}
}
2.在配置文件中體映射這個Service:
咱們定義這個Beans.xml
<?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:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<jaxws:endpoint id="webServiceHelloWorld"
address="/HelloWorld" implementor="com.services.soap.HelloWorld"/>
</beans>
這個Beans.xml放到Spring的加載Beans的配置文件中被引用:
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<import resource="classpath*:META-INF/cxf/cxf.xml" />
<import resource="classpath*:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath*:META-INF/cxf/cxf-servlet.xml" />
<import resource="classpath:beans.xml" /> //注意這行代碼的引用
</beans>
固然咱們要在Web.xml中配置Spring:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>webrest</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/classes/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>
org.apache.cxf.transport.servlet.CXFServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
也可參考http://www.cnblogs.com/hoojo/archive/2011/03/30/1999563.html提供了另外一種類似的配置方式。
四,建立一個基於CXF及Spring的Restful Web Service:
這個就相對簡單了。由於經不須要直接接供RPC接口給客戶端,只是其於ROA的方式提供資源的操做,能夠理解爲基於一些xml,json的表達一些資源對象變態變化的傳輸同步給遠程服務。
因此經過xml映射對象,Annomation進行直接映射方法與path.因此直接寫實現類就好了,固然cxf還有別的框架有其它的映射或配置方式。
a.代碼實現:
先上代碼:
HelloWorld.java
package com.services.rest;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
@Path("/hello")
public class HelloWorld {
@GET
@Path("/echo/{input}")
@Produces("text/plain")
public String ping(@PathParam("input") String input) {
return input + ":in server!";
}
@POST
@Produces("application/json")
@Consumes("application/json")
@Path("/jsonBean")
public Response modifyJson(JsonBean input) {
input.setCommand(222);
input.getParam().put("content", "welcome to server!");
return Response.ok().entity(input).build();
}
}
其中用到JsonBean對象這個是能夠遠程傳送參數對象,通常狀況無需特別的定義。就能夠直接用了。我這裏定義以下:
JsonBean:
package com.services.rest;
import java.util.Map;
public class JsonBean {
private Integer command;
private Integer protocolVersion;
private String platformType;
private Map<String, Object> param;
public Integer getCommand() {
return command;
}
public void setCommand(Integer command) {
this.command = command;
}
public Integer getProtocolVersion() {
return protocolVersion;
}
public void setProtocolVersion(Integer protocolVersion) {
this.protocolVersion = protocolVersion;
}
public String getPlatformType() {
return platformType;
}
public void setPlatformType(String platformType) {
this.platformType = platformType;
}
public Map<String, Object> getParam() {
return param;
}
public void setParam(Map<String, Object> param) {
this.param = param;
}
}
b.進行發佈:
配置一個rest-services.xml進行映射:
<?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:jaxrs="http://cxf.apache.org/jaxrs" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<context:property-placeholder/> <context:annotation-config/> <bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer"/> <bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"/>
<jaxrs:server id="services" address="/"> <jaxrs:serviceBeans> <bean class="com.services.rest.HelloWorld" /> </jaxrs:serviceBeans> <jaxrs:providers> <bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider"/> </jaxrs:providers> </jaxrs:server>
</beans>
在Spring的加載配置文件(applicationContext.xml)裏引入:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<import resource="classpath*:META-INF/cxf/cxf.xml" />
<import resource="classpath*:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath*:META-INF/cxf/cxf-servlet.xml" />
<import resource="classpath:rest-services.xml" />
</beans>
OK,大功告成。
到時此咱們能把這兩種模式的Web Service同時在一個框架裏發佈嗎?固然能夠:)要作的只有一步,就是在上面的applicationContext.xml裏同時加載兩個Service的映射文件就能夠了。
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<import resource="classpath*:META-INF/cxf/cxf.xml" />
<import resource="classpath*:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath*:META-INF/cxf/cxf-servlet.xml" />
<import resource="classpath:beans.xml" />
<import resource="classpath:rest-services.xml" />
</beans>
如今就你就能夠編譯完成,Publish到你的tomcat上進行測試了,不過必定要注意,在發佈選項裏必定要把你項目工程中引用的jar依賴庫(好比,cxf相關,spring相關的,Json相關的)同時發佈到你的Tomcat Server的運行環境裏,這裏只須要修改:項目(MyServices)右鍵=》Properties=>Deployment Assembly=>Add=>Java Build Path Entries 不過在引入的jar過多時可能會形成衝突,假如在測試時,說CXF 的一個Discoveryxxx對象..... Null Point之類的錯誤:
SEVERE: Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'bookservice': Invocation of init method failed; nested exception is org.apache.cxf.service.factory.ServiceConstructionException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1422)
.......
Caused by: org.apache.cxf.service.factory.ServiceConstructionException
at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:201)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...
Caused by: java.lang.NullPointerException
at org.apache.cxf.ws.discovery.listeners.WSDiscoveryServerListener.startServer(WSDiscoveryServerListener.java:64)
at org.apache.cxf.bus.managers.ServerLifeCycleManagerImpl.startServer(ServerLifeCycleManagerImpl.java:61)
at org.apache.cxf.endpoint.ServerImpl.start(ServerImpl.java:146)
at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:192)
........
就是最多見的cxf-services-ws-discovery-service-2.x.x.jar衝突,去掉這個.jar的依賴便可。若是你在項目的Java Build Path中去掉這個jar仍不行,就去你測試的Tocat Server上右鍵「clean" 而後再"Publish",若是這樣還不行,說明是Eclipse 清除Tomcat的發佈目錄不完全(Eclipse也有不少bug的),你就去Tomcat 的運行時臨時Web根目錄中去清除這個jar.這個目錄是在Eclipse的Workspace目錄下的」.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps「子目錄。如今估計你能理解爲何你在Eclipse 的runtime server中用Tomcat測試發佈後的文件在Tomcat的安裝目錄看不到的緣由了吧?呵呵,由於Eclipse整合tomcat測試運行時,根本上會使用本身的臨時目錄做爲Tomcat的運行時Web根目錄。
若是你遇到:
Caused by: java.lang.NullPointerException
Class Could not found: org.springframework.web.context.ContextLoaderListener 之類的錯誤。你須要在你的Web project的Deployment Assemblly 中 加入Java build path的庫,即點擊"Add"按鈕,在彈出列表窗口中選擇「Java Build Path Entries"而後選中你的工程發佈所須要的庫便可。
到這裏應該完成了。
下面就能夠用各類客戶端或者瀏覽器進行訪問了,這裏主要講方法,可能部分代碼在相關的博文裏面附上了:
0.測試工具:
對於restful web service由於返回的內容均可以簡單的分析,因此能夠用不少工具進行測試。
a. 基於firefox的 Poster
b.linux上的curl.
c.......
1.Native 客戶端訪問方法:
用Java的NIO中的HttpClient就能夠搞定 Restful Web Service.
a.cxf的WebClient接口:
cxf提供了訪問WebService的全部接口,例子代碼以下:
import javax.ws.rs.core.MediaType;
import org.apache.cxf.jaxrs.client.WebClient;
public class RSETClient {
private static WebClient client;
public void init() {
client = new WebClient("http://localhost:8080/restWeb/hello/teststring");
}
public void testGet() {
System.out.println(client.path("sample").accept(MediaType.TEXT_PLAIN).get(String.class));
}
}
b.Spring RestTemplate:
這個能夠經過在客戶端使用Spring 的RestTemplate 相關的庫來訪問。
下面代碼是用Spring for Android寫的,PC各平臺上調用大同小異,沒時間在這裏上代碼了。
HttpHeaders reqHeader = new HttpHeaders();
reqHeader.setContentType(new MediaType("text", "plain"));
HttpEntity<String> req = new HttpEntity<String>(reqHeader);
String restUrl = "http://192.168.2.100:8080/webrest/hello/echo/testtest";// 這個地址要根據你Restful
// 服務器來定
// 好戲上場了,呵呵
RestTemplate restTemplate = new RestTemplate(true);
//restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
ResponseEntity<String> response = restTemplate.exchange(restUrl,
HttpMethod.GET, req, String.class);
String msgBody = response.getBody();
System.out.println(msgBody);
2.瀏覽器測試:
a.能夠經過Form進行簡單的訪問。
b. 能夠經過客戶端的Ajax代碼來訪問Restful Webservice.
能夠經過客戶端的Ajax代碼來訪問Restful Webservice.
3.手機端訪問方法(訪問代碼見個人相關手機客戶端的博文):
a.Android端:
可使用Android自帶的HttpClient進行訪問Restful Web Service。這就是Restful Web Service的優點能夠一些平臺上最基本的http 庫來訪問。
可使用第三方庫KSoap來訪問基於Soap的Web Service.
同時你能夠用Spring for Android 中的RestTemplate接口來訪問 Restful Web service :
HttpHeaders reqHeader = new HttpHeaders();
reqHeader.setContentType(new MediaType("text", "plain"));
HttpEntity<String> req = new HttpEntity<String>(reqHeader);
String restUrl = "http://192.168.2.100:8080/webrest/hello/echo/testtest";// 這個地址要根據你Restful
// 服務器來定 // 好戲上場了,呵呵
RestTemplate restTemplate = new RestTemplate(true);
//restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
ResponseEntity<String> response = restTemplate.exchange(restUrl, HttpMethod.GET, req, String.class);
String msgBody = response.getBody();
System.out.println(msgBody);
b.IOS端:
可使用IOS上的第三方Http庫來訪問 Restful Web Service,庫名字叫:。