基于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. }