基于cxf实现的webservice,全程开发指南和笔记,以及代码

SOA(面向服务的架构)
Service1,Service2,Service3 --  所有组件都是“即插即用”的

IBM提倡的SOA架构,希望以“组装电脑”的方式来开发软件。
1,各种提供服务的组件。
2,企业服务总线(Enterprise Service Bus,ESB)

CXF号称是SOA框架

CXF(Apache)

cxf框架的使用
1,下载cxf
2,配置cxf下bin的path环境变量
3,测试环境变量是否配置正确

cxf框架目录介绍
/bin 常用命令
/doc 开发文档
/lib  jar包

cxf内置了一个Jetty Web服务器
(tomcat的开发者就是java ee规范的制定者)
使用cxf开发web service服务端
    1,开发一个webservice接口
        加上@WebService注释
    2,开发实现类
        加上@WebService()注释
        加上属性 endpointInterface="com.kenan.cxf.HelloWorld"指定实现的接口
        serviceName=“HelloworldService”
    3,加入jar包
        cxf
        servlet 3.0
        jetty-* (Jetty Web服务器)
        asm
        common-logging
        neethi
        xmlschema-core
        wsdl4j
    4,创建测试类,发布ws(需要在main方法中)
        HelloWorld hw = new HImpl();
        Endpoint.publish("http://localhost:9999/hello",hw);
    5,访问http://localhost/hello?wsdl

使用cxf开发web service客户端
    1,使用wsdl2java  将服务端暴露的wsdl文档转换为java代码
    2,找到实现了service接口的类 ,该类可以当成工厂来使用
        HelloWorldImpl fac = new ();
    3,生产 HelloWorld hello = fac.getHelloWorldWsPort();
        调用远程方法
        hello.say("sdf");

1,当形参,返回值为String的时候,cxf可以轻松的处理
2,当形参返回值类型为javabean的复合类,List集合,数组 ,cxf也可以很好的处理

wsdl介绍
wsdl :  web service data language
wsdl是一个xml文档
xml中的两个属性
targetNamespace  (规定自己这个文档的命名空间)  相当于java中的包名
xmlns    (命名空间:xml namespace) 相当于java中要引入的

WSDL文档
    1,WebService接口

一次web service的调用,其实不是方法调用,而是发送SOAP消息(xml文档片段)
    要调用的方法,和传入的参数都写在xml文档中,也就是一个SOAP消息

SOAP simple object access proto 简单对象协议
调用一次web service的本质
    1,客户端把要调用方法参数,转换成xml文档片段(SOAP消息),该文档必须符合wsdl文档规范
    2,通过网络,把xml文档传给服务器
    3,服务器接受到xml文档
    4,服务器解析xml文档片段,提取其中的数据。
        并把数据转换调用web service所需要的参数类型
    5,服务器执行方法
    6,把执行方法得到的返回值,再次转换成xml文档片段
    7,通过网络,把xml文档片段传给客户端
    8,客户端接受到XML文档
    9,客户端解析到XML文档,提取其中的数据
        并把数据转换成调用web service的返回值
       
从上面调用的本质来看,要一个语言支持web service
唯一的要求是,该语言支持xml文档解析,声称,支持网络传输


如果遇到cxf无法转换的类型,就需要我们自定义转换
如对于map对象
    1,使用@XmlJavaTypeAdapter注释无法处理的类型
        通过(value=)XmlAdapter指定一个转换器
        转换器在这里就可以把cxf搞不定的类型搞定
    2,实现自己的转换器,开发一个cxf搞得定的类型 需要实现XmlAdapter抽象类
        这里有两个参数,第一个是搞得定的类型
                第二个是搞不定的类型
        extends XmlAdapter<StringCat,Map<string,Cat>>

