什麼是CXF:javascript
Apache CXF = Celtix + Xfirehtml
支持多種協議:java
SOAP1.1,1.2jquery
XML/HTTPc++
CORBA(Common Object Request Broker Architecture公共對象請求代理體系結構,早期語言使用的WS。 C,c++,C#) web
並能夠與Spring進行快速無縫的整合ajax
靈活的部署:能夠運行在Tomcat,Jboss,Jetty(內置),IBMWS,BeaWL上面。spring
安裝CXF的其餘支持項目:apache
Ant編程
Tomcat
並設置如下環境變量:
JAVA_HOME
CXF_HOME
ANT_HOME
CATALINA_HOME
Path = %JAVA_HOME%\bin;%CXF_HOME%\bin;%CATALINA_HOME%\bin;%ANT_HOME%\bin
CLASSPATH=.;%CXF_HOME%\lib\cxf-manifest.jar;.\build\classes
在Eclipse中開發CXF的JavaSE應用:
導入CXF中的 全部jar文件。能夠經過WACH_JARS來觀察各jar文件的用途。
創建好以後的項目如圖所示:
CXF發佈服務的類:
用兩個不一樣的類發佈應用:
ServerFactoryBean -- FacotryBean
JaxWsServerFactoryBean(建議使用此類)
使用ServerFactoryBean發佈服務:
/** * 使用ServerFactoryBean發佈CXF的javase應用 * @author zhaoqx * */ public class HelloService { public String sayHello(String name){ System.out.println("sayHello called..."); return "hello " + name; } public static void main(String[] args) { ServerFactoryBean bean = new ServerFactoryBean(); bean.setAddress("http://192.168.1.24:9999/Hello"); bean.setServiceClass(HelloService.class); bean.setServiceBean(new HelloService()); bean.create(); System.err.print("啓動成功"); } }
使用ClientProxyFactoryBean客戶端調用
使用ServerFactoryBean發佈服務之後,在沒有接口的狀況下,可使用wsimport生成的客戶端代碼調用成功。
但若是要使用ClientProxyFactoryBean客戶端去調用服務器,則必需要先在服務器端建立一個接口。(一直以來,Spring都要求面向接口編程,而cxf與Spring能很好的整合,也就在此。),因此,必需要重寫服務器端的代碼。這將致使剛纔使用wsimport生成的調用代碼失效。
同時, ClientProxyFactoryBean因爲要用到CXF環境,因此要導入CXF的全部包。
同時,若是是在本項目中調用,則能夠直接使用本項目的接口。
若是在其餘項目中調用,仍然需wsimport生成的類,但只須要一個接口。
使用JaxWsServerFactoryBean發佈服務: (建議使用此類)
JaxWsServerFactoryBean是ServerFactoryBean的子類,也是功能擴展類。但在CXF的API文檔中沒有提供此類API,請經過查看源代碼的方式獲取此類的幫助。此類,必需要在被髮布爲服務的類上添加@WebService註解,若是不加註解,雖然不出錯,但也不會對外暴露任何方法。使用此類生成的wsdl文件更加規範。
@WebService //@javax.xml.ws.BindingType(value=javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING) public class HiService { public String sayHi(String name){ System.out.println("服務調用"); return "Hi"+name; } public static void main(String[] args) { JaxWsServerFactoryBean bean = new JaxWsServerFactoryBean(); bean.setAddress("http://localhost:9999/two"); bean.setServiceClass(HiService.class); bean.setServiceBean(new HiService()); bean.create(); System.err.print("服務啓動成功"); } }
使用JaxWsProxyFactoryBean客戶端調用:
此調用過程與ClientProxyFactoryBean的要求同樣,也必需要擁有一個接口。
此時,仍然可使用wsimport生成接口,在其餘項目的調用。
規範的作法應該是先書寫一個接口,以下:
@WebService public interface IHelloService { public String sayHello(String name); }
public class IHelloServiceImpl implements IHelloService { public String sayHello(String name) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(new Date())+"=== hello=====" + name; } public static void main(String[] args) { JaxWsServerFactoryBean bean = new JaxWsServerFactoryBean(); bean.setAddress("http://192.168.1.24:8888/sayHi"); bean.setServiceClass(IHelloService.class); bean.setServiceBean(new IHelloServiceImpl()); //加入請求消息攔截器 bean.getInInterceptors().add(new LoggingInInterceptor()); //加入響應消息攔截器 bean.getOutInterceptors().add(new LoggingOutInterceptor()); bean.create(); System.err.print("服務啓動成功"); } }
wsdl2java生成客戶代碼:
在cxf中,也提供了一個用於生成客戶端調用代碼的工具。它的功能就如同wsimport同樣。
先讓咱們瞭解一下cxf的wsdl2java工具,能夠生成一堆客戶端調用的代碼。
此工具位於cxf_home/bin目錄下。參數與wsimport有所不一樣。
它包含如下參數:
-d參數,指定代碼生成的目錄。
-p參數,指定生成的新的包結構。
須要說明的是,因爲wsdl2java是根據jdk1.7生成的本地代碼,因此,須要對生成的代碼作一點點修改。
在命令行執行:
wsdl2java –d . http://127.0.0.1:6666/helloworld?wsdl
調用端代碼:
使用JavaScript也能夠訪問WebServie:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>使用jquery的ajax調用Web服務 </title> <script type="text/javascript" src="js/jquery-1.6.2.js"></script> <script type="text/javascript"> $(function(){ $("#but1").click(function(){ //指定訪問服務的地址 var wsUrl = "http://localhost:8090/CXF03/cxf/hi"; //構造請求體 var soap = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHi xmlns:ns2="http://kaiyi/"><arg0>abc</arg0></ns2:sayHi></soap:Body></soap:Envelope>'; $.ajax({ url:wsUrl, type:'post', dataType:'xml', contentType:'text/xml;charset=UTF-8', data:soap, success:function(data){ alert('OK!'); var o = $(data); alert(o.find('return').eq(0).text()); }, error:function(){ alert('error!'); } }); }); }); </script> </head> <body> <input type="button" value="發送jquery的ajax請求" id="but1"> </body> </html>
以上均是非WEB的開發下面介紹基於web的cxf
因爲cxf的web項目已經集成了Spring因此,cxf的服務類都是在spring的配置文件中完成的。如下是步驟:
第一步:創建一個web項目。
第二步:準備全部jar包。將cxf_home\lib項目下的全部jar包所有copy到新項目的lib目錄下,裏面已經包含了spring3.0的jar包。
第三步:在web.xml中配置cxf的核心servlet,CXFServlet。
第四步:建立(最好是Copy)cxf-servlet.xml文件。這是一個spring的配置文件。
cxf-servlet.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" xmlns:soap="http://cxf.apache.org/bindings/soap" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd "> <!-- 引入CXF Bean定義以下,早期的版本中使用 --> <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" /> <!-- 經過spring配置文件發佈CXF的服務 --> <!-- 第一種發佈方式:沒有接口的發佈(簡單發佈) --> <!-- id:惟一標識 address:訪問url implementor:提供服務的類型 --> <jaxws:endpoint id="helloService" address="/hello" implementor="kaiyi.HelloService"> <!-- 加入消息攔截器 --> <jaxws:inInterceptors> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean> </jaxws:inInterceptors> <jaxws:outInterceptors> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean> </jaxws:outInterceptors> </jaxws:endpoint> <!-- 第二種發佈方式:帶有接口的發佈 --> <jaxws:server id="hiService" address="/hi" serviceClass="kaiyi.IHiService"> <jaxws:serviceBean> <!-- 提供服務的實現類 --> <bean class="kaiyi.IHiServiceImpl"></bean> </jaxws:serviceBean> <!-- 加入消息攔截器 --> <jaxws:inInterceptors> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean> </jaxws:inInterceptors> <jaxws:outInterceptors> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean> </jaxws:outInterceptors> </jaxws:server> <!-- 配置restful方式的web服務 --> <bean id="ps" class="restful.PersonServiceImpl"></bean> <jaxrs:server id="personService" address="/p"> <jaxrs:serviceBeans> <ref bean="ps"/> </jaxrs:serviceBeans> <jaxrs:inInterceptors> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean> </jaxrs:inInterceptors> <jaxrs:outInterceptors> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean> </jaxrs:outInterceptors> </jaxrs:server> </beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- 經過上下文參數指定spring配置文件的位置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:cxf-servlet.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 配置CXF框架的核心Servlet --> <servlet> <servlet-name>cxf</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <!-- 經過初始化參數指定配置文件的位置 --> <!-- <init-param> <param-name>config-location</param-name> <param-value>classpath:cxf-servlet.xml</param-value> </init-param>--> </servlet> <servlet-mapping> <servlet-name>cxf</servlet-name> <url-pattern>/cxf/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
這是個人包結構:
/** * 使用ServerFactoryBean發佈CXF的javase應用 * @author zhaoqx * */ @WebService public class HelloService { public String sayHello(String name){ System.out.println("sayHello called..."); return "hello " + name; } }
package kaiyi; import javax.jws.WebService; @WebService public interface IHiService { public String sayHi(String name); }
package kaiyi; public class IHiServiceImpl implements IHiService{ public String sayHi(String name) { System.out.println("sayHi...."); return "hi " + name; } }
在地址欄訪問:
Java項目代碼調用服務:
使用純Java項目調用
一、根據客戶端生成的代碼來調用。(優選這種方式)請先生成而後在任意的Java項目中調用 。
二、客戶端只擁有一個接口,使用JaxWsProxyFactoryBean來調用。
由於如下使用了JaxWsProxyFactoryBean,因此,仍然須要CXF的環境,而使用此環境就會形成Jar文件的大量冗餘,因此你們要謹慎選擇(一下的地址是隨便貼的)。
在Spring項目中,經過配置文件調用:
如下是使用Spring的配置文件調用:
新創建一個Java項目,並加載cxf的全部包。
只須要生成的接口文件.
在classpath下新創建一個ClientBeans.xml文件.
優勢與缺點:
此種狀況,適合於一個Javaweb項目已經集成了Spring。並但願經過CXF配置的方式調用Web服務。
此種狀況,仍然須要導入CXF的大量jar包。
這種狀況也存在必定優勢,如能夠將外部的Web服務經過配置文件注入(DI)到Action類中。
結構圖以下(帶接口的方式):
ClientBeans.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" xmlns:soap="http://cxf.apache.org/bindings/soap" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <!-- 配置客戶端bean --> <!-- id:惟一標識 address:請求的服務地址 serviceClass:客戶端接口 --> <jaxws:client id="hiService" address="http://localhost:8090/CXF03/cxf/hi" serviceClass="kaiyi.IHiService"></jaxws:client> </beans>
如下是調用代碼:
package test; import kaiyi.IHiService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class test { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("ClientBeans.xml"); IHiService ihi = (IHiService) ctx.getBean("hiService"); ihi.sayHi("abc"); System.out.println(ihi.getClass().getName()); } }
經過JS來調用WebService:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>使用jquery的ajax調用Web服務 </title> <script type="text/javascript" src="js/jquery-1.6.2.js"></script> <script type="text/javascript"> $(function(){ $("#but1").click(function(){ //指定訪問服務的地址 var wsUrl = "http://localhost:8090/CXF03/cxf/hi"; //構造請求體 var soap = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHi xmlns:ns2="http://kaiyi/"><arg0>abc</arg0></ns2:sayHi></soap:Body></soap:Envelope>'; $.ajax({ url:wsUrl, type:'post', dataType:'xml', contentType:'text/xml;charset=UTF-8', data:soap, success:function(data){ alert('OK!'); var o = $(data); alert(o.find('return').eq(0).text()); }, error:function(){ alert('error!'); } }); }); }); </script> </head> <body> <input type="button" value="發送jquery的ajax請求" id="but1"> </body> </html>
POJO類:
package pojo; import java.io.Serializable; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "person") public class Person implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private String id; private String name; private String desc; @XmlElement(name = "id") public String getId() { return id; } public void setId(String id) { this.id = id; } @XmlElement(name = "name") public String getName() { return name; } public void setName(String name) { this.name = name; } @XmlElement(name = "desc") public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } @Override public String toString() { return "Person [desc=" + desc + ", id=" + id + ", name=" + name + "]"; } }
如今通常來講用URL的方式調用restful服務比較流行:
它與WSDL方式徹底不一樣,採用的是一種新型的方式,企業開發使用較爲常見:
Available RESTful services:
Endpoint address: http://localhost:8090/CXF03/cxf/p WADL : http://localhost:8090/CXF03/cxf/p?_wadl&type=xml |
訪問後返回的是json或者XML數據
此種方式只須要在cxf-servlet.xml配置一下便可:
<!-- 配置restful方式的web服務 --> <bean id="ps" class="restful.PersonServiceImpl"></bean> <jaxrs:server id="personService" address="/p"> <jaxrs:serviceBeans> <ref bean="ps"/> </jaxrs:serviceBeans> <jaxrs:inInterceptors> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean> </jaxrs:inInterceptors> <jaxrs:outInterceptors> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean> </jaxrs:outInterceptors> </jaxrs:server>
如下是訪問方式:
package test; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.util.List; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import org.junit.Test; import pojo.Person; // 使用URL的方式調用restful服務 public class UrlConnectionTest { @Test public void test1() throws Exception { String wsUrl = "http://localhost:8090/CXF03/cxf/p/persons/id0"; URL url = new URL(wsUrl); URLConnection conn = url.openConnection(); HttpURLConnection con = (HttpURLConnection)conn; con.setRequestMethod("GET"); int code = con.getResponseCode(); if(code == 200){ InputStream in = con.getInputStream(); byte[] b = new byte[1024]; int len = 0; StringBuffer sb = new StringBuffer(); while((len=in.read(b))!=-1){ String s = new String(b,0,len,"UTF-8"); sb.append(s); } String json = sb.toString(); JSONObject o = JSONObject.fromObject(json); json = o.getString("person").toString(); //將String轉換爲Person對象 Person person = (Person) JSONObject.toBean(JSONObject.fromObject(json), Person.class); System.out.println("----"+person); } con.disconnect(); } @Test public void test2() throws Exception { String wsUrl = "http://localhost:8090/CXF03/cxf/p/persons"; URL url = new URL(wsUrl); URLConnection conn = url.openConnection(); HttpURLConnection con = (HttpURLConnection)conn; con.setRequestMethod("GET"); int code = con.getResponseCode(); if(code == 200){ InputStream in = con.getInputStream(); byte[] b = new byte[1024]; int len = 0; StringBuffer sb = new StringBuffer(); while((len=in.read(b))!=-1){ String s = new String(b,0,len,"UTF-8"); sb.append(s); } String json = sb.toString(); JSONObject o = JSONObject.fromObject(json); Object obj = o.get("person"); json = obj.toString(); List<Person> list = (List<Person>)JSONArray.toCollection(JSONArray.fromObject(json), Person.class); for(Person p:list){ System.out.println(p); } } con.disconnect(); } }
咱們能夠根據被調用服務的接口上的註解來決定返回值的數據格式
//@Produces( { MediaType.APPLICATION_XML })
@Produces( { MediaType.APPLICATION_JSON })
public interface IPersonService extends Serializable
如下是服務代碼:
package restful; import java.io.Serializable; import java.util.List; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import pojo.Person; //@Produces( { MediaType.APPLICATION_XML }) @Produces( { MediaType.APPLICATION_JSON }) public interface IPersonService extends Serializable { @GET @Path(value="/persons/{id}") public Person findPersonById( @PathParam("id") String id); @GET @Path(value="/persons") public List<Person> findAllPerson(); }
package restful; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import pojo.Person; public class PersonServiceImpl implements IPersonService { /** * */ private static final long serialVersionUID = 1L; private static Map<String, Person> ps = new HashMap<String, Person>(); static { for(int i=0;i<5;i++){ Person p = new Person(); p.setId("id" + i); p.setName("person" + i); p.setDesc("desc" + i); ps.put(p.getId(), p); } } public List<Person> findAllPerson() { return new ArrayList<Person>(ps.values()); } public Person findPersonById(String id) { return ps.get(id); } }
如下是調用代碼:
package test; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.util.List; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import org.junit.Test; import pojo.Person; // 使用URL的方式調用restful服務 public class UrlConnectionTest { @Test public void test1() throws Exception { String wsUrl = "http://localhost:8090/CXF03/cxf/p/persons/id0"; URL url = new URL(wsUrl); URLConnection conn = url.openConnection(); HttpURLConnection con = (HttpURLConnection)conn; con.setRequestMethod("GET"); int code = con.getResponseCode(); if(code == 200){ InputStream in = con.getInputStream(); byte[] b = new byte[1024]; int len = 0; StringBuffer sb = new StringBuffer(); while((len=in.read(b))!=-1){ String s = new String(b,0,len,"UTF-8"); sb.append(s); } String json = sb.toString(); JSONObject o = JSONObject.fromObject(json); json = o.getString("person").toString(); //將String轉換爲Person對象 Person person = (Person) JSONObject.toBean(JSONObject.fromObject(json), Person.class); System.out.println("----"+person); } con.disconnect(); } @Test public void test2() throws Exception { String wsUrl = "http://localhost:8090/CXF03/cxf/p/persons"; URL url = new URL(wsUrl); URLConnection conn = url.openConnection(); HttpURLConnection con = (HttpURLConnection)conn; con.setRequestMethod("GET"); int code = con.getResponseCode(); if(code == 200){ InputStream in = con.getInputStream(); byte[] b = new byte[1024]; int len = 0; StringBuffer sb = new StringBuffer(); while((len=in.read(b))!=-1){ String s = new String(b,0,len,"UTF-8"); sb.append(s); } String json = sb.toString(); JSONObject o = JSONObject.fromObject(json); Object obj = o.get("person"); json = obj.toString(); List<Person> list = (List<Person>)JSONArray.toCollection(JSONArray.fromObject(json), Person.class); for(Person p:list){ System.out.println(p); } } con.disconnect(); } }
這是調用http://localhost:8090/CXF03/cxf/p/persons 地址後被解析的數據
----Person [desc=desc0, id=id0, name=person0]
Person [desc=desc2, id=id2, name=person2]
Person [desc=desc1, id=id1, name=person1]
Person [desc=desc0, id=id0, name=person0]
Person [desc=desc4, id=id4, name=person4]
Person [desc=desc3, id=id3, name=person3]
目前的webservice的就到這!