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
packagecom.kenan.cxf.adapter;程序員
importjava.util.HashMap;web
importjava.util.Map;數據庫
importjavax.xml.bind.annotation.adapters.XmlAdapter;apache
importcom.kenan.cxf.adapter.domain.StringCat;數組
importcom.kenan.cxf.adapter.domain.StringCat.Entry;tomcat
importcom.kenan.cxf.domain.Cat;服務器
publicclassMapXmlAdapterextendsXmlAdapter<StringCat,Map<String,Cat>>{網絡
@Override
publicMap<String,Cat>unmarshal(StringCatv)throwsException{
Map<String,Cat>m=newHashMap<String,Cat>();
for(Entryentry:v.getEntries()){
m.put(entry.getKey(),entry.getValue());
}
returnm;
}
@Override
publicStringCatmarshal(Map<String,Cat>v)throwsException{
StringCats=newStringCat();
for(Stringkey:v.keySet()){
Entrye=newEntry(key,v.get(key));
s.getEntries().add(e);
}
returns;
}
}
用戶map轉換器的實體
packagecom.kenan.cxf.adapter.domain;
importjava.util.ArrayList;
importjava.util.List;
importcom.kenan.cxf.domain.Cat;
publicclassStringCat{
publicstaticclassEntry{
privateStringkey;
privateCatvalue;
publicEntry(){
}
publicEntry(Stringkey,Catvalue){
super();
this.key=key;
this.value=value;
}
publicStringgetKey(){
returnkey;
}
publicvoidsetKey(Stringkey){
this.key=key;
}
publicCatgetValue(){
returnvalue;
}
publicvoidsetValue(Catvalue){
this.value=value;
}
}
privateList<Entry>entries=newArrayList<Entry>();
publicList<Entry>getEntries(){
returnentries;
}
publicvoidsetEntries(List<Entry>entries){
this.entries=entries;
}
}
進行權限驗證的過濾器:AuthInterceptor
packagecom.kenan.cxf.auth;
importjava.util.List;
importorg.apache.cxf.binding.soap.SoapMessage;
importorg.apache.cxf.headers.Header;
importorg.apache.cxf.interceptor.Fault;
importorg.apache.cxf.phase.AbstractPhaseInterceptor;
importorg.apache.cxf.phase.Phase;
importorg.w3c.dom.Element;
importorg.w3c.dom.NodeList;
publicclassAuthInterceptorextendsAbstractPhaseInterceptor<SoapMessage>{
publicAuthInterceptor(){
super(Phase.PRE_INVOKE);//在調用方法以前攔截
//TODOAuto-generatedconstructorstub
}
@Override
publicvoidhandleMessage(SoapMessagemsg)throwsFault{
List<Header>headers=msg.getHeaders();
if(headers!=null&&headers.size()>0){
Headerheader=headers.get(0);
Elementele=(Element)header.getObject();
NodeListuserIdList=ele.getElementsByTagName("userId");
NodeListuserPassList=ele.getElementsByTagName("userPass");
if(userIdList!=null&&userIdList.getLength()==1&&userPassList!=null&&userPassList.getLength()==1){
StringuserId=userIdList.item(0).getTextContent();
StringuserPass=userPassList.item(0).getTextContent();
if(userId.equals("admin")&&userPass.equals("admin")){
return;
}
}
}
thrownewFault(newException("驗證不經過"));
}
}
model層也就是數據庫實體層,這裏僅用於測試,並無連接數據庫
類cat
packagecom.kenan.cxf.domain;
publicclassCat{
privateIntegerid;
privateStringname;
privateStringcolor;
publicCat(){
super();
}
publicCat(Integerid,Stringname,Stringcolor){
super();
this.id=id;
this.name=name;
this.color=color;
}
publicIntegergetId(){
returnid;
}
publicvoidsetId(Integerid){
this.id=id;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicStringgetColor(){
returncolor;
}
publicvoidsetColor(Stringcolor){
this.color=color;
}
@Override
publicStringtoString(){
return"Cat[id="+id+",name="+name+",color="+color+"]";
}
}
類User
packagecom.kenan.cxf.domain;
publicclassUser{
privateIntegerid;
privateStringname;
privateStringpass;
privateStringaddress;
publicUser(){
super();
}
publicUser(Integerid,Stringname,Stringpass,Stringaddress){
super();
this.id=id;
this.name=name;
this.pass=pass;
this.address=address;
}
publicIntegergetId(){
returnid;
}
publicvoidsetId(Integerid){
this.id=id;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicStringgetPass(){
returnpass;
}
publicvoidsetPass(Stringpass){
this.pass=pass;
}
publicStringgetAddress(){
returnaddress;
}
publicvoidsetAddress(Stringaddress){
this.address=address;
}
@Override
publicinthashCode(){
finalintprime=31;
intresult=1;
result=prime*result+((name==null)?0:name.hashCode());
result=prime*result+((pass==null)?0:pass.hashCode());
returnresult;
}
@Override
publicbooleanequals(Objectobj){
if(this==obj)
returntrue;
if(obj==null)
returnfalse;
if(getClass()!=obj.getClass())
returnfalse;
Userother=(User)obj;
if(name==null){
if(other.name!=null)
returnfalse;
}elseif(!name.equals(other.name))
returnfalse;
if(pass==null){
if(other.pass!=null)
returnfalse;
}elseif(!pass.equals(other.pass))
returnfalse;
returntrue;
}
}
websercie接口
packagecom.kenan.cxf.ws;
importjava.util.List;
importjava.util.Map;
importjavax.jws.WebService;
importjavax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
importcom.kenan.cxf.adapter.MapXmlAdapter;
importcom.kenan.cxf.domain.Cat;
importcom.kenan.cxf.domain.User;
@WebService
publicinterfaceHelloWorld{
Stringhello(Stringname);
List<Cat>getCatsByUser(Useruser);
@XmlJavaTypeAdapter(value=MapXmlAdapter.class)Map<String,Cat>getAllCats();
}
webservice接口實現類
packagecom.kenan.cxf.ws.impl;
importjava.util.ArrayList;
importjava.util.HashMap;
importjava.util.List;
importjava.util.Map;
importjavax.jws.WebService;
importcom.kenan.cxf.domain.Cat;
importcom.kenan.cxf.domain.User;
importcom.kenan.cxf.ws.HelloWorld;
@WebService(endpointInterface="com.kenan.cxf.ws.HelloWorld",
serviceName="HelloWorldImpl")
publicclassHelloWorldImplimplementsHelloWorld{
@Override
publicStringhello(Stringname){
System.out.println("hello:"+name);
returnname;
}
@Override
publicList<Cat>getCatsByUser(Useruser){
System.out.println(user.getName());
Listlist=newArrayList();
list.add(newCat(12,"sdf","sdf"));
list.add(newCat(12,"2df","sdf"));
list.add(newCat(12,"3df","sdf"));
list.add(newCat(12,"4df","sdf"));
list.add(newCat(12,"sdf","sdf"));
returnlist;
}
@Override
publicMap<String,Cat>getAllCats(){
Map<String,Cat>m=newHashMap<String,Cat>();
m.put("1",newCat(12,"2","34"));
m.put("2",newCat(12,"2","34"));
m.put("3",newCat(12,"2","34"));
m.put("4",newCat(12,"2","34"));
returnm;
}
}
發佈webservice
packagecom.kenan.cxf.ws.impl;
importstaticorg.junit.Assert.*;
importjavax.xml.ws.Endpoint;
importorg.apache.cxf.interceptor.LoggingInInterceptor;
importorg.apache.cxf.interceptor.LoggingOutInterceptor;
importorg.apache.cxf.jaxws.EndpointImpl;
importcom.kenan.cxf.auth.AuthInterceptor;
importcom.kenan.cxf.ws.HelloWorld;
publicclassWSTest{
publicstaticvoidmain(String[]args){
HelloWorldhello=newHelloWorldImpl();
EndpointImplep=(EndpointImpl)(Endpoint.publish("http://localhost:9999/hello",hello));
//ep.getInInterceptors().add(newLoggingInInterceptor());
//ep.getOutInterceptors().add(newLoggingOutInterceptor());
ep.getInInterceptors().add(newAuthInterceptor());
}
}
客戶端
1,首先用sadl2java命令倒入須要的java代碼,而後開發本身的攔截器
2,攔截器,用戶實現權限認證
packagecom.kenan.cxf.auth;
importjava.util.List;
importjavax.xml.namespace.QName;
importorg.apache.cxf.binding.soap.SoapMessage;
importorg.apache.cxf.headers.Header;
importorg.apache.cxf.helpers.DOMUtils;
importorg.apache.cxf.interceptor.Fault;
importorg.apache.cxf.phase.AbstractPhaseInterceptor;
importorg.apache.cxf.phase.Phase;
importorg.w3c.dom.Document;
importorg.w3c.dom.Element;
publicclassAuthOutInterceptorextendsAbstractPhaseInterceptor<SoapMessage>{
privateStringuserId;
privateStringuserPass;
publicAuthOutInterceptor(StringuserId,StringuserPass){
super(Phase.PREPARE_SEND);//在消息發送前調用
this.userId=userId;
this.userPass=userPass;
}
@Override
publicvoidhandleMessage(SoapMessagemsg)throwsFault{
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.appendChild(idEle);
ele.appendChild(passEle);
headers.add(newHeader(newQName("kenan"),ele));
}
}
客戶端webservcie調用
packagetest;
importjava.util.List;
importorg.apache.cxf.endpoint.Client;
importorg.apache.cxf.frontend.ClientProxy;
importorg.apache.cxf.interceptor.LoggingOutInterceptor;
importcom.kenan.cxf.auth.AuthOutInterceptor;
importcom.kenan.cxf.ws.Cat;
importcom.kenan.cxf.ws.Entry;
importcom.kenan.cxf.ws.StringCat;
importcom.kenan.cxf.ws.User;
importcom.kenan.cxf.ws.impl.HelloWorldImpl;
publicclassTest{
/**
*@paramargs
*/
publicstaticvoidmain(String[]args){
HelloWorldImplhelloWorld=newHelloWorldImpl();
com.kenan.cxf.ws.HelloWorldhello=helloWorld.getHelloWorldImplPort();
//攔截器
Clientclient=ClientProxy.getClient(hello);
client.getOutInterceptors().add(newAuthOutInterceptor("admin","admin"));
client.getOutInterceptors().add(newLoggingOutInterceptor());
hello.hello("你好");
//Useruser=newUser();
//user.setName("柯南");
//List<Cat>l=hello.getCatsByUser(user);
//for(Catcat:l){
//System.out.println(cat.getName());
//}
//StringCats=hello.getAllCats();
//for(Entryentry:s.getEntries()){
//System.out.println(entry.getKey()+":"+entry.getValue());
//}
}
}