SOAP协议:简单对象传输协议
传入消息:
header:默认情况下,header元素不是强制出现的,header元素
有程序员控制添加,主要用于携带一些额外的信息
2013-1-28 22:13:26 org.apache.cxf.services.HelloWorldImpl.HelloWorldImplPort.HelloWorld
信息: Inbound Message
----------------------------
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, image/gif, image/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:
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:hello xmlns:ns2="http://ws.cxf.kenan.com/">
<arg0>你好</arg0>
</ns2:hello>
</S:Body>
</S:Envelope>
--------------------------------------

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

web service急需解决的问题:如何收钱?
            --如何进行权限控制?
为了进行权限控制,需要:
    客户端发送soap消息的时候,必须携带用户名和密码信息
        如果没有,或者不正确,拒绝调用

拦截器   
    为了让程序员放访问,并修改cxf声称的xml文档,cxf提供的拦截器
    分为In拦截器
        Out拦截器
服务器端添加拦截器:
    1,在发布的时候
        EndPointImpl ep = En...publish();
        添加in拦截器
        ep.getInInterceptors().add(e);
        添加out拦截器
        ep.getOutInterceptors().add(e);
    2,系统的拦截器
        这个是日志的拦截器
        new LoggingInInterceptor();(默认输出到控制台)
        new LoggingOutInterceprot();
    3,创建自定义拦截器需要实现Interceptor
        一般我们会继承AbstractPhaseInterceptor

客户端添加拦截器

    1,倒入jar包(zxf。。。)
    2,Client client = ClientProxy.getClient(hi);
        hi为webserice 接口类对象
        client.getInInterceptors().add();

自定义拦截器
    1,继承AbstractPhaseInterceptor
        extends AbstractPhaseInterceptor<SoapMessage>
    2,实现handlMessage方法
        这个方法中的形参就是被拦截到的soap消息
        解析soap消息,或者修改soap消息
    3,写构造函数,显式调用父类构造函数,程序将不会隐式调用父类无参数的构造函数
        super(Phase.PRE_INVOKE) 在调用之前  拦截soap消息
    4,消息处理
        参数SoapMessage msg
        System.our.println(msg);
        List<Header> headers = msg.getHeaders();
        if(headers!=null&&headers.size()>0){
            //加入要求第一个header存放用户名和密码
            Header h = headers.get(0);
            Element ele = (Element)h.getObject();
            NodeList userIds = ele.getElementsByTagName("userId");
            NodeList userPasses = ele.getElementsByTagName("userPass");

            if(userIds.getLength==1&&userPasses.getLength()==1){
                String userId = userIds.item)0).getTextContent();
                String userPass = userPasses.item(0).getTextContent();
                if(){
                    //验证通过
                    return ;
                }
            }
        }
自定义客户端的OutInterceptor
    1,同上
    2,构造器
        public Constructor(String userId,String userPass){
            super(Phase.PREPARE_SEND);//在发送soap消息之前调用该拦截器
            this.userId=
            this.userPass..
        }
    3,HandleMessage
        List<Header> headers = msg.getHeaders();
        Document doc = DOMUtils.createDocument();
        Element ele = doc.createElement("authHeader");
        Element idEle = doc.createElement("userId");
        idEle.setTextContent(userId);
        Element passEle = doc.createElement("userPass");
        passEle.setTextContent(userPass);
       
        ele.appenChild(idEle);
        ele.appenChild(passEle);
        生成如下文档
            <authHeader>
                <userId></userId>
                <userPass></userPass>
            </authHeader>
        //把ele元素包装成header,并添加到soap消息中
        Header header = new Header(new QName("qname"),ele);
        headers.add(header);

客户端利用拦截器在发功的soap消息中写入数据后的消息
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<authHeader>
<userId>23</userId>
<userPass>sdr</userPass>
</authHeader>
</soap:Header>
<soap:Body>
<ns2:hello xmlns:ns2="http://ws.cxf.kenan.com/">
<arg0>你好</arg0></ns2:hello
></soap:Body>
</soap:Envelope>

服务器端代码:

