webservice cxf学习

转载:http://www.blogjava.net/hao446tian/archive/2012/01/04/367825.html

第一步:新建一个webservice接口 
html

@WebService  
public interface IHelloWorld {   
    //@WebParam给参数命名,提升可代码可读性。此项可选   
blic String sayHi(@WebParam(name="text") String text);   
}
  
java


经过注解@WebService申明为webservice接口 
   第二步,实现WebService接口 
程序员

 @WebService  
  public class HelloWorldImpl implements IHelloWorld {   
  
public String sayHi(String name) {   
    System.out.println("sayHello is called by " + name);   
    return "Hello " + name;   
}
   
  
   }
  
web


第三步,建立服务端spring

 public class Server {   
  
private Server(){   
    IHelloWorld helloWorld = new HelloWorldImpl();   
    //建立WebService服务工厂   
    JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();   
    //注册WebService接口   
    factory.setServiceClass(IHelloWorld.class);   
    //发布接口   
    factory.setAddress("http://localhost:9000/HelloWorld");   
    factory.setServiceBean(helloWorld);   
    //建立WebService   
    factory.create();   
}
;   
  
public static void main(String[] args) throws InterruptedException{   
       //启动服务端   
              new Server();   
    System.out.println("Server ready");   
    //休眠一分钟,便于测试   
               Thread.sleep(1000*60);   
    System.out.println("Server exit");   
    System.exit(0);   
}
   
   }
  
数据库


第四步,建立客户端 
apache

