基於cxf實現的webservice,全程開發指南和筆記,以及代碼

SOA(面向服務的架構)
Service1,Service2,Service3--全部組件都是「即插即用」的

IBM提倡的SOA架構,但願以「組裝電腦」的方式來開發軟件。
1,各類提供服務的組件。
2,企業服務總線(EnterpriseServiceBus,ESB)

CXF號稱是SOA框架

CXF(Apache)

cxf框架的使用
1,下載cxf
2,配置cxf下bin的path環境變量
3,測試環境變量是否配置正確

cxf框架目錄介紹
/bin經常使用命令
/doc開發文檔
/libjar包

cxf內置了一個JettyWeb服務器
(tomcat的開發者就是javaee規範的制定者)
使用cxf開發webservice服務端
1,開發一個webservice接口
加上@WebService註釋
2,開發實現類
加上@WebService()註釋
加上屬性endpointInterface="com.kenan.cxf.HelloWorld"指定實現的接口
serviceName=「HelloworldService」
3,加入jar包
cxf
servlet3.0
jetty-*(JettyWeb服務器)
asm
common-logging
neethi
xmlschema-core
wsdl4j
4,建立測試類,發佈ws(須要在main方法中)
HelloWorldhw=newHImpl();
Endpoint.publish("http://localhost:9999/hello",hw);
5,訪問http://localhost/hello?wsdl

使用cxf開發webservice客戶端
1,使用wsdl2java將服務端暴露的wsdl文檔轉換爲java代碼
2,找到實現了service接口的類,該類能夠當成工廠來使用
HelloWorldImplfac=new();
3,生產HelloWorldhello=fac.getHelloWorldWsPort();
調用遠程方法
hello.say("sdf");

1,當形參,返回值爲String的時候,cxf能夠輕鬆的處理
2,當形參返回值類型爲javabean的複合類,List集合,數組,cxf也能夠很好的處理

wsdl介紹
wsdl:webservicedefinationlanguagehtml

wsdl是一個xml文檔
xml中的兩個屬性
targetNamespace(規定本身這個文檔的命名空間)至關於java中的包名
xmlns(命名空間:xmlnamespace)至關於java中要引入的

WSDL文檔
1,WebService接口

一次webservice的調用,其實不是方法調用,而是發送SOAP消息(xml文檔片斷)
要調用的方法,和傳入的參數都寫在xml文檔中,也就是一個SOAP消息

SOAPsimpleobjectaccessproto簡單對象協議
調用一次webservice的本質
1,客戶端把要調用方法參數,轉換成xml文檔片斷(SOAP消息),該文檔必須符合wsdl文檔規範
2,經過網絡,把xml文檔傳給服務器
3,服務器接受到xml文檔
4,服務器解析xml文檔片斷,提取其中的數據。
並把數據轉換調用webservice所須要的參數類型
5,服務器執行方法
6,把執行方法獲得的返回值,再次轉換成xml文檔片斷
7,經過網絡,把xml文檔片斷傳給客戶端
8,客戶端接受到XML文檔
9,客戶端解析到XML文檔,提取其中的數據
並把數據轉換成調用webservice的返回值

從上面調用的本質來看,要一個語言支持webservice
惟一的要求是,該語言支持xml文檔解析,聲稱,支持網絡傳輸


若是遇到cxf沒法轉換的類型,就須要咱們自定義轉換
如對於map對象
1,使用@XmlJavaTypeAdapter註釋沒法處理的類型
經過(value=)XmlAdapter指定一個轉換器
轉換器在這裏就能夠把cxf搞不定的類型搞定
2,實現本身的轉換器,開發一個cxf搞得定的類型須要實現XmlAdapter抽象類
這裏有兩個參數,第一個是搞得定的類型
第二個是搞不定的類型
extendsXmlAdapter<StringCat,Map<string,Cat>>