转换器 :用于转换Map数据类型

 
 
  1. package com.kenan.cxf.adapter; 
  2.  
  3. import java.util.HashMap; 
  4. import java.util.Map; 
  5.  
  6. import javax.xml.bind.annotation.adapters.XmlAdapter; 
  7.  
  8. import com.kenan.cxf.adapter.domain.StringCat; 
  9. import com.kenan.cxf.adapter.domain.StringCat.Entry; 
  10. import com.kenan.cxf.domain.Cat; 
  11.  
  12. public class MapXmlAdapter extends XmlAdapter<StringCat, Map<String,Cat>> { 
  13.  
  14.     @Override 
  15.     public Map<String, Cat> unmarshal(StringCat v) throws Exception { 
  16.         Map<String,Cat> m = new HashMap<String,Cat>(); 
  17.         for(Entry entry:v.getEntries()){ 
  18.             m.put(entry.getKey(), entry.getValue()); 
  19.         } 
  20.         return m ; 
  21.     } 
  22.  
  23.     @Override 
  24.     public StringCat marshal(Map<String, Cat> v) throws Exception { 
  25.         StringCat s = new StringCat(); 
  26.         for(String key:v.keySet()){ 
  27.             Entry e = new Entry(key,v.get(key)); 
  28.             s.getEntries().add(e); 
  29.         } 
  30.         return s; 
  31.     } 
  32.  


          用户map转换器的实体

 
 
  1. package com.kenan.cxf.adapter.domain; 
  2.  
  3. import java.util.ArrayList; 
  4. import java.util.List; 
  5.  
  6. import com.kenan.cxf.domain.Cat; 
  7.  
  8. public class StringCat { 
  9.     public static class Entry{ 
  10.         private String key; 
  11.         private Cat value; 
  12.         public Entry(){ 
  13.         } 
  14.         public Entry(String key, Cat value) { 
  15.             super(); 
  16.             this.key = key; 
  17.             this.value = value; 
  18.         } 
  19.         public String getKey() { 
  20.             return key; 
  21.         } 
  22.         public void setKey(String key) { 
  23.             this.key = key; 
  24.         } 
  25.         public Cat getValue() { 
  26.             return value; 
  27.         } 
  28.         public void setValue(Cat value) { 
  29.             this.value = value; 
  30.         } 
  31.          
  32.     } 
  33.     private List<Entry> entries = new ArrayList<Entry>(); 
  34.     public List<Entry> getEntries() { 
  35.         return entries; 
  36.     } 
  37.     public void setEntries(List<Entry> entries) { 
  38.         this.entries = entries; 
  39.     } 


进行权限验证的过滤器:AuthInterceptor

 
 
  1. package com.kenan.cxf.auth; 
  2.  
  3. import java.util.List; 
  4.  
  5.  
  6. import org.apache.cxf.binding.soap.SoapMessage; 
  7. import org.apache.cxf.headers.Header; 
  8. import org.apache.cxf.interceptor.Fault; 
  9. import org.apache.cxf.phase.AbstractPhaseInterceptor; 
  10. import org.apache.cxf.phase.Phase; 
  11. import org.w3c.dom.Element; 
  12. import org.w3c.dom.NodeList; 
  13.  
  14. public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> { 
  15.  
  16.     public AuthInterceptor() { 
  17.         super(Phase.PRE_INVOKE);  //在调用方法之前  拦截 
  18.         // TODO Auto-generated constructor stub 
  19.     } 
  20.  
  21.     @Override 
  22.     public void handleMessage(SoapMessage msg) throws Fault { 
  23.         List<Header> headers = msg.getHeaders(); 
  24.         if(headers!=null&&headers.size()>0){ 
  25.             Header header = headers.get(0); 
  26.             Element ele = (Element) header.getObject(); 
  27.             NodeList userIdList = ele.getElementsByTagName("userId"); 
  28.             NodeList userPassList = ele.getElementsByTagName("userPass"); 
  29.             if(userIdList!=null && userIdList.getLength()==1 && userPassList!=null && userPassList.getLength() == 1){ 
  30.                 String userId = userIdList.item(0).getTextContent(); 
  31.                 String userPass = userPassList.item(0).getTextContent(); 
  32.                 if(userId.equals("admin")&&userPass.equals("admin")){ 
  33.                     return ; 
  34.                 } 
  35.             } 
  36.         } 
  37.         throw new Fault(new Exception("验证不通过")); 
  38.     } 
  39.  

model层也就是数据库实体层,这里仅用于测试,并没有链接数据库

类cat

 
 
  1. package com.kenan.cxf.domain; 
  2.  
  3. public class Cat { 
  4.     private Integer id; 
  5.     private String name; 
  6.     private String color; 
  7.      
  8.      
  9.     public Cat() { 
  10.         super(); 
  11.     } 
  12.     public Cat(Integer id, String name, String color) { 
  13.         super(); 
  14.         this.id = id; 
  15.         this.name = name; 
  16.         this.color = color; 
  17.     } 
  18.     public Integer getId() { 
  19.         return id; 
  20.     } 
  21.     public void setId(Integer id) { 
  22.         this.id = id; 
  23.     } 
  24.     public String getName() { 
  25.         return name; 
  26.     } 
  27.     public void setName(String name) { 
  28.         this.name = name; 
  29.     } 
  30.     public String getColor() { 
  31.         return color; 
  32.     } 
  33.     public void setColor(String color) { 
  34.         this.color = color; 
  35.     } 
  36.     @Override 
  37.     public String toString() { 
  38.         return "Cat [id=" + id + "name=" + name + "color=" + color + "]"; 
  39.     } 
  40.      

类User

 
 
  1. package com.kenan.cxf.domain; 
  2.  
  3. public class User { 
  4.     private Integer id; 
  5.     private String name; 
  6.     private String pass; 
  7.     private String address; 
  8.      
  9.      
  10.     public User() { 
  11.         super(); 
  12.     } 
  13.     public User(Integer id, String name, String pass, String address) { 
  14.         super(); 
  15.         this.id = id; 
  16.         this.name = name; 
  17.         this.pass = pass; 
  18.         this.address = address; 
  19.     } 
  20.     public Integer getId() { 
  21.         return id; 
  22.     } 
  23.     public void setId(Integer id) { 
  24.         this.id = id; 
  25.     } 
  26.     public String getName() { 
  27.         return name; 
  28.     } 
  29.     public void setName(String name) { 
  30.         this.name = name; 
  31.     } 
  32.     public String getPass() { 
  33.         return pass; 
  34.     } 
  35.     public void setPass(String pass) { 
  36.         this.pass = pass; 
  37.     } 
  38.     public String getAddress() { 
  39.         return address; 
  40.     } 
  41.     public void setAddress(String address) { 
  42.         this.address = address; 
  43.     } 
  44.     @Override 
  45.     public int hashCode() { 
  46.         final int prime = 31
  47.         int result = 1
  48.         result = prime * result + ((name == null) ? 0 : name.hashCode()); 
  49.         result = prime * result + ((pass == null) ? 0 : pass.hashCode()); 
  50.         return result; 
  51.     } 
  52.     @Override 
  53.     public boolean equals(Object obj) { 
  54.         if (this == obj) 
  55.             return true
  56.         if (obj == null
  57.             return false
  58.         if (getClass() != obj.getClass()) 
  59.             return false
  60.         User other = (User) obj; 
  61.         if (name == null) { 
  62.             if (other.name != null
  63.                 return false
  64.         } else if (!name.equals(other.name)) 
  65.             return false
  66.         if (pass == null) { 
  67.             if (other.pass != null
  68.                 return false
  69.         } else if (!pass.equals(other.pass)) 
  70.             return false
  71.         return true
  72.     } 
  73.      


web sercie接口

 
 
  1. package com.kenan.cxf.ws; 
  2.  
  3. import java.util.List; 
  4. import java.util.Map; 
  5.  
  6. import javax.jws.WebService; 
  7. import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 
  8.  
  9. import com.kenan.cxf.adapter.MapXmlAdapter; 
  10. import com.kenan.cxf.domain.Cat; 
  11. import com.kenan.cxf.domain.User; 
  12.  
  13. @WebService 
  14. public interface HelloWorld { 
  15.     String hello(String name); 
  16.     List<Cat> getCatsByUser(User user); 
  17.     @XmlJavaTypeAdapter(value = MapXmlAdapter.class) Map<String,Cat> getAllCats(); 

web service接口实现类

 
 
  1. package com.kenan.cxf.ws.impl; 
  2.  
  3. import java.util.ArrayList; 
  4. import java.util.HashMap; 
  5. import java.util.List; 
  6. import java.util.Map; 
  7.  
  8. import javax.jws.WebService; 
  9.  
  10. import com.kenan.cxf.domain.Cat; 
  11. import com.kenan.cxf.domain.User; 
  12. import com.kenan.cxf.ws.HelloWorld; 
  13.  
  14. @WebService(endpointInterface="com.kenan.cxf.ws.HelloWorld"
  15.                         serviceName="HelloWorldImpl"
  16. public class HelloWorldImpl implements HelloWorld{ 
  17.  
  18.     @Override 
  19.     public String hello(String name) { 
  20.         System.out.println("hello:"+name); 
  21.         return name; 
  22.     } 
  23.  
  24.     @Override 
  25.     public List<Cat> getCatsByUser(User user) { 
  26.         System.out.println(user.getName()); 
  27.         List list = new ArrayList(); 
  28.         list.add(new Cat(12,"sdf","sdf")); 
  29.         list.add(new Cat(12,"2df","sdf")); 
  30.         list.add(new Cat(12,"3df","sdf")); 
  31.         list.add(new Cat(12,"4df","sdf")); 
  32.         list.add(new Cat(12,"sdf","sdf")); 
  33.         return list; 
  34.     } 
  35.  
  36.     @Override 
  37.     public Map<String, Cat> getAllCats() { 
  38.         Map<String,Cat> m = new HashMap<String,Cat>(); 
  39.         m.put("1"new Cat(12,"2","34")); 
  40.         m.put("2"new Cat(12,"2","34")); 
  41.         m.put("3"new Cat(12,"2","34")); 
  42.         m.put("4"new Cat(12,"2","34")); 
  43.         return m; 
  44.     } 
  45.  

发布web service

 
 
  1. package com.kenan.cxf.ws.impl; 
  2.  
  3. import static org.junit.Assert.*; 
  4.  
  5. import javax.xml.ws.Endpoint; 
  6.  
  7. import org.apache.cxf.interceptor.LoggingInInterceptor; 
  8. import org.apache.cxf.interceptor.LoggingOutInterceptor; 
  9. import org.apache.cxf.jaxws.EndpointImpl; 
  10.  
  11.  
  12.  
  13. import com.kenan.cxf.auth.AuthInterceptor; 
  14. import com.kenan.cxf.ws.HelloWorld; 
  15.  
  16. public class WSTest { 
  17.  
  18.     public static void main(String[] args) { 
  19.         HelloWorld hello = new HelloWorldImpl(); 
  20.         EndpointImpl ep = (EndpointImpl)(Endpoint.publish("http://localhost:9999/hello", hello)); 
  21. //      ep.getInInterceptors().add(new LoggingInInterceptor()); 
  22. //      ep.getOutInterceptors().add(new LoggingOutInterceptor()); 
  23.          
  24.         ep.getInInterceptors().add(new AuthInterceptor()); 
  25.     } 
  26.  

客户端

1,首先用sadl2java命令倒入需要的java代码,然后开发自己的拦截器

2,拦截器,用户实现权限认证

 
 
  1. package com.kenan.cxf.auth; 
  2.  
  3. import java.util.List; 
  4.  
  5. import javax.xml.namespace.QName; 
  6.  
  7. import org.apache.cxf.binding.soap.SoapMessage; 
  8. import org.apache.cxf.headers.Header; 
  9. import org.apache.cxf.helpers.DOMUtils; 
  10. import org.apache.cxf.interceptor.Fault; 
  11. import org.apache.cxf.phase.AbstractPhaseInterceptor; 
  12. import org.apache.cxf.phase.Phase; 
  13. import org.w3c.dom.Document; 
  14. import org.w3c.dom.Element; 
  15.  
  16. public class AuthOutInterceptor extends AbstractPhaseInterceptor<SoapMessage> { 
  17.  
  18.     private String userId; 
  19.     private String userPass; 
  20.          
  21.     public AuthOutInterceptor(String userId, String userPass) { 
  22.         super(Phase.PREPARE_SEND);//在消息发送前调用 
  23.         this.userId = userId; 
  24.         this.userPass = userPass; 
  25.     } 
  26.  
  27.     @Override 
  28.     public void handleMessage(SoapMessage msg) throws Fault { 
  29.         List<Header> headers = msg.getHeaders(); 
  30.         Document doc = DOMUtils.createDocument(); 
  31.         Element ele = doc.createElement("authHeader"); 
  32.         Element idEle = doc.createElement("userId"); 
  33.         idEle.setTextContent(userId); 
  34.         Element passEle = doc.createElement("userPass"); 
  35.         passEle.setTextContent(userPass); 
  36.         ele.appendChild(idEle); 
  37.         ele.appendChild(passEle); 
  38.         headers.add(new Header(new QName("kenan"), ele)); 
  39.     } 
  40.  

客户端web servcie调用

 
 
  1. package test; 
  2.  
  3. import java.util.List; 
  4.  
  5. import org.apache.cxf.endpoint.Client; 
  6. import org.apache.cxf.frontend.ClientProxy; 
  7. import org.apache.cxf.interceptor.LoggingOutInterceptor; 
  8.  
  9. import com.kenan.cxf.auth.AuthOutInterceptor; 
  10. import com.kenan.cxf.ws.Cat; 
  11. import com.kenan.cxf.ws.Entry; 
  12. import com.kenan.cxf.ws.StringCat; 
  13. import com.kenan.cxf.ws.User; 
  14. import com.kenan.cxf.ws.impl.HelloWorldImpl; 
  15.  
  16. public class Test { 
  17.  
  18.     /** 
  19.      * @param args 
  20.      */ 
  21.     public static void main(String[] args) { 
  22.         HelloWorldImpl helloWorld = new HelloWorldImpl(); 
  23.         com.kenan.cxf.ws.HelloWorld hello = helloWorld.getHelloWorldImplPort(); 
  24.          
  25.         //拦截器 
  26.         Client client = ClientProxy.getClient(hello); 
  27.         client.getOutInterceptors().add(new AuthOutInterceptor("admin", "admin")); 
  28.         client.getOutInterceptors().add(new LoggingOutInterceptor()); 
  29.          
  30.         hello.hello("你好"); 
  31.          
  32.          
  33.          
  34. //      User user = new User(); 
  35. //      user.setName("柯南"); 
  36. //      List<Cat> l = hello.getCatsByUser(user); 
  37. //      for(Cat cat:l){ 
  38. //          System.out.println(cat.getName()); 
  39. //      } 
  40. //      StringCat s = hello.getAllCats(); 
  41. //      for(Entry entry:s.getEntries()){ 
  42. //          System.out.println(entry.getKey()+":"+entry.getValue()); 
  43. //      } 
  44.     } 
  45.  

 

本文出自 “Kenan_ITBlog” 博客,请务必保留此出处http://soukenan.blog.51cto.com/5130995/1128378

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值