public class Client {   
  
private Client(){};   
  
public static void main(String[] args){   
    //建立WebService客户端代理工厂   
    JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();   
    //注册WebService接口   
    factory.setServiceClass(HelloWorld.class);   
    //设置WebService地址   
    factory.setAddress("http://localhost:9000/HelloWorld");        
    IHelloWorld iHelloWorld = (IHelloWorld)factory.create();   
    System.out.println("invoke webservice");   
    System.out.println("message context is:"+iHelloWorld.sayHi("     
                 Josen"));   
    System.exit(0);   
}
   
   }
   
编程


首先,运行服务端程序 
    其次,打开浏览器,在地址栏中输入http://localhost:9000/HelloWorld?wsdl(由于cxf自带了一个jetty服务器),查看接口是否发布成功,如里浏览器页面显示下面内容,证实接口发布成功 

本文所引用的资源主要包括两类,一类是Web服务的技术资源网站,包含了大量Web服务的技术信息,另外一类是Web服务“stack"系列技术规范,他们是一个总体的技术体系,包括UDDI、SOAP、WSDL、XML等。本文的最后给出了这些资源的连接,有兴趣的读者能够经过这些资源连接找到所需的内容。


其中,绿色部分是先前已经定义好的而且普遍使用的传输层和网络层的标准:IP、HTTP、SMTP等。而蓝色部分是目前开发的Web服务的相关标准协议,包括服务调用协议SOAP、服务描述协议WSDL和服务发现/集成协议UDDI,以及服务工做流描述语言WSFL。而橙色部分描述的是更高层的待开发的关于路由、可靠性以及事务等方面的协议。***部分是各个协议层的公用机制,这些机制通常由外部的正交机制来完成。 

其中,一个可使用的Web服务应当按照须要选用若干层次的功能,而无需全部的特性。可是不管如何为了实现一个通常意义上的Web服务,具有Web服务的基础特性:跨平台调用和接口可机器识别,那么必需使用WSDL和SOAP。SOAP是用来最终完成Web服务调用的,而WSDL则是用于描述如何使用 SOAP来调用Web服务的。 

    WSDL 是一种XML Application,他将Web服务描述定义为一组服务访问点,客户端能够经过这些服务访问点对包含面向文档信息或面向过程调用的服务进行访问(相似远程过程调用)。WSDL首先对访问的操做和访问时使用的请求/响应消息进行抽象描述,而后将其绑定到具体的传输协议和消息格式上以最终定义具体部署的服务访问点。相关的具体部署的服务访问点经过组合就成为抽象的Web服务。 

    在具体使用中,咱们能够对 WSDL 进行扩展(相似SOAP的可扩展性),这样不管通讯时使用何种消息格式或网络协议,均可以对服务访问点及其使用的消息格式进行描述。在WSDL的框架中,可使用任意的消息格式和网络协议,如同SOAP中可使用任意的网络协议同样。在WSDL规范中,定义了如何使用SOAP消息格式、HTTP GET/POST消息格式以及MIME格式来完成Web服务交互的规范。

WSDL 文档将Web服务定义为服务访问点或端口的集合。在 WSDL 中,因为服务访问点和消息的抽象定义已从具体的服务部署或数据格式绑定中分离出来,所以能够对抽象定义进行再次使用:消息,指对交换数据的抽象描述;而端口类型,指操做的抽象集合。用于特定端口类型的具体协议和数据格式规范构成了能够再次使用的绑定。将Web访问地址与可再次使用的绑定相关联,能够定义一个端口,而端口的集合则定义为服务。所以,WSDL 文档在Web服务的定义中使用下列元素: 
api

  * Types - 数据类型定义的容器,它使用某种类型系统(通常地使用XML Schema中的类型系统)。 
    * Message - 通讯消息的数据结构的抽象类型化定义。使用Types所定义的类型来定义整个消息的数据结构。 
    * Operation - 对服务中所支持的操做的抽象描述,通常单个Operation描述了一个访问入口的请求/响应消息对。 
    * PortType - 对于某个访问入口点类型所支持的操做的抽象集合,这些操做能够由一个或多个服务访问点来支持。 
    * Binding - 特定端口类型的具体协议和数据格式规范的绑定。 
    * Port - 定义为协议/数据格式绑定与具体Web访问地址组合的单个服务访问点。 
    * Service - 相关服务访问点的集合。 浏览器


你们能够参考下图,来理解一下WSDL文档的结构组织: 


其中,Types是一个数据类型定义的容器,包含了全部在消息定义中须要的XML元素的类型定义,我将在从此的文章中结合XML Schema来详细说明如何进行类型定义。 

    Message具体定义了在通讯中使用的消息的数据结构,Message元素包含了一组Part元素,每一个Part元素都是最终消息的一个组成部分,每一个 Part都会引用一个DataType来表示它的结构。Part元素不支持嵌套(可使用DataType来完成这方面的须要),都是并列出现。 

    PortType具体定义了一种服务访问入口的类型,何谓访问入口的类型呢?就是传入/传出消息的模式及其格式。一个PortType能够包含若干个 Operation,而一个Operation则是指访问入口支持的一种类型的调用。在WSDL里面支持四种访问入口调用的模式: 

   1. 单请求; 
   2. 单响应; 
   3. 请求/响应; 
   4. 响应/请求。 
在这里请求指的是从客户端到Web服务端,而响应指的是从Web服务端到客户端。PortType的定义中会引用消息定义部分的一个到两个消息,做为请求或响应消息的格式。好比,一个股票查询的访问入口可能就会支持两种请求消息,一种请求消息中指明股票代码,而另外一种请求消息中则会指明股票的名称,响应消息可能都是股票的价格等等。 

    以上三种结构描述了调用Web服务的抽象定义,这三部分与具体Web服务部署细节无关,是可复用的描述(每一个层次均可以复用)。若是与通常的对象语言作比较的话,这部分能够堪称是IDL描述的对象,描述了对象的接口标准,可是到底对象是用哪一种语言实现,听从哪一种平台的细节规范,被部署在哪台机器上则是后面的元素所描述的。 

    Service描述的是一个具体的被部署的Web服务所提供的全部访问入口的部署细节,一个Service每每会包含多个服务访问入口,而每一个访问入口都会使用一个Port元素来描述。 

    Port描述的是一个服务访问入口的部署细节,包括经过哪一个Web地址(URL)来访问,应当使用怎样的消息调用模式来访问等。其中消息调用模式则是使用Binding结构来表示。 

    Binding结构定义了某个PortType与某一种具体的网络传输协议或消息传输协议相绑定,从这一层次开始,描述的内容就与具体服务的部署相关了。好比能够将PortType与SOAP/HTTP绑定,也能够将PortType与MIME/SMTP相绑定等。 

    在介绍了WSDL的主要元素以后,你们会发现,WSDL的设计理念彻底继承了以XML为基础的当代Web技术标准的一向设计理念:开放。WSDL容许经过扩展使用其余的类型定义语言(不光是XML Schema),容许使用多种网络传输协议和消息格式(不光是在规范中定义的这些:SOAP/HTTP,HTTP-GET/POST以及MIME等)。同时WSDL也应用了当代软件工程中的复用理念,分离了抽象定义层和具体部署层,使得抽象定义层的复用性大大增长。好比咱们能够先使用抽象定义层为一类 Web服务进行抽象定义(好比UDDI Registry,抽象定义确定是彻底一致的遵循了UDDI规范),而不一样的运营公司能够采用不一样的具体部署层的描述结合抽象定义完成其自身的Web服务的描述。 
WSDL文档示例 
    下例是一个提供股票报价的简单Web服务的 WSDL 定义。该服务支持名为 GetLastTradePrice 的单一操做,这个操做是经过在 HTTP 上运行 SOAP 1.1 协议来实现的。该请求接受一个类型为字符串的 tickerSymbol,并返回类型为浮点数的价格。 

<?xml version="1.0"?>   
<definitions name="StockQuote"    
             targetNamespace="http://example.com/stockquote.wsdl"  
             xmlns:tns="http://example.com/stockquote.wsdl"  
             xmlns:xsd1="http://example.com/stockquote.xsd"  
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"  
             xmlns="http://schemas.xmlsoap.org/wsdl/">   
                
    
  <types>   
    <schema targetNamespace="http://example.com/stockquote.xsd"  
            xmlns="http://www.w3.org/1999/XMLSchema">   
      <element name="TradePriceRequest">   
        <complexType>   
          <all>   
            <element name="tickerSymbol" type="string"/>   
          </all>   
        </complexType>   
      </element>   
      <element name="TradePriceResult">   
        <complexType>   
          <all>   
            <element name="price" type="float"/>   
          </all>   
        </complexType>   
      </element>   
    </schema>   
  </types>  


上面这部分是数据类型的定义,其中为定义了两个元素的结构: 

    * TradePriceRequest(交易价格请求): 将该元素定义为包含一个字符串元素(tickerSymbol)的复合类型元素。 
    * TradePriceResult(交易价格): 将该元素定义为一个包含一个浮点数元素(price)的复合类型元素。 

message name="GetLastTradePriceInput">   
    <part name="body" element="xsd1:TradePriceRequest"/>   
  </message>   
    
  <message name="GetLastTradePriceOutput">   
    <part name="body" element="xsd1:TradePriceResult"/>   
  </message>  


这部分是消息格式的抽象定义,其中定义了两个消息格式: 

    * GetlastTradePriceInput(获取最后交易价格的请求消息格式): 由一个消息片段组成,该消息片段的名字是body,包含的具体元素类型是TradePriceRequest。(前面已经定义过了) 
    * GetLastTradePriceOutput(获取最后交易价格的响应消息格式) : 由一个消息片段组成,该消息片段的名字是body,包含的具体元素类型是TradePriceResult。(前面已经定义过了) 

<portType name="StockQuotePortType">   
   <operation name="GetLastTradePrice">   
     <input message="tns:GetLastTradePriceInput"/>   
     <output message="tns:GetLastTradePriceOutput"/>   
   </operation>   
 </portType>  


这部分定义了服务访问点的调用模式的类型,代表StockQuoteService的某个入口类型是请求/响应模式,请求消息是GetlastTradePriceInput,而响应消息是GetLastTradePriceOutput。 

binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType">   
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>   
      <operation name="GetLastTradePrice">   
        <soap:operation soapAction="http://example.com/GetLastTradePrice"/>   
          <input>   
            <soap:body use="literal" namespace="http://example.com/stockquote.xsd"  
                       encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>   
          </input>   
          <output>   
            <soap:body use="literal" namespace="http://example.com/stockquote.xsd"  
                       encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>   
          </output>   
        </soap:operation>   
      </operation>   
    </soap:binding>   
  </binding>  

 这部分将服务访问点的抽象定义与SOAP HTTP绑定,描述如何经过SOAP/HTTP来访问按照前面描述的访问入口点类型部署的访问入口。其中规定了在具体SOAP调用时,应当使用的 soapAction是"http://example.com/GetLastTradePrice",而请求/响应消息的编码风格都应当采用SOAP 规范默认定义的编码风格" http://schemas.xmlsoap.org/soap/encoding/"。 

<service name="StockQuoteService">   
    <documentation>股票查询服务</documentation>    
    <port name="StockQuotePort" binding="tns:StockQuoteBinding">   
    <soap:address location="http://example.com/stockquote"/>   
    </port>   
  </service>   
    
</definitions>  


这部分是具体的Web服务的定义,在这个名为StockQuoteService的Web服务中,提供了一个服务访问入口,访问地址是"http://example.com/stockquote",使用的消息模式是由前面的binding所定义的。 

    按照这个WSDL文档的描述,在具体Web服务的使用中,具体发生的SOAP交互可能以下面所示: 
SOAP消息请求: 

POST /StockQuote HTTP/1.1  
Host: example.com   
Content-Type: text/xml; charset="utf-8"  
Content-Length: nnnn   
SOAPAction: "http://example.com/GetLastTradePrice"  
  
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"  
                   SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">   
  <SOAP-ENV:Body>   
    <m:TradePriceRequest xmlns:m="http://example.com/stockquote.xsd">   
      <tickerSymbol>MSFT</tickerSymbol >   
    </m:TradePriceRequest>   
  </SOAP-ENV:Body>   
</SOAP-ENV:Envelope>  

SOAP消息响应: 

HTTP/1.1 200 OK   
Content-Type: text/xml; charset="utf-8"  
Content-Length: nnnn   
  
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"  
                   SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>   
  <SOAP-ENV:Body>   
    <m:TradePriceResult xmlns:m=" http://example.com/stockquote.xsd ">   
      <price>74.5</price>   
    </m:TradePriceResult >   
  </SOAP-ENV:Body>   
</SOAP-ENV:Envelope>  



    JAX-WS规范是一组XML web services的JAVA API。JAX-WS容许开发者能够选择RPC-oriented或者message-oriented 来实现本身的web services。 
  在 JAX-WS中,一个远程调用能够转换为一个基于XML的协议例如SOAP。在使用JAX-WS过程当中,开发者不须要编写任何生成和处理SOAP消息的代码。JAX-WS的运行时实现会将这些API的调用转换成为对于SOAP消息。 
  在服务器端,用户只须要经过Java语言定义远程调用所须要实现的接口SEI (service endpoint interface),并提供相关的实现,经过调用JAX-WS的服务发布接口就能够将其发布为WebService接口。 
  在客户端,用户能够经过JAX-WS的API建立一个代理(用本地对象来替代远程的服务)来实现对于远程服务器端的调用。 
  经过web service所提供的互操做环境,咱们能够用JAX-WS轻松实现JAVA平台与其余编程环境(.net等)的互操做。 

  JAX-WS工做原理以下图所示
  : 

前面几节都是讲一些理论知识,如今又用一个例子来讲明一下,这一节咱们就CXF框架对象传递进行讲解。 

  @XmlRootElement(name="Customer")   
   @XmlAccessorType(XmlAccessType.FIELD)   
   @XmlType(propOrder = {"name","age"})   
   public class Customer {   
  
private int age;   
private String name;   
  
public int getAge() {   
    return age;   
}
   
  
public void setAge(int age) {   
    this.age = age;   
}
   
  
public String getName() {   
    return name;   
}
   
  
public void setName(String name) {   
    this.name = name;   
}
   
  
   }
  

    @XmlRootElement-指定XML根元素名称(可选) 
   @XmlAccessorType-控制属性或方法序列化 

FIELD-对每一个非静态,非瞬变属性JAXB工具自动绑定成XML,除非注明XmlTransient 
    NONE-不作任何处理 
    PROPERTY-对具备set/get方法的属性进行绑定,除非注明XmlTransient 
    PUBLIC_MEMBER -对有set/get方法的属性或具备共公访问权限的属性进行绑定,除非注 
    明XmlTransient 
    @XmlType-映射一个类或一个枚举类型成一个XML Schema类型 



    @XmlType-映射一个类或一个枚举类型成一个XML Schema类型 
第二步:建立WebService接口

@WebService  
  public interface HelloService {   
  
public void save(Customer c1,Customer c2);   
  
public void test(String args);   
  
public Customer get(int id);   
 }
   


@WebService  
  public class HelloServiceImpl implements HelloService {   
  
public void save(Customer c1, Customer c2) {   
  
    System.out.println(c1.getAge()+"---"+c2.getAge());   
    System.out.println(c1.getName()+"---"+c2.getName());   
}
   
  
public void test(String args) {   
    System.out.println(args);   
       
}
   
  
public Customer get(int id) {   
    Customer cus = new Customer();   
    cus.setAge(100);   
    cus.setName("Josen");   
    return cus;   
}
   
    
}
   


第四步:建立服务端 

public class SoapServer {   
  
public static void main(String[] args){   
//两种方法,任选一种发布WebService接口   
              
//Endpoint.publish("http://localhost:8080/helloService", new    
               HelloServiceImpl());   
JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();   
factory.setAddress("http://localhost:8080/helloService");   
factory.setServiceClass(HelloServiceImpl.class);   
              factory.getInInterceptors().add(new LoggingInInterceptor());         
factory.getOutInterceptors().add(new LoggingOutInterceptor());   
factory.create();   
  
  }
   

第五步:建立客户端 


public class SoapClient {   
  
public static void main(String[] args){   
    JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();   
    factory.setAddress("http://localhost:8080/helloService");   
    factory.setServiceClass(HelloService.class);   
               factory.setServiceClass(HelloServiceImpl.class);   
               factory.getInInterceptors().add(new LoggingInInterceptor());   
    HelloService service = (HelloService)factory.create();   
       
    Customer c1 = new Customer();   
    c1.setAge(1);   
    c1.setName("aaa");   
       
    Customer c2 = new Customer();   
    c2.setAge(2);   
    c2.setName("bbb");   
       
    service.save(c1, c2);   
    service.test("aaaaaaaaaaaaa");   
}
   
 }
   

最后,测试程序 
  运行服务端程序,在浏览器地址栏输入http://localhost:8080/helloService?wsdl查看接口是否发布成功。成功则运行一下客户端程序,看看对象传输是否成功。 


如今咱们来分析一下控制打印的日志信息。 

信息: Inbound Message 
---------------------------- 
ID: 1 
Address: /HelloWorld 
Encoding: UTF-8 
Content-Type: text/xml; charset=UTF-8 
Headers: {content-type=[text/xml; charset=UTF-8], connection=[keep-alive], Host=[localhost:9000], Content-Length=[184], SOAPAction=[""], User-Agent=[Apache CXF 2.2.2], Content-Type=[text/xml; charset=UTF-8], Accept=[*/*], Pragma=[no-cache], Cache-Control=[no-cache]} 
Payload: <soap:Envelope xmlns:soap="
http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns1:say xmlns:ns1="http://client.itdcl.com/"><text> Josen</text></ns1:say></soap:Body></soap:Envelope> 
-------------------------------------- 
2010-1-9 20:41:56 org.apache.cxf.interceptor.LoggingOutInterceptor$LoggingCallback onClose 
信息: Outbound Message 
--------------------------- 
ID: 1 
Encoding: UTF-8 
Content-Type: text/xml 
Headers: {} 
Payload: <soap:Envelope xmlns:soap="
http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><text xmlns="http://client.itdcl.com/">hi Josen</text></soap:Header><soap:Body><ns1:sayResponse xmlns:ns1="http://client.itdcl.com/"></ns1:sayResponse></soap:Body></soap:Envelope> 
-------------------------------------- 
2010-01-09 20:41:56.578::INFO:  seeing JVM BUG(s) - cancelling interestOps==0 


 当客户端向服器发送请求时,服务端LoggingInInterceptor拉截客户端发送过来的SOAP消息,以下: 

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> 
<soap:Body> 
<ns1:sayHi xmlns:ns1="http://client.itdcl.com/"> 
<text>Josen</text> 
</ns1:sayHi> 
</soap:Body> 
</soap:Envelope> 

客户端将请求信息封闭在<soap:Body></soap:Body>中,固然也能够将其放到<soap:Header></soap:Header>,只要在@WebParam中的header设置成true,默认为false; 
     服务器接到请求以后,响应客户端。一样以SOAP形式将信息封装好发回客户端,SOAP信息以下:
 

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> 
<soap:Header> 
<text xmlns="http://client.itdcl.com/">hi Josen</text> 
</soap:Header> 
<soap:Body> 
<ns1:sayResponse xmlns:ns1="http://client.itdcl.com/"></ns1:sayResponse> 
</soap:Body> 
</soap:Envelope> 



前面几节咱们讲解对象传递,可是一般状况下咱们不直接传对象,由于直接传递对象安全性差,并且暴露了实体对象。因此咱们选择传递XML文件,固然也能够传递JSON对象。这节我只针对传递XML,那么JAVA绑定成XML,服务端将XML解析成Java对象有什么工具可用吗,其实这样的工具多的是。这里我选择一个比较简单的JAXB工具来说解一下。 
    JAXB(Java Architecture for XML Binding)提供了一个快速而方便的方式绑定XML Schemas和java,使java程序员可以很方便的在java应用程序中处理XML数据。JAXB提供了将XML文档解组为java内容树的方法,以及将java内容树从新编组回XML文档的方法。JAXB一样也提供了一种从java对象生成XML Schema的方式。 

里有几个重要的定义: 
    编组(Marshalling)是把内存中的数据转化到存储媒介上的过程。所以在 Java 和 XML 环境中,编组就是把一些 Java 对象转化成一个(或多个) XML 文档。在数据库环境中,则是把 Java 表示的数据存入数据库。显然,编组的秘密在于把 Java 实例中的面向对象结构转化成适用于 XML 的 扁平结构,或者 RDBMS 中的关系结构(使用 Java 技术转换到 OODBMS 实际上很简单)。工做原理以下图所示

解组(Unmarshalling) 是把数据从存储媒介转换到内存中的过程--正好与编组相反。所以须要把 XML 文档解组到 Java VM 中。这里的复杂性不是在扁平数据中,由于这不是必需的,而在于从正确的数据到正确的 Java 代码变量的映射。若是映射是错误的,就不可能正确地访问数据。固然,若是再尝试从新编组还会形成更大的问题,而且问题传播得很快。工做原理以下图所示: 


 往返(Round-tripping)多是最重要也最容易误解的数据绑定术语。往返用于描述从存储媒介到内存而后回到存储媒介的完整循 环。在 XML 和 Java 技术环境中,这就意味着从 XML 文档到 Java 实例变量,而后再回到 XML 文档。正确的往返要求,若是中间没有修改数据,XML 输入和 XML 输出应该是等同的。 
咱们还以例子来讲明它的工做原理,直观点。 
    第一步,建立一个Customer对象 

@XmlRootElement(name="customer")   
@XmlAccessorType(XmlAccessType.FIELD)   
@XmlType(name = "")   
public class Customer {   
  
    @XmlAttribute(required = true)   
    protected String name;   
    @XmlAttribute(required = true)   
    protected int age;   
  
    /**  
     * Gets the value of the name property.  
     *   
     * 
@return  
     *     possible object is  
     *     {
@link String }  
     *       
     
*/
  
    public String getName() {   
        return name;   
    }
   
  
    /**  
     * Sets the value of the name property.  
     *   
     * 
@param value  
     *     allowed object is  
     *     {
@link String }  
     *       
     
*/
  
    public void setName(String value) {   
        this.name = value;   
    }
   
  
    /**  
     * Gets the value of the age property.  
     *   
     
*/
  
    public int getAge() {   
        return age;   
    }
   
  
    /**  
     * Sets the value of the age property.  
     *   
     
*/
  
    public void setAge(int value) {   
        this.age = value;   
    }
   
  
}
   


第二步,建立一个测试类 

public class SoapClient {   
  
    private final static String MODEL = "com.itdcl.model";   
    public static void main(String[] args) throws ParserConfigurationException, JAXBException, TransformerException{   
  
           
        ObjectFactory factory = new ObjectFactory();   
        Customer customer = factory.createCustomer();   
        customer.setAge(20);   
        customer.setName("Josen");   
  
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();   
        dbf.setNamespaceAware(true);   
        DocumentBuilder db = dbf.newDocumentBuilder();   
        Document doc = db.newDocument();   
  
        JAXBContext jaxbContext = JAXBContext.newInstance(MODEL);   
        //Java对象转换成XML   
                Marshaller marshaller = jaxbContext.createMarshaller();   
        marshaller.marshal(customer, doc);   
           
        DOMSource domSource = new DOMSource(doc);   
        StringWriter writer = new StringWriter();   
        StreamResult result = new StreamResult(writer);   
        TransformerFactory tf = TransformerFactory.newInstance();   
        Transformer transformer = tf.newTransformer();   
        transformer.transform(domSource, result);   
        String xmlString = writer.toString();   
        System.out.println(xmlString);   
        //XML转换成Java对象   
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();   
        StringReader reader = new StringReader(xmlString);   
        Customer cus = (Customer)unmarshaller.unmarshal(reader);   
        System.out.println("Age:"+cus.getAge());   
        System.out.println("Name:"+cus.getName());   
           
           
    }
   
}
  



第三步,运行一个测试类,看看效果如何。Java与XML之间转换如此简单 
编组操做:利用上面生成的java文件执行编组操做。 

JAXBContext jaxbContext = JAXBContext.newInstance(MODEL);   
//Java对象转换成XML   
              Marshaller marshaller = jaxbContext.createMarshaller();   
marshaller.marshal(customer, doc);   
  
DOMSource domSource = new DOMSource(doc);   
StringWriter writer = new StringWriter();   
StreamResult result = new StreamResult(writer);   
TransformerFactory tf = TransformerFactory.newInstance();   
Transformer transformer = tf.newTransformer();   
transformer.transform(domSource, result);   
String xmlString = writer.toString();   
System.out.println(xmlString);  


解组操做:经过xml文件执行解组操做。

  JAXBContext jaxbContext = JAXBContext.newInstance(MODEL);   
              Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();   
StringReader reader = new StringReader(xmlString);   
Customer cus = (Customer)unmarshaller.unmarshal(reader);   
System.out.println("Age:"+cus.getAge());   
System.out.println("Name:"+cus.getName());  



整合Spring框架
首先,在前面基础上再导入几个spring要用到的几个.jar包: 
    spring-core.jar 
    spring-jdbc.jar 
    spring-context.jar 
    spring-orm.jar 
    spring-beans.jar 
    spring-tx.jar 
    包导入完以后,咱们还不能开如干活,配置几荐参数,便于下一步工做。 
    配置CXF框架 
    个人电脑->属性->高级->环境变量 
    建立一个CXF_HOEM变量,值为CXF框架所在根目录,修改一下 
    CLASSPATH=%CXF_HOME%/lib;PATH=%CXF_HOME%/bin;这时有会问为何要配置这两个参数据呢,其实配置这两个参数用途与配置JAVA变量一下,在DOS窗口下直接运行java2ws,wsdl2java等可执行文件。固然你没有配置也能够进到CXF框架的bin目录下远行这个几个可执行文件。 
   配置好了后,你在DOS窗口下输入java2ws,看看配置是否效。确定没有成功,缘由是使用6.0的JDK,咱们还得在%JAVA_HOME%/jre/lib目录下建立一下endorsed文件夹,将jaxb-api.jar,jaxws.jar拷贝进去。如今再运一下java2ws,成功运行,配置生效了。 
    基本工做作得差很少,整合spring框架正式开始: 
    第一步:新一个web project,导入要用到.jar包,其实CXF利用org.apache.cxf.transport.servlet.CXFServlet来拦截全部web请求,将其配置到web.xml中。配置以下: 

<web-app>   
    <context-param>   
        <param-name>contextConfigLocation</param-name>   
        <param-value>   
            /WEB-INF/classes/applicationContext-*.xml,/WEB-INF/classes/webservice.xml   
        </param-value>   
    </context-param>   
  
    <listener>   
        <listener-class>   
            org.springframework.web.context.ContextLoaderListener   
        </listener-class>   
    </listener>   
  
    [color=red]<servlet>   
        <servlet-name>CXFServlet</servlet-name>   
        <display-name>CXF Servlet</display-name>   
        <servlet-class>   
            org.apache.cxf.transport.servlet.CXFServlet   
        </servlet-class>   
        <load-on-startup>1</load-on-startup>   
    </servlet>   
  
    <servlet-mapping>   
        <servlet-name>CXFServlet</servlet-name>   
        <url-pattern>/*</url-pattern>   
    </servlet-mapping>[/color]   
</web-app>  


注意一下绿色字体 
      CXF框架配置好了,我就来开发一个WebService接口

@WebService   
     public interface IService {   
  
//public void save(@WebParam(name="info")String xml);   
public void save(@WebParam(name="dto")UserInfoDTO dto,@WebParam(name="flag")boolean flag);   
public void update(@WebParam(name="info")String xml);   
public void delete(@WebParam(name="id")int id);   
public @WebResult(name="String")String get(@WebParam(name="id")int id);   
    }
  


这里面有四个方法,其中有一个涉及到对象,这一点前面一节讲到怎么处理它。放在这里是再回顾前节内容。 
    建立一个WebService接口实现类 

 @WebService  
   public class ServiceImpl implements IService {   
private Logger log = LoggerFactory.getLogger(ServiceImpl.class);   
  
public void delete(int id) {   
    log.info("delete id is {} user"+id);   
}
   
  
public void save(UserInfoDTO dto,boolean flag) {   
    System.out.println("name:"+dto.getName());   
}
   
  
public void update(String xml) {   
}
   
  
public String get(int id){   
    return null;   
}
   
  }
   

因为本节只讲解与Spring整合,没有涉及到数据库,因就打印一下传递过来的对象内容来证实整合成功。与spring,hibernate整合后面章节会讲到,请留意后面章节。 
   传递对象,固然建立对象啦

 

@XmlType(name="ServerUserInfo")   
  @XmlAccessorType(XmlAccessType.FIELD)   
  public class UserInfoDTO implements java.io.Serializable {   
  
private static final long serialVersionUID = -4666026219400887433L;   
private Integer id;   
private String name;   
private Integer age;   
private Integer address;   
  
public Integer getId() {   
    return id;   
}
   
  
public void setId(Integer id) {   
    this.id = id;   
}
   
  
public String getName() {   
    return name;   
}
   
  
public void setName(String name) {   
    this.name = name;   
}
   
  
public Integer getAge() {   
    return age;   
}
   
  
public void setAge(Integer age) {   
    this.age = age;   
}
   
  
public Integer getAddress() {   
    return address;   
}
   
  
public void setAddress(Integer address) {   
    this.address = address;   
}
   
  
public UserInfoDTO() {   
}
   
  
   }
  

   作了这么多工做,有人又会问,怎么如今作的与spring框架就没一点联系,呵呵,确实是这样。开戏开场了,利用Spring来发布WebService接口:

<?xml version="1.0" encoding="UTF-8"?>   
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    [color=red]xmlns:jaxws="http://cxf.apache.org/jaxws"[/color]   
    xsi:schemaLocation="   
        http://www.springframework.org/schema/beans    
        http://www.springframework.org/schema/beans/spring-beans-2.0.xsd   
        http://cxf.apache.org/jaxws    
        http://cxf.apache.org/schemas/jaxws.xsd">   
    [color=red]   
        <!--导入与CXF框架有关的xml-->   
        <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" />[/color]   
  
        <!--布布WebService接口-->   
    <jaxws:endpoint id="service"  
        implementor="com.itdcl.service.ServiceImpl" address="/Service">   
           
    </jaxws:endpoint>   
</beans>  


服务端开发工做基本结束。如今打包部署到Tomcat6.0.18(本人目前使用的测试服务器,你固然可使用别的服务器) 
    服务器启动完成后,打开浏览器在地址栏中输入http://localhost:port/project name/Service?wsdl看看接口是否发成功。 
    接下来就是开发一个客户端了。 
    另建一个web project,如今前面的参数配置要起做用了,cmd进入DOS环境下输入wsdl2java -p com.itdcl.service(自定义包名) http://localhost:port/project name/Service?wsdl(前提是服务器没中止) 
    敲击Enter,wsdl2java工具帮你将发布出来的wsdl文件转换成webservice接口,到指定目录下将com.itdcl.service拷到刚才另建的web project的src目录下。 
    如今,咱们就来建立一个客户端程序: 

 public class SampleClient {   
  
ublic static void main(String[] args) {   
ApplicationContext context = new ClassPathXmlApplicationContext(   
        "beans.xml");   
     
 IService service = (IService)context.getBean("service");   
 ServerUserInfo userInfo = new ServerUserInfo();   
 userInfo.setAddress(1);   
 userInfo.setAge(100);   
 userInfo.setName("Jason");   
  
 service.save(userInfo,true);   
 service.delete(1);   
  
  
 }
  

看得仔细的朋友就会问了,ServerUserInfo 这个类那来的,你进到com.itdcl.service目录下就会看到,是WebService发布出来的。 
    到目前为止,客户端尚未完成,你没有看到程序中ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");这个bean.xml就是spring框架来注删除WebService接口的。好啦,建立一个bean.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"  
[color=red]xmlns:jaxws="http://cxf.apache.org/jaxws[/color]"  
xsi:schemaLocation="   
    http://www.springframework.org/schema/beans    
    http://www.springframework.org/schema/beans/spring-beans-2.0.xsd   
    [color=red]http://cxf.apache.org/jaxws    
    http://cxf.apache.org/schemas/jaxws.xsd[/color]">   
<jaxws:client id="service"  
    address="http://localhost:9999/cxf/Service"  
    serviceClass="com.itdcl.service.IService" />   
  </beans>  


这一节咱们来探讨一下WebService安全问题,若是全部系统都运行在一个封闭的局域网内,那么能够不考虑网络***,拒绝服务,消息篡改,窃取等问题。但一般状况都接入互联网,那么我就得考虑信息安全问题,像前面那样直接将消息裸传,确定不行。那么,咱们就得给消息加密。CXF能够结合WSS4J来对消息安全进行管理,可使用令牌,X.509认证对消息头或内容进行加密。这节我只对令牌加密作一个简单的描述,咱们还以Demo的形式来说解一下。 
    这个Demo是在CXF+Spring+Hibernate的基础修改而成。在这里我只针对修改的东西进行讲解。 

<?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"  
    xsi:schemaLocation="   
        http://www.springframework.org/schema/beans    
        http://www.springframework.org/schema/beans/spring-beans-2.0.xsd   
        http://cxf.apache.org/jaxws    
        http://cxf.apache.org/schemas/jaxws.xsd">   
    <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" />   
  
  
    <jaxws:endpoint id="service"  
        implementor="com.itdcl.service.ServiceImpl" address="/Service">   
        <jaxws:inInterceptors>   
            <bean   
                class="org.apache.cxf.interceptor.LoggingInInterceptor" />   
            <bean   
                class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" />   
            <bean   
                class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">   
                <constructor-arg>   
                    <map>   
                        <entry key="action" value="UsernameToken" />   
                        <entry key="passwordType"  
                            value="PasswordText" />   
                        <entry key="user" value="cxfServer" />   
                        <entry key="passwordCallbackRef">   
                            <ref bean="serverPasswordCallback" />   
                        </entry>   
                    </map>   
                </constructor-arg>   
            </bean>   
        </jaxws:inInterceptors>   
    </jaxws:endpoint>   
  
    <bean id="serverPasswordCallback"  
        class="com.itdcl.ws.ServerPasswordCallback" />   
  
</beans>  

action:UsernameToken指使用用户令牌 
    passwordType:PasswordText指密码加密策略,这里直接文本 
    user:cxfServer指别名 
    passwordCallBackRef:serverPasswordCallback指消息验证 

package com.itdcl.ws;   
  
import java.io.IOException;   
  
import javax.security.auth.callback.Callback;   
import javax.security.auth.callback.CallbackHandler;   
import javax.security.auth.callback.UnsupportedCallbackException;   
  
import org.apache.ws.security.WSPasswordCallback;   
  
public class ServerPasswordCallback implements CallbackHandler {   
  
    public void handle(Callback[] callbacks) throws IOException,   
            UnsupportedCallbackException {   
        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];   
        String pw = pc.getPassword();   
        String idf = pc.getIdentifier();   
        System.out.println("password:"+pw);   
        System.out.println("identifier:"+idf);   
        if (pw.equals("josen") && idf.equals("admin")) {   
            // 验证经过   
        }
 else {   
            throw new SecurityException("验证失败");   
        }
   
    }
   
  
}
  

消息验证类经过实现CallbackHandler接口,实现handle方法来进行用户认证。 
那么,客户端又怎样来验证消息是否确呢。 

<?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"  
    xsi:schemaLocation="   
        http://www.springframework.org/schema/beans    
        http://www.springframework.org/schema/beans/spring-beans-2.0.xsd   
        http://cxf.apache.org/jaxws    
        http://cxf.apache.org/schemas/jaxws.xsd">   
  
    <jaxws:client id="service"  
        address="http://localhost:9999/cxf/Service"  
        serviceClass="com.itdcl.service.IService">   
        <jaxws:outInterceptors>   
            <bean   
                class="org.apache.cxf.interceptor.LoggingOutInterceptor" />   
            <bean   
                class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />   
            <bean   
                class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">   
                <constructor-arg>   
                    <map>   
                        <entry key="action" value="UsernameToken" />   
                        <entry key="passwordType"  
                            value="PasswordText" />   
                        <entry key="user" value="cxfClient" />   
                        <entry key="passwordCallbackRef">   
                            <ref bean="clientPasswordCallback" />   
                        </entry>   
                    </map>   
                </constructor-arg>   
            </bean>   
        </jaxws:outInterceptors>   
    </jaxws:client>   
  
    <bean id="clientPasswordCallback"  
        class="com.itdcl.ws.ClientPasswordCallback" />   
</beans>  

客户端在发送SOAP时对消息对认证,策略跟服务端同样。可是认证类有所区别: 

package com.itdcl.ws;   
  
import java.io.IOException;   
  
import javax.security.auth.callback.Callback;   
import javax.security.auth.callback.CallbackHandler;   
import javax.security.auth.callback.UnsupportedCallbackException;   
  
import org.apache.ws.security.WSPasswordCallback;   
  
public class ClientPasswordCallback implements CallbackHandler {   
  
    public void handle(Callback[] callbacks) throws IOException,   
            UnsupportedCallbackException {   
        for(int i=0;i<callbacks.length;i++)   
        {   
             WSPasswordCallback pc = (WSPasswordCallback)callbacks[i];   
             pc.setPassword("josen");   
             pc.setIdentifier("admin");   
        }
   
    }
   
  
}
  

客户端在发送消息,设置好用户名和密码。服务端用相应的用户名和密码进行验证。      令牌验证就如此简单。