SOAP協議:簡單對象傳輸協議
傳入消息:
header:默認狀況下,header元素不是強制出現的,header元素
有程序員控制添加,主要用於攜帶一些額外的信息
2013-1-2822:13:26org.apache.cxf.services.HelloWorldImpl.HelloWorldImplPort.HelloWorld
信息:InboundMessage
----------------------------
ID:3
Address:http://localhost:9999/hello
Encoding:UTF-8
Http-Method:POST
Content-Type:text/xml;charset=UTF-8
Headers:
{Accept=[text/xml,multipart/related,text/html,p_w_picpath/gif,p_w_picpath/jpeg,*;q=.2,*/*;q=.2],
connection=[keep-alive],
Content-Length=[195],
content-type=[text/xml;
charset=UTF-8],
Host=[localhost:9999],
SOAPAction=[""],
User-Agent=[Java/1.6.0_13]}
Payload:
<?xmlversion="1.0"?>
<S:Envelopexmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:helloxmlns:ns2="http://ws.cxf.kenan.com/">
<arg0>你好</arg0>
</ns2:hello>
</S:Body>
</S:Envelope>
--------------------------------------

傳出消息:
2013-1-2822:13:26org.apache.cxf.services.HelloWorldImpl.HelloWorldImplPort.HelloWorld
信息:OutboundMessage
---------------------------
ID:3
Encoding:UTF-8
Content-Type:text/xml
Headers:{}
Payload:
<soap:Envelopexmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:helloResponsexmlns:ns2="http://ws.cxf.kenan.com/">
<return>你好</return>
</ns2:helloResponse>
</soap:Body>
</soap:Envelope>
--------------------------------------

webservice急需解決的問題:如何收錢?
--如何進行權限控制?
爲了進行權限控制,須要:
客戶端發送soap消息的時候,必須攜帶用戶名和密碼信息
若是沒有,或者不正確,拒絕調用

攔截器
爲了讓程序員放訪問,並修改cxf聲稱的xml文檔,cxf提供的攔截器
分爲In攔截器
Out攔截器
服務器端添加攔截器:
1,在發佈的時候
EndPointImplep=En...publish();
添加in攔截器
ep.getInInterceptors().add(e);
添加out攔截器
ep.getOutInterceptors().add(e);
2,系統的攔截器
這個是日誌的攔截器
newLoggingInInterceptor();(默認輸出到控制檯)
newLoggingOutInterceprot();
3,建立自定義攔截器須要實現Interceptor
通常咱們會繼承AbstractPhaseInterceptor

客戶端添加攔截器

1,倒入jar包(zxf。。。)
2,Clientclient=ClientProxy.getClient(hi);
hi爲webserice接口類對象
client.getInInterceptors().add();

自定義攔截器
1,繼承AbstractPhaseInterceptor
extendsAbstractPhaseInterceptor<SoapMessage>
2,實現handlMessage方法
這個方法中的形參就是被攔截到的soap消息
解析soap消息,或者修改soap消息
3,寫構造函數,顯式調用父類構造函數,程序將不會隱式調用父類無參數的構造函數
super(Phase.PRE_INVOKE)在調用以前攔截soap消息
4,消息處理
參數SoapMessagemsg
System.our.println(msg);
List<Header>headers=msg.getHeaders();
if(headers!=null&&headers.size()>0){
//加入要求第一個header存放用戶名和密碼
Headerh=headers.get(0);
Elementele=(Element)h.getObject();
NodeListuserIds=ele.getElementsByTagName("userId");
NodeListuserPasses=ele.getElementsByTagName("userPass");

if(userIds.getLength==1&&userPasses.getLength()==1){
StringuserId=userIds.item)0).getTextContent();
StringuserPass=userPasses.item(0).getTextContent();
if(){
//驗證經過
return;
}
}
}
自定義客戶端的OutInterceptor
1,同上
2,構造器
publicConstructor(StringuserId,StringuserPass){
super(Phase.PREPARE_SEND);//在發送soap消息以前調用該攔截器
this.userId=
this.userPass..
}
3,HandleMessage
List<Header>headers=msg.getHeaders();
Documentdoc=DOMUtils.createDocument();
Elementele=doc.createElement("authHeader");
ElementidEle=doc.createElement("userId");
idEle.setTextContent(userId);
ElementpassEle=doc.createElement("userPass");
passEle.setTextContent(userPass);

ele.appenChild(idEle);
ele.appenChild(passEle);
生成以下文檔
<authHeader>
<userId></userId>
<userPass></userPass>
</authHeader>
//把ele元素包裝成header,並添加到soap消息中
Headerheader=newHeader(newQName("qname"),ele);
headers.add(header);

客戶端利用攔截器在發功的soap消息中寫入數據後的消息
<soap:Envelopexmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<authHeader>
<userId>23</userId>
<userPass>sdr</userPass>
</authHeader>
</soap:Header>
<soap:Body>
<ns2:helloxmlns:ns2="http://ws.cxf.kenan.com/">
<arg0>你好</arg0></ns2:hello
></soap:Body>
</soap:Envelope>

服務器端代碼:

轉換器:用於轉換Map數據類型java

 
 
  1. packagecom.kenan.cxf.adapter;程序員

  2. importjava.util.HashMap;web

  3. importjava.util.Map;數據庫

  4. importjavax.xml.bind.annotation.adapters.XmlAdapter;apache

  5. importcom.kenan.cxf.adapter.domain.StringCat;數組

  6. importcom.kenan.cxf.adapter.domain.StringCat.Entry;tomcat

  7. importcom.kenan.cxf.domain.Cat;服務器

  8. publicclassMapXmlAdapterextendsXmlAdapter<StringCat,Map<String,Cat>>{網絡

  9. @Override

  10. publicMap<String,Cat>unmarshal(StringCatv)throwsException{

  11. Map<String,Cat>m=newHashMap<String,Cat>();

  12. for(Entryentry:v.getEntries()){

  13. m.put(entry.getKey(),entry.getValue());

  14. }

  15. returnm;

  16. }

  17. @Override

  18. publicStringCatmarshal(Map<String,Cat>v)throwsException{

  19. StringCats=newStringCat();

  20. for(Stringkey:v.keySet()){

  21. Entrye=newEntry(key,v.get(key));

  22. s.getEntries().add(e);

  23. }

  24. returns;

  25. }

  26. }


用戶map轉換器的實體

 
 
  1. packagecom.kenan.cxf.adapter.domain;

  2. importjava.util.ArrayList;

  3. importjava.util.List;

  4. importcom.kenan.cxf.domain.Cat;

  5. publicclassStringCat{

  6. publicstaticclassEntry{

  7. privateStringkey;

  8. privateCatvalue;

  9. publicEntry(){

  10. }

  11. publicEntry(Stringkey,Catvalue){

  12. super();

  13. this.key=key;

  14. this.value=value;

  15. }

  16. publicStringgetKey(){

  17. returnkey;

  18. }

  19. publicvoidsetKey(Stringkey){

  20. this.key=key;

  21. }

  22. publicCatgetValue(){

  23. returnvalue;

  24. }

  25. publicvoidsetValue(Catvalue){

  26. this.value=value;

  27. }

  28. }

  29. privateList<Entry>entries=newArrayList<Entry>();

  30. publicList<Entry>getEntries(){

  31. returnentries;

  32. }

  33. publicvoidsetEntries(List<Entry>entries){

  34. this.entries=entries;

  35. }

  36. }


進行權限驗證的過濾器:AuthInterceptor

 
 
  1. packagecom.kenan.cxf.auth;

  2. importjava.util.List;

  3. importorg.apache.cxf.binding.soap.SoapMessage;

  4. importorg.apache.cxf.headers.Header;

  5. importorg.apache.cxf.interceptor.Fault;

  6. importorg.apache.cxf.phase.AbstractPhaseInterceptor;

  7. importorg.apache.cxf.phase.Phase;

  8. importorg.w3c.dom.Element;

  9. importorg.w3c.dom.NodeList;

  10. publicclassAuthInterceptorextendsAbstractPhaseInterceptor<SoapMessage>{

  11. publicAuthInterceptor(){

  12. super(Phase.PRE_INVOKE);//在調用方法以前攔截

  13. //TODOAuto-generatedconstructorstub

  14. }

  15. @Override

  16. publicvoidhandleMessage(SoapMessagemsg)throwsFault{

  17. List<Header>headers=msg.getHeaders();

  18. if(headers!=null&&headers.size()>0){

  19. Headerheader=headers.get(0);

  20. Elementele=(Element)header.getObject();

  21. NodeListuserIdList=ele.getElementsByTagName("userId");

  22. NodeListuserPassList=ele.getElementsByTagName("userPass");

  23. if(userIdList!=null&&userIdList.getLength()==1&&userPassList!=null&&userPassList.getLength()==1){

  24. StringuserId=userIdList.item(0).getTextContent();

  25. StringuserPass=userPassList.item(0).getTextContent();

  26. if(userId.equals("admin")&&userPass.equals("admin")){

  27. return;

  28. }

  29. }

  30. }

  31. thrownewFault(newException("驗證不經過"));

  32. }

  33. }

model層也就是數據庫實體層,這裏僅用於測試,並無連接數據庫

類cat

 
 
  1. packagecom.kenan.cxf.domain;

  2. publicclassCat{

  3. privateIntegerid;

  4. privateStringname;

  5. privateStringcolor;

  6. publicCat(){

  7. super();

  8. }

  9. publicCat(Integerid,Stringname,Stringcolor){

  10. super();

  11. this.id=id;

  12. this.name=name;

  13. this.color=color;

  14. }

  15. publicIntegergetId(){

  16. returnid;

  17. }

  18. publicvoidsetId(Integerid){

  19. this.id=id;

  20. }

  21. publicStringgetName(){

  22. returnname;

  23. }

  24. publicvoidsetName(Stringname){

  25. this.name=name;

  26. }

  27. publicStringgetColor(){

  28. returncolor;

  29. }

  30. publicvoidsetColor(Stringcolor){

  31. this.color=color;

  32. }

  33. @Override

  34. publicStringtoString(){

  35. return"Cat[id="+id+",name="+name+",color="+color+"]";

  36. }

  37. }

類User

 
 
  1. packagecom.kenan.cxf.domain;

  2. publicclassUser{

  3. privateIntegerid;

  4. privateStringname;

  5. privateStringpass;

  6. privateStringaddress;

  7. publicUser(){

  8. super();

  9. }

  10. publicUser(Integerid,Stringname,Stringpass,Stringaddress){

  11. super();

  12. this.id=id;

  13. this.name=name;

  14. this.pass=pass;

  15. this.address=address;

  16. }

  17. publicIntegergetId(){

  18. returnid;

  19. }

  20. publicvoidsetId(Integerid){

  21. this.id=id;

  22. }

  23. publicStringgetName(){

  24. returnname;

  25. }

  26. publicvoidsetName(Stringname){

  27. this.name=name;

  28. }

  29. publicStringgetPass(){

  30. returnpass;

  31. }

  32. publicvoidsetPass(Stringpass){

  33. this.pass=pass;

  34. }

  35. publicStringgetAddress(){

  36. returnaddress;

  37. }

  38. publicvoidsetAddress(Stringaddress){

  39. this.address=address;

  40. }

  41. @Override

  42. publicinthashCode(){

  43. finalintprime=31;

  44. intresult=1;

  45. result=prime*result+((name==null)?0:name.hashCode());

  46. result=prime*result+((pass==null)?0:pass.hashCode());

  47. returnresult;

  48. }

  49. @Override

  50. publicbooleanequals(Objectobj){

  51. if(this==obj)

  52. returntrue;

  53. if(obj==null)

  54. returnfalse;

  55. if(getClass()!=obj.getClass())

  56. returnfalse;

  57. Userother=(User)obj;

  58. if(name==null){

  59. if(other.name!=null)

  60. returnfalse;

  61. }elseif(!name.equals(other.name))

  62. returnfalse;

  63. if(pass==null){

  64. if(other.pass!=null)

  65. returnfalse;

  66. }elseif(!pass.equals(other.pass))

  67. returnfalse;

  68. returntrue;

  69. }

  70. }


websercie接口

 
 
  1. packagecom.kenan.cxf.ws;

  2. importjava.util.List;

  3. importjava.util.Map;

  4. importjavax.jws.WebService;

  5. importjavax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

  6. importcom.kenan.cxf.adapter.MapXmlAdapter;

  7. importcom.kenan.cxf.domain.Cat;

  8. importcom.kenan.cxf.domain.User;

  9. @WebService

  10. publicinterfaceHelloWorld{

  11. Stringhello(Stringname);

  12. List<Cat>getCatsByUser(Useruser);

  13. @XmlJavaTypeAdapter(value=MapXmlAdapter.class)Map<String,Cat>getAllCats();

  14. }

webservice接口實現類

 
 
  1. packagecom.kenan.cxf.ws.impl;

  2. importjava.util.ArrayList;

  3. importjava.util.HashMap;

  4. importjava.util.List;

  5. importjava.util.Map;

  6. importjavax.jws.WebService;

  7. importcom.kenan.cxf.domain.Cat;

  8. importcom.kenan.cxf.domain.User;

  9. importcom.kenan.cxf.ws.HelloWorld;

  10. @WebService(endpointInterface="com.kenan.cxf.ws.HelloWorld",

  11. serviceName="HelloWorldImpl")

  12. publicclassHelloWorldImplimplementsHelloWorld{

  13. @Override

  14. publicStringhello(Stringname){

  15. System.out.println("hello:"+name);

  16. returnname;

  17. }

  18. @Override

  19. publicList<Cat>getCatsByUser(Useruser){

  20. System.out.println(user.getName());

  21. Listlist=newArrayList();

  22. list.add(newCat(12,"sdf","sdf"));

  23. list.add(newCat(12,"2df","sdf"));

  24. list.add(newCat(12,"3df","sdf"));

  25. list.add(newCat(12,"4df","sdf"));

  26. list.add(newCat(12,"sdf","sdf"));

  27. returnlist;

  28. }

  29. @Override

  30. publicMap<String,Cat>getAllCats(){

  31. Map<String,Cat>m=newHashMap<String,Cat>();

  32. m.put("1",newCat(12,"2","34"));

  33. m.put("2",newCat(12,"2","34"));

  34. m.put("3",newCat(12,"2","34"));

  35. m.put("4",newCat(12,"2","34"));

  36. returnm;

  37. }

  38. }

發佈webservice

 
 
  1. packagecom.kenan.cxf.ws.impl;

  2. importstaticorg.junit.Assert.*;

  3. importjavax.xml.ws.Endpoint;

  4. importorg.apache.cxf.interceptor.LoggingInInterceptor;

  5. importorg.apache.cxf.interceptor.LoggingOutInterceptor;

  6. importorg.apache.cxf.jaxws.EndpointImpl;

  7. importcom.kenan.cxf.auth.AuthInterceptor;

  8. importcom.kenan.cxf.ws.HelloWorld;

  9. publicclassWSTest{

  10. publicstaticvoidmain(String[]args){

  11. HelloWorldhello=newHelloWorldImpl();

  12. EndpointImplep=(EndpointImpl)(Endpoint.publish("http://localhost:9999/hello",hello));

  13. //ep.getInInterceptors().add(newLoggingInInterceptor());

  14. //ep.getOutInterceptors().add(newLoggingOutInterceptor());

  15. ep.getInInterceptors().add(newAuthInterceptor());

  16. }

  17. }

客戶端

1,首先用sadl2java命令倒入須要的java代碼,而後開發本身的攔截器

2,攔截器,用戶實現權限認證

 
 
  1. packagecom.kenan.cxf.auth;

  2. importjava.util.List;

  3. importjavax.xml.namespace.QName;

  4. importorg.apache.cxf.binding.soap.SoapMessage;

  5. importorg.apache.cxf.headers.Header;

  6. importorg.apache.cxf.helpers.DOMUtils;

  7. importorg.apache.cxf.interceptor.Fault;

  8. importorg.apache.cxf.phase.AbstractPhaseInterceptor;

  9. importorg.apache.cxf.phase.Phase;

  10. importorg.w3c.dom.Document;

  11. importorg.w3c.dom.Element;

  12. publicclassAuthOutInterceptorextendsAbstractPhaseInterceptor<SoapMessage>{

  13. privateStringuserId;

  14. privateStringuserPass;

  15. publicAuthOutInterceptor(StringuserId,StringuserPass){

  16. super(Phase.PREPARE_SEND);//在消息發送前調用

  17. this.userId=userId;

  18. this.userPass=userPass;

  19. }

  20. @Override

  21. publicvoidhandleMessage(SoapMessagemsg)throwsFault{

  22. List<Header>headers=msg.getHeaders();

  23. Documentdoc=DOMUtils.createDocument();

  24. Elementele=doc.createElement("authHeader");

  25. ElementidEle=doc.createElement("userId");

  26. idEle.setTextContent(userId);

  27. ElementpassEle=doc.createElement("userPass");

  28. passEle.setTextContent(userPass);

  29. ele.appendChild(idEle);

  30. ele.appendChild(passEle);

  31. headers.add(newHeader(newQName("kenan"),ele));

  32. }

  33. }

客戶端webservcie調用

 
 
  1. packagetest;

  2. importjava.util.List;

  3. importorg.apache.cxf.endpoint.Client;

  4. importorg.apache.cxf.frontend.ClientProxy;

  5. importorg.apache.cxf.interceptor.LoggingOutInterceptor;

  6. importcom.kenan.cxf.auth.AuthOutInterceptor;

  7. importcom.kenan.cxf.ws.Cat;

  8. importcom.kenan.cxf.ws.Entry;

  9. importcom.kenan.cxf.ws.StringCat;

  10. importcom.kenan.cxf.ws.User;

  11. importcom.kenan.cxf.ws.impl.HelloWorldImpl;

  12. publicclassTest{

  13. /**

  14. *@paramargs

  15. */

  16. publicstaticvoidmain(String[]args){

  17. HelloWorldImplhelloWorld=newHelloWorldImpl();

  18. com.kenan.cxf.ws.HelloWorldhello=helloWorld.getHelloWorldImplPort();

  19. //攔截器

  20. Clientclient=ClientProxy.getClient(hello);

  21. client.getOutInterceptors().add(newAuthOutInterceptor("admin","admin"));

  22. client.getOutInterceptors().add(newLoggingOutInterceptor());

  23. hello.hello("你好");

  24. //Useruser=newUser();

  25. //user.setName("柯南");

  26. //List<Cat>l=hello.getCatsByUser(user);

  27. //for(Catcat:l){

  28. //System.out.println(cat.getName());

  29. //}

  30. //StringCats=hello.getAllCats();

  31. //for(Entryentry:s.getEntries()){

  32. //System.out.println(entry.getKey()+":"+entry.getValue());

  33. //}

  34. }

  35. }

相關文章
相關標籤/搜索