<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Java遠程通信技術——Axis實戰

    前言

    在 Internet 網絡覆蓋全球的今天,網絡通信已經是當今軟件開發過程中離不開的話題。在常用的Windows、Liunx、Unix 系統當中,大部分的網絡數據傳輸都是使用 TCP/IP、UDP/IP 作為底層傳輸協議的,而 HTTP 協議就是基于 TCP/IP 協議而運行的超文本傳送協議。
    在 JAVA 高級開發語言中,陸續出現 RMI、CORBA、JAX-RPC、JAX-WS、Axis、XFire、HTTP Invoker、Hessian、Burlap、JMX 等遠程通信架構去實現系統之間數據傳送。在 “遠程通信技術” 的一系列文章中,本人將對上述復雜的 JAVA 遠程通信技術作出歸納。
    首先,在本篇文章中先對有著10多年歷史的 Axis 進行介紹。

     

    目錄

    一、Axis 簡介

    二、Axis 1.x 實例

    三、Web 服務會話管理

    四、自定義Handler

    五、新一代 SOAP 引擎 Axis 2.x

    六、AXIOM 對象模型

    七、Module 模塊獨立化處理方式

    八、異步調用Web服務

     

     


    一、Axis 簡介

    1.1 Web 服務的起源

    Web 服務是現今實現網絡服務概念的趨勢,它把基礎架構建立于標準化的XML語言之上,能夠使用一種與平臺無關的方式對數據進行編碼,其中 SOAP 與 WSDL 都遵從此標準化的 XML 編碼規則。
    SOAP (Simple Object Access Protocol,簡單對象訪問協議)是一種輕量的、簡單的、基于 XML 的協議,用于描述在服務過程中服務器端與客戶端之間所交換的消息。 SOAP 可以和現存的許多因特網協議和格式結合使用,包括超文本傳輸協議( HTTP),簡單郵件傳輸協議(SMTP),多用途網際郵件擴充協議(MIME)。
    WSDL (Web Service Definition Language,Web服務描述語言)是一種基于 XML的協議,用于定義服務端與客戶端之間的契約,描述Web服務的公共接口,列出 Web服務進行交互時需要綁定的協議和信息格式。
    Web 服務采用 WSDL 語言描述該服務支持的操作和信息,運行時再將實際的數據以 SOAP 方式在服務端與客戶端進行信息傳遞。
    由于軟件開發平臺眾多,當中存在不同的開發風格,當服務器端與客戶端使用不同的開發工具時,數據轉換成為復雜且關鍵的問題。而 SOAP 與 WSDL 的主要特性之一在于它們都是可擴展的,且與開發平臺無關。為了建立統一的 XML 協議, 微軟、IBM、Sun、Oracle、BEA 等多家軟件開發商聯合起來,組成了一個名為WS-I(Web Service Interoperability)組織,由該組織制定 WS-ReliableMessage、WS-Discovery、WS-Federation、WS-Coordination、WS-AtomicTransaction、WS-BusinessActivity 、WS-Enumeration、WS-Eventing 、WS-Management 等一系列用于數據交換的規范。

    1.2 JAX-RPC 、JAX-WS 簡介

    JAX-RPC ( Java API for XML-based RPC ) 是 Java 庫中基于 XML 遠程服務的一組標準 API,它通過 WSDL 方式對所提供的服務進行描述,并以 RPC 的風格把 SOAP 信息進行公開,是 Java 庫中最早對 Web 服務提供支持的一組API。
    JAX-RPC 1.0 從其名稱可以看出,最初的目的只是為了支持使用(Remote Procedure Call,RPC) 的 XML 遠程過程調用操作,它以 BP 1.0 (WS-I’s Basic Profile 1.0)為基礎,依賴于SAAJ 1.2(SOAP with Attachments API for Java)為規范,雖然支持 SOAP 協議,但對 Web 服務功能有一定的局限性。于是在 2003 年底,開發團隊對 JAX-RPC 1.0 進行大幅修訂,由 Sun 公司組織了一個專家組開始進行 JAX-RPC 2.0 規范的開發。
    JAX-RPC 2.0 是基于 JAVA 5 而開發的,它依賴于 Annotation 等新特性,在JAX-RPC 的基礎上提供還增加了如異步回調,面向消息等新增技術。JAX-RPC 2.0 以 BP 1.1(WS-I’s Basic Profile 1.1 ) 為基礎,依賴于SAAJ 1.3(SOAP with Attachments API for Java)為規范,能使用 SOAP 1.1、SOAP 1.2 進行信息公開。它是 JAX-RPC 1.1 架構發展的成果,在開發完成后,JAX-RPC 2.0 被正式改名成為 JAX-WS ( Java API for XML-Web Services ) 。

     

    1.3 Axis 概述

    Axis 全稱 Apache EXtensible Interaction System ( 阿帕奇可擴展交互系統 ) , 它是一個 SOAP 引擎,提供創建 Web 服務的基本框架。Axis 1.x 是基于 JAX-RPC 而實現一個工具包,它可以使用 HTTP、JMS、SMTP 等多種傳輸方式支持 SOAP  。
    Axis 2.x 是新一代的 Axis 引擎,它支持 JAX-WS、JAX-PRC 等 API,并且在Axis 1.x 的基礎上增加了靈活數據綁定、異步調用等新增功能,可使用 SOAP 1.1 、SOAP 1.2 協議。在服務請求上,Axis 2.x 支持三種請求-響應模式:In-Only、Robust-In和In-Out,也可支持使用 REST 風格的開發方式。
    基本的 Axis Web 服務由四部分組成:Axis Servlet 、Axis 部署描述、 遠程服務接口、服務實現類。
    Axis Servlet 是 Axis 的核心,它負責 WSDL 基礎服務信息的公開,并把 SOAP 請求轉化為 Java 方法的調用,最后把返回值轉化為 SOAP 。Axis Servlet 隱藏了構建 Web 服務的大量代碼,使用開發人員不用直接與 SOAP 打交道便可輕松完成 Web 服務的開發。
    Axis 部署描述是一個XML文檔,它用于管理 Web 服務的發布,決定哪些服務類需要通過 SOAP 對外公開 。
    遠程服務接口并非必要的,但在很多的 Web 服務開發過程中都會使用遠程服務接口用于對外暴露服務類的方法,在服務器端通過服務實現類去繼承實現服務接口。
    由于 Axis 1.x 與 Axis 2.x 有各自的特色,下面將分開來介紹。

    回到目錄

    二、Axis 1.x 實例

    2.1 Axis 1.x 的下載與安裝

    Axis 1.x 可于官網 http://axis.apache.org/axis/ 下載,完成下載后建立 Web Project 作為測試項目 ,把 lib 文件夾下的 jar 文件拷貝,引入到測試項目當中。
    在 web.xml 文件下加入 AxisServlet 配置后,系統就會對以后綴為 *.jws 及路徑為 /services/* 的請求進行監聽,遇到此類請求時將把信息交由  org.apache.axis.transport.http.AxisServlet 進行處理。

     1 <web-app>
     2     <display-name>Apache-Axis</display-name>
     3     <listener>
     4       <listener-class>org.apache.axis.transport.http.AxisHTTPSessionListener</listener-class>
     5     </listener>
     6     <servlet>
     7       <display-name>Apache-Axis Servlet</display-name>
     8       <servlet-name>AxisServlet</servlet-name>
     9       <servlet-class>
    10           org.apache.axis.transport.http.AxisServlet
    11       </servlet-class>
    12     </servlet>
    13     <!-- 服務管理 -->
    14     <servlet>
    15       <display-name>Axis Admin Servlet</display-name>
    16       <servlet-name>AdminServlet</servlet-name>
    17       <servlet-class>
    18           org.apache.axis.transport.http.AdminServlet
    19       </servlet-class>
    20       <load-on-startup>100</load-on-startup>
    21     </servlet>
    22     <!-- 對輸入輸出的SOAP信息進行檢測 -->
    23     <servlet>
    24       <display-name>SOAPMonitorService</display-name>
    25       <servlet-name>SOAPMonitorService</servlet-name>
    26       <servlet-class>
    27           org.apache.axis.monitor.SOAPMonitorService
    28       </servlet-class>
    29       <init-param>
    30         <param-name>SOAPMonitorPort</param-name>
    31         <param-value>5001</param-value>
    32       </init-param>
    33       <load-on-startup>100</load-on-startup>
    34     </servlet>
    35     <servlet-mapping>
    36       <servlet-name>AxisServlet</servlet-name>
    37       <url-pattern>/servlet/AxisServlet</url-pattern>
    38     </servlet-mapping>
    39     <servlet-mapping>
    40       <servlet-name>AxisServlet</servlet-name>
    41       <url-pattern>*.jws</url-pattern>
    42     </servlet-mapping>
    43     <servlet-mapping>
    44       <servlet-name>AxisServlet</servlet-name>
    45       <url-pattern>/services/*</url-pattern>
    46     </servlet-mapping>
    47     <servlet-mapping>
    48       <servlet-name>SOAPMonitorService</servlet-name>
    49       <url-pattern>/SOAPMonitor</url-pattern>
    50     </servlet-mapping>
    51   </web-app>

    而 SOAPMonitorService 并非必要配置,但加入SOAPMonitorService 配置,可以便于對服務運行時所傳輸的SOAP信息進行監聽,在服務的requestFlow或responseFlow 中加入 SOAPMonitorHandler , 系統就可顯示服務請求和回發時的 SOAP 信息。

     1  <deployment xmlns="http://xml.apache.org/axis/wsdd/" 
     2              xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">  
     3         <handler name="soapmonitor" type="java:org.apache.axis.handlers.SOAPMonitorHandler">  
     4             <parameter name="wsdlURL" value="/axis/SOAPMonitorService-impl.wsdl"/>  
     5             <parameter name="namespace" 
     6              value="http://tempuri.org/wsdl/2001/12/SOAPMonitorService-impl.wsdl"/>  
     7             <parameter name="serviceName" value="SOAPMonitorService"/>  
     8             <parameter name="portName" value="Demo"/>  
     9         </handler>  
    10         <service name="SOAPMonitorService" provider="java:RPC">  
    11             <parameter name="allowedMethods" value="publishMessage"/>  
    12             <parameter name="className" value="org.apache.axis.monitor.SOAPMonitorService"/>  
    13             <parameter name="scope" value="Application"/>  
    14         </service>  
    15 
    16      <service name="myService" provider="java:RPC">  
    17         <requestFlow>  
    18             <handler type="soapmonitor"/>  
    19         </requestFlow>  
    20         <responseFlow>  
    21             <handler type="soapmonitor"/>  
    22         </responseFlow>  
    23         <parameter name="allowedMethods" value="*"/>  
    24         <parameter name="className" value="axis.server.myService"/>  
    25     </service>  
    26 </deployment>  

     

    2.2 調用服務的三種方式

    下面從最簡單的 HelloWorld 開始,介紹 Axis 的使用方法。首先在 WEB-INF 文件夾下建立 server-config.wsdd 文件,在 Axis 1.x 當中,此文件正是用于管理服務發布的默認配置文件。首先 service 用于定義對外暴露的服務,其中 name 屬性用于定義服務的名稱。像下面例子,當 name 為 PersonService 時,對外暴露的服務路徑則對應為 http://localhost:8080/axis.server/services/PersonService
    而 parameter 用于定義服務的相關屬性,className 表示此服務的實現類,而 allowedMethods 表示所公開的服務方法,“*" 則默認為公開此類中的所有 public 公共方法。而 scope 則是用于定義服務對象生成的方式,它包括三個選項:request、session、application 。
    request 是默認選擇,表示為每個請求生成一個服務對象;
    session 表示對同一個客戶代理對象所發送的請求使用同一個服務對象,并把服務信息放在同一個上下文當中。當使用有狀態服務時,使用此 session 更為合適,在下節將再作進一步介紹;
    application 類似于使用單體模式,表示所示的請求均使用同一個服務對象,當使用無狀態服務時使用 application 能有效提高運行效率。
    最后在 transport 中定義一個 requestFlow 處理類 org.apache.axis.handlers.http.URLMapper,表示在系統接受到 http 請求時,將會調用 URLMapper 類來處理路徑映射等問題。

     1 <deployment xmlns="http://xml.apache.org/axis/wsdd/"
     2              xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
     3     <!--在瀏覽器暴露服務 PersonService-->
     4     <service name="PersonService" provider="java:RPC">
     5          <!--綁定服務實現類型 PersonServiceImpl-->
     6         <parameter name="className"  value="axis.serviceImpls.PersonServiceImpl" />
     7         <parameter name="allowedMethods" value="*" />
     8         <parameter name="scope"  value="application" />
     9     </service>
    10     <!--當接收到 http 請求時交由 URLMapper 進行處理-->
    11     <transport name="http">
    12         <requestFlow>
    13             <handler type="java:org.apache.axis.handlers.http.URLMapper"/>
    14         </requestFlow>
    15     </transport>
    16  </deployment>

    PersonService 服務代碼如下,此時運行服務,輸入路徑 http://localhost:8080/axis.server/services/PersonService?wsdl ,瀏覽器上將顯示此服務的 wsdl 信息。

     1  public interface IPersonService {
     2      String HelloWorld(String name);
     3  }
     4  
     5  public class PersonServiceImpl  implements IPersonService { 
     6      @Override  
     7      public String HelloWorld(string name){
     8          return "Hello "+name;
     9      }
    10  }

    客戶端的生成工具有多種,其中一種是使用 Axis 1.x 中的自帶生成器 WSDL2Java ,此生成器可以根據 wsdl 文件生成客戶端。
    首先在環境變量中把 Axis_Home 綁定到 Axis 1.x 的根目錄,在 path 加入設置  ".;%Axis_Home%\lib ", 然后輸入
    Java org.apache.axis.wsdl.WSDL2Java http://localhost:8080/axis.server/services/PersonService?wsdl -p axis.client.person
    此時系統將在 axis.client.person 包內生成客戶端代碼類 PersonServiceImpl、PersonServiceImplService、PersonServiceImplServiceLocator、PersonServiceSoapBindingStub。
    PersonServiceImplServiceLocator 用于實現 PersonServiceImplService 接口,它綁定了服務的名稱,地址,端口等詳細資料。
    PersonServiceImpl 用于定義服務的接口,而 PersonServiceSoapBindingStub 則是此服務代理,它通過 SOAP 協議把操作請求發送到服務器,并把返回信息轉化為 Java 對象。

     1     public static void main(String[] args) throws 
     2         RemoteException, MalformedURLException, ServiceException {
     3         // TODO Auto-generated method stub
     4          HelloWorld();
     5     }
     6     
     7     private static void HelloWorld() throws 
     8         RemoteException, MalformedURLException{
     9         PersonServiceImpl personService=new PersonServiceSoapBindingStub(
    10             new URL("http://localhost:8080/axis.server/services/PersonService"),
    11             new PersonServiceImplServiceLocator());
    12         System.out.println(personService.helloWorld("Leslie"));
    13     }

    通過系統自動生成的代理類就能簡單地調用遠程服務,這是因為在代理類中已經完成了大量關于PersonService 服務的配置,但本人覺得想要深入地了解 Axis 的開發,就應該了解其內部的結構。所以在下面例子當中將介紹如何使用Axis的內部機制直接調用Web服務。
    在 org.apache.axis.client 中存在著服務的基礎類 Service ,通過 Service 可用于管理服務的綁定地址,端點,獲取服務的 WSDL 等詳細信息。另外 Call 類用于管理每個服務請求動作,它可以設置每個請求的方法,最后通過call.invoke(Object[])調用服務,并獲取完成后的返回值。

     1     public static void main(String[] args) throws 
     2         RemoteException, MalformedURLException, ServiceException {
     3         HelloWorld();
     4     }
     5 
     6     private static void HelloWorld() throws
     7         ServiceException,RemoteException{
     8         //生成服務對象Service
     9         Service service=new Service();
    10         Call call=(Call) service.createCall();
    11         //設置Endpoint地址
    12         call.setTargetEndpointAddress(
    13             "http://localhost:8080/axis.server/services/PersonService");
    14         //綁定請求方法名稱
    15         call.setOperationName("HelloWorld");
    16         //通過call.invoke調用服務,獲取返回值
    17         String data=(String)call.invoke(new Object[]{"Leslie"});
    18         System.out.println(data);
    19     }

    如果覺得使用 Call 實現請求較為麻煩,Service 中還提供一個 getPort 方法,通過此方法還可直接實現服務接口 PersonServiceImpl。另外,Axis 還為準備了一個 ServiceFactory 工廠,通過 ServiceFactory 可以直接獲取 Service 對象。

     1     public static void main(String[] args) throws 
     2         RemoteException, MalformedURLException, ServiceException {
     3         // TODO Auto-generated method stub
     4          HelloWorld();
     5     }
     6 
     7     private static void HelloWorld() throws 
     8         ServiceException, RemoteException, MalformedURLException {
     9         String wsdl="http://localhost:8080/axis.server/services/PersonService?wsdl";
    10         String uri="http://localhost:8080/axis.server/services/PersonService";
    11         String serviceName="PersonServiceImplService";
    12         
    13         //使用serviceFacotry直接生成服務
    14         ServiceFactory factory=ServiceFactory.newInstance();
    15         Service service=(Service) factory.createService(
    16                 new URL(wsdl),new QName(uri,serviceName));
    17         
    18         //使用service.getPort方法實現服務接口
    19         PersonServiceImpl personService=(PersonServiceImpl)service
    20                 .getPort(PersonServiceImpl.class);
    21         String data=personService.helloWorld("Leslie");
    22         System.out.println(data);
    23     }

     

    2.3 以自定義對象傳輸數據

    若需要以自定義對象作為數據傳輸的載體,則需要為自定義對象繼承 Serializable 接口。另外可以留意一下服務的 wsdl , 因為 Axis 并沒有默認使用List , Map 等類型, 在 List,Map 等作為參數時,wsdl 都會把返回類型設置為 ArrayOf_xsd_anyType,所以建議使用簡單數組作為返回值。

     1 public class PersonEntity implements Serializable {
     2      private Integer id;
     3      private String name;
     4      private Integer age;
     5      private String address;
     6      
     7      public PersonEntity(Integer id,String name,Integer age,String address){
     8          this.id=id;
     9          this.name=name;
    10          this.age=age;
    11          this.address=address;
    12      }
    13      
    14      public Integer getId(){
    15          return id;
    16      }
    17      
    18      public void setId(Integer id){
    19          this.id=id;
    20      }
    21      ..........
    22  }
    23  
    24  public interface IPersonService {
    25      PersonEntity GetPerson(int id);
    26      PersonEntity[] GetList();
    27      List GetList(String name);
    28  }
    29  
    30  public class PersonServiceImpl implements IPersonService {
    31      @Override
    32      public PersonEntity[] GetList(){
    33          PersonEntity[] list=new PersonEntity[2];
    34          PersonEntity person1=new PersonEntity(1,"Leslie",32,"tianhe");
    35          PersonEntity person2=new PersonEntity(2,"Elva",31,"henan");
    36          list[0]=person1;
    37          list[1]=person2;
    38          return list;
    39      }
    40      
    41      @Override
    42      public List GetList(String name){
    43          List list=new ArrayList();
    44          PersonEntity person1=new PersonEntity(1,name+" Lee",32,"tianhe");
    45          PersonEntity person2=new PersonEntity(2,name+" Chen",31,"henan");
    46          list.add(person1);
    47          list.add(person2);
    48          return list;
    49      }
    50      
    51      @Override
    52      public PersonEntity GetPerson(int id){
    53          return new PersonEntity(id,"Leslie",32,"tianhe");
    54      }
    55  }

    在 server-config.wsdd 中使用 beanMapping 加入自定義對象綁定,以 languageSpecificType 綁定類名,qname 可由用戶設置,但必須與 xmln 特性相對應。

    1   .........
    2    <service name="PersonService" provider="java:RPC">
    3        <parameter name="className"  value="axis.serviceImpls.PersonServiceImpl" />
    4        <parameter name="allowedMethods" value="*" />
    5        <parameter name="scope"  value="application" />
    6        <beanMapping qname="myNS:PersonEntity" xmlns:myNS="urn:PersonEntity" 
    7            languageSpecificType="java:axis.entity.PersonEntity" />
    8    </service>
    9    .........

    以 WSDL2Java 生成客戶端代碼后,可以留意 PersonEntity 對象已經自動實現了 Serializable 接口,增加了 getDeserializer、getSerializer 等序列化與反序列化方法。此時直接使用代理類,會自動地完成對象序列化的過程,可以節省了不少時間。

     1      public static void main(String[] args) throws 
     2          RemoteException, MalformedURLException, ServiceException {
     3          GetList();
     4          GetPerson();
     5      }     
     6      
     7      private static void GetPerson() throws 
     8          RemoteException, MalformedURLException{
     9          PersonServiceImpl personService=new PersonServiceSoapBindingStub(
    10                  new URL("http://localhost:8080/axis.server/services/PersonService"),
    11                  new PersonServiceImplServiceLocator());
    12          PersonEntity person=personService.getPerson(1);
    13          DisplayPersonProperty(person);
    14      }
    15 
    16      private static void GetList() throws 
    17         ServiceException, RemoteException, MalformedURLException{
    18         PersonServiceImpl personService=new PersonServiceSoapBindingStub(
    19                 new URL("http://localhost:8080/axis.server/services/PersonService"),
    20                 new PersonServiceImplServiceLocator());
    21         Object[] objs=personService.getList("Leslie");
    22         for(Object person:objs)
    23            DisplayPersonProperty((PersonEntity)person);
    24      }
    25 
    26      //顯示對象屬性
    27      private static void DisplayPersonProperty(PersonEntity person){
    28          System.out.println("Id:"+person.getId()+"  Name:"+person.getName()+"  Age:"+
    29              person.getAge()+"  Address:"+person.getAddress());
    30      }

    但需要注意,如果使用 Service 類去調用服務的時候,需要使用 Call.registerTypeMapping 注冊一個類型,把接收到的信息轉換為 PersonEntity 類型。在注冊類型時 namespaceURI 參數值需要與服務端 server-config.wsdd 中的值保持一致。

     1      public static void main(String[] args) throws 
     2          RemoteException, MalformedURLException, ServiceException {
     3          // TODO Auto-generated method stub
     4          GetArray();
     5          GetList();
     6      }    
     7 
     8      private static void GetArray() throws 
     9          ServiceException, RemoteException{
    10          Service service=new Service();
    11          Call call=(Call)service.createCall();
    12          call.setTargetEndpointAddress(
    13               "http://localhost:8080/axis.server/services/PersonService");
    14          
    15          //注冊返回類型,namespaceURI 必須與服務端注冊值一致
    16          QName qName2=new QName("urn:PersonEntity","PersonEntity");     
    17          call.registerTypeMapping(PersonEntity.class, qName2,
    18                 new BeanSerializerFactory(PersonEntity.class,qName2), 
    19                 new BeanDeserializerFactory(PersonEntity.class,qName2));
    20          
    21          //綁定請求方法
    22          call.setOperation("GetList");
    23          
    24          //設置返回類型
    25          call.setReturnClass(PersonEntity[].class);
    26          PersonEntity[] list=(PersonEntity[]) call.invoke(new Object[]{});
    27          for(PersonEntity person:list)
    28              DisplayPersonProperty(person);
    29      }
    30     
    31      private static void GetList() throws 
    32         ServiceException, RemoteException{
    33         Service service=new Service();
    34         Call call=(Call)service.createCall();
    35         call.setTargetEndpointAddress(
    36                 "http://localhost:8080/axis.server/services/PersonService");
    37         
    38         //注冊返回類型,namespaceURI 必須與服務端注冊值一致
    39         QName qName2=new QName("urn:PersonEntity","PersonEntity");     
    40         call.registerTypeMapping(PersonEntity.class, qName2,
    41                new BeanSerializerFactory(PersonEntity.class,qName2), 
    42                new BeanDeserializerFactory(PersonEntity.class,qName2));
    43         
    44         //綁定請求方法
    45         call.setOperationName(new javax.xml.namespace.QName(
    46                 "http://serviceImpls.axis", "GetList"));
    47         //輸入參數
    48         Object[] list=(Object[]) call.invoke(new Object[]{"Leslie"});
    49         for(Object person:list)
    50             DisplayPersonProperty((PersonEntity)person);
    51      }
    52      
    53      private static void DisplayPersonProperty(PersonEntity person){
    54          System.out.println("Id:"+person.getId()+"  Name:"+person.getName()+"  Age:"+
    55              person.getAge()+"  Address:"+person.getAddress());
    56      }

    回到目錄

    三、Web服務會話管理

    記得在第二節曾經為大家介紹服務對象的生成方式,當 scope 設置 session 時,系統會對同一個客戶代理對象所發送的請求使用同一個服務對象,并把服務信息放在同一個上下文當中。利用 session 可以把用戶名、用戶密碼、訂單號此類信息在方法中傳播,也可以確保不同的客戶信息分別保存在不同的上下文之上。session 數據的保存時間可以通過 session.setTimeout 方法設置。

     1 public interface ILoginService {
     2     public Boolean Login(String name,String password);
     3     public String GetUserName();
     4 }
     5 
     6 public class LoginServiceImpl implements ILoginService {
     7 
     8     @Override
     9     public Boolean Login(String name, String password) {
    10         // TODO Auto-generated method stub
    11         MessageContext context=MessageContext.getCurrentContext();
    12         Session session=context.getSession();
    13         if(session!=null)
    14             context.getSession().set("User",name);
    15          return true;
    16     }
    17     
    18     @Override
    19     public String GetUserName(){
    20         MessageContext context=MessageContext.getCurrentContext();
    21         Session session=context.getSession();
    22         return session.get("User").toString();
    23     }
    24 }

    在 server-config.wsdd 中,把 scope 設置為 session 模式

    1    .......
    2    <service name="LoginService" provider="java:RPC" style="wrapped">
    3        <parameter name="className"  value="axis.serviceImpls.LoginServiceImpl" />
    4        <parameter name="allowedMethods" value="*" />
    5        <parameter name="scope"  value="session" />
    6    </service>
    7    .......

    在客戶端調用時,需要把 maintainSession 設置為 true,此時可以把 userName , password 等信息存到上下文當中。

     1     public static void main(String[] args) throws 
     2         RemoteException, MalformedURLException, ServiceException {
     3         // TODO Auto-generated method stub
     4         Login();
     5     }
     6     
     7     private static void Login() throws 
     8         MalformedURLException, RemoteException{
     9         LoginServiceImpl service1=getService();
    10         LoginServiceImpl service2=getService();
    11         
    12         service1.login("Leslie", "12345678");
    13         service2.login("Jack", "12345678");
    14         
    15         System.out.println("UserName: "+service1.getUserName());
    16         System.out.println("UserName: "+service2.getUserName());
    17     }
    18     
    19     private static LoginServiceImpl getService() throws
    20         AxisFault, MalformedURLException{
    21         LoginServiceImplServiceLocator locator=new LoginServiceImplServiceLocator();
    22         locator.setMaintainSession(true);
    23         LoginServiceImpl loginService=new LoginServiceSoapBindingStub(
    24                 new URL("http://localhost:8080/axis.server/services/LoginService"),
    25                 locator);      
    26         return loginService;
    27     }

    測試結果


    回到目錄 

    四、自定義 Handler

    Axis 的 Handler 與 Servlet 中的 Filter 有點相似,用于過濾服務,檢測管理 Web 服務信息的接收發送過程。開發 Handler 需要實現 org.apache.axis.Handler 接口,接口包含了下面多個方法:


    為了簡化 Handler 的開發,Axis 在org.apache.axis.handlers 命名空間內就為客戶提供了 BasicHandler、ErrorHandler、LogHandler、SimpleSessionHandler、SimpleAuthenticationHandler、SimpleAuthorizationHandler 等 Handler 用于管理 Axis 的錯誤處理,日志記錄,身份認證,權限管理等工作。BasicHandler 是實現 Handler 接口的基礎類,用戶可以繼承 BasicHandler 類, 開發自定義的 Handler 對特定的服務分別在服務請求request 、信息回送 response 時進行處理。init、invoke 是 BasicHandler 最常用的方法, init 方法會在對象初始化時執行,而對服務的管理操作可以在 invoke 方法中定義。invoke 方法包括了 messageContext 參數 , 利用 messageContext ,可以獲取到服務的 SOAP ,HttpServletRequest 、HttpServletResponse、URL 等相關信息。
    下面的例子就是利用自定義的 LoginHandler 對 LoginService 服務請求進行監聽。
    首先修改 server-config.wsdd 文件,在 LoginService 服務的 requestFlow 中加入 LoginHandler 。

     1    .......
     2    <service name="LoginService" provider="java:RPC" style="wrapped">
     3        <parameter name="className"  value="axis.serviceImpls.LoginServiceImpl" />
     4        <parameter name="allowedMethods" value="*" />
     5        <parameter name="scope"  value="session" />
     6        <requestFlow>
     7            <handler type="java:axis.handler.LoginHandler"/>
     8        </requestFlow>
     9    </service>
    10    ......

    建立 LoginService,在對 LoginService 服務接收到 SOAP 請求時,系統可以通過 LoginHandler 監聽請求信息,獲取相關的方法名,輸入參數等信息。通過 messageContext.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST) 方法,可以獲取到 HttpServletRequest 對象。

     1 public interface ILoginService {
     2      public Boolean Login(String name,String password);
     3  }
     4  
     5  public class LoginServiceImpl implements ILoginService {
     6  
     7      @Override
     8      public Boolean Login(String name, String password) {
     9          // TODO Auto-generated method stub
    10          UserService service=new UserService();
    11          User user=service.getUser(name);
    12          if(user!=null)
    13              return user.password==password;
    14          else
    15              return false;
    16      }
    17  }
    18  
    19  public class LoginHandler extends BasicHandler{
    20      private MessageContext context;
    21      
    22      public void invoke(MessageContext context){
    23          this.context=context;
    24          GetServletRequest();
    25          GetSOAP();
    26      }
    27      
    28      //獲取HtppServletRequest對象
    29      private void GetServletRequest(){
    30          HttpServletRequest request = (HttpServletRequest)context
    31                  .getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST);
    32          String remoteAddress=request.getRemoteAddr();
    33          String method=request.getMethod();
    34          StringBuffer URL=request.getRequestURL();
    35          String message=String.format("Client Address:%s\nMethod:%s\n" +
    36                  "RequestURL:%s\n", remoteAddress,method,URL);
    37          System.out.println(message);
    38      }
    39      
    40      //獲取SOAPBody信息
    41      private void GetSOAP(){
    42          String soap=null;
    43          try {
    44              soap=context.getCurrentMessage().getSOAPBody().toString();
    45          } catch (SOAPException e) {
    46              // TODO Auto-generated catch block
    47              e.printStackTrace();
    48          }
    49          if(soap!=null){
    50              String[] data= soap.split(">");
    51              for(String line:data)
    52                 System.out.println(line+">");
    53          }
    54      }
    55  }

    客戶端

     1     public static void main(String[] args) throws 
     2          RemoteException, MalformedURLException, ServiceException {
     3          LoginServiceImpl service1=getService();
     4          service1.login("Leslie", "12345678");  
     5      }
     6 
     7      private static LoginServiceImpl getService() throws
     8          AxisFault, MalformedURLException{
     9          LoginServiceImplServiceLocator locator=new LoginServiceImplServiceLocator();
    10          locator.setMaintainSession(true);
    11          LoginServiceImpl loginService=new LoginServiceSoapBindingStub(
    12                  new URL("http://localhost:8080/axis.server/services/LoginService"),
    13                  locator);      
    14          return loginService;
    15      }

    只要在 service 的 requestFlow 對 Handler 進行綁定,在客戶端發送請求后, Handler 就能對服務請求進行監聽。


     

    同樣地,在 service 的 responseFlow 輸入流中對 Handler 進行綁定,就可以對回發的 SOAP 信息進行監聽。
    下面例子是利用自定義 LoginHandler 對用戶的登錄回發信息進行監察,計算成功登錄的在線人數 。
    首先修改 server-config.wsdd 文件,在 LoginService 服務的 responseFlow 中加入 LoginHandler 。

    1    <service name="LoginService" provider="java:RPC" style="wrapped">
    2        <parameter name="className"  value="axis.serviceImpls.LoginServiceImpl" />
    3        <parameter name="allowedMethods" value="*" />
    4        <parameter name="scope"  value="session" />
    5        <responseFlow>
    6            <handler type="java:axis.handler.LoginHandler"/>
    7        </responseFlow>
    8    </service>

    在自定義 Handler 中可以通過 Message.getSOAPEnvelope , Message.getSOAPHead ,Message.getSOAPBody 等多個方法對 Web 服務的回發信息進行監測。若登錄成功,系統檢測到 LoginReturn 值為 true 時,則修改成功登錄人數數量。
    除此以外,開發人員還可在 SOAP 的 head、body 等多處地方額外添加回發信息。下面的例子將記錄成功登陸的人數,并把此信息記錄在頭文件中返還到客戶端。

     1   public interface ILoginService {
     2          public Boolean login(String name,String password);
     3   }
     4   
     5   public class LoginServiceImpl implements ILoginService {
     6   
     7       @Override
     8       public Boolean login(String name, String password) {
     9           UserService userService=new UserService();
    10           User user=userSerivice.getUser(name);
    11           if(user!=null)
    12             return user.password==password;
    13           else
    14             return false;
    15       }
    16   }
    17   
    18  public class LoginHandler extends BasicHandler{
    19      private MessageContext context;
    20      
    21      public void invoke(MessageContext context){
    22          this.context=context;
    23          try {
    24              if(success())
    25                 logged();
    26              addElement();
    27              getSOAP();
    28          } catch (AxisFault e) {
    29              e.printStackTrace();
    30          } catch (SOAPException e) {
    31              e.printStackTrace();
    32          }
    33      }
    34      
    35      //記錄登錄人數 
    36      private void logged(){
    37          Handler handler=context.getService();
    38          //判斷服務是否為LoginService
    39          if(handler.getName().equals("LoginService")){
    40              if(this.getOption("loggedCount")==null)
    41                  this.setOption("loggedCount", 0);
    42  
    43              Integer count=Integer.parseInt(
    44                      this.getOption("loggedCount").toString());
    45              count++;
    46              this.setOption("loggedCount", count);
    47  
    48              System.out.println("logged count: "+count+"   "+
    49                 new Date().toString()+"\n");
    50          }
    51      }
    52      
    53      //獲取LoginService服務返回值
    54      //若登錄成功則返回true,失敗則返回false
    55      private Boolean success() throws SOAPException{
    56          SOAPBody soap=context.getCurrentMessage().getSOAPBody();
    57          Node node=soap.getElementsByTagName("LoginReturn").item(0);
    58          return node.toString().contains("true");
    59      }
    60      
    61      //在回發的SOAP中加入已登錄人數的信息
    62      private void addElement() throws SOAPException  {
    63          SOAPEnvelope soap=context.getCurrentMessage().getSOAPEnvelope();
    64          SOAPElement element=soap.getHeader().addChildElement("loggedOnline");
    65          element.addTextNode(this.getOption("loggedCount").toString());
    66      }
    67      
    68      //顯示SOAP信息
    69      private void getSOAP() throws AxisFault{
    70          SOAPEnvelope soap=context.getCurrentMessage().getSOAPEnvelope();
    71          if(soap!=null){
    72              String[] data= soap.toString().split(">");
    73              for(String line:data)
    74                 System.out.println(line+">");
    75          }
    76      }
    77  }

    客戶端

     1     public static void main(String[] args) throws 
     2          RemoteException, MalformedURLException, ServiceException {
     3          LoginServiceImpl service1=getService();
     4          service1.login("Leslie", "12345678");  
     5      }
     6 
     7      private static LoginServiceImpl getService() throws
     8          AxisFault, MalformedURLException{
     9          LoginServiceImplServiceLocator locator=new LoginServiceImplServiceLocator();
    10          locator.setMaintainSession(true);
    11          LoginServiceImpl loginService=new LoginServiceSoapBindingStub(
    12                  new URL("http://localhost:8080/axis.server/services/LoginService"),
    13                  locator);      
    14          return loginService;
    15      }

    運行結果


     

     回到目錄

    五、新一代 SOAP 引擎 Axis 2.x

    5.1 Axis 2.x 核心結構

    Axis 1.x 建立在 JAX-RPC 基礎之上的, 但事實證明這并非一個好方法,因為 JAX-RPC 限制了 Axis 代碼的功能,而且造成了性能問題使系統缺乏靈活性。Axis 2.x 在設計時已經考慮到靈活性操作的問題,它同時實現了對 JAXB 2.x、 Java XML 數據綁定標準,并以 JAX-WS 技術替代了 JAVA-PRC 作為 Java Web 服務標準。
    Axis 2.x 是純 SOAP 處理引擎,它的核心功能是處理傳輸消息,并將其交付給目標應用程序。像 JAX-WS 此類 Web 服務標準不會進入 Axis 2.x 核心部分當中,而只作為 Axis 2.x 服務傳遞組件。 AXIOM(Axis2 Object Model,Axis 2 對象模型)才是 Axis2 的基礎,任何 SOAP 消息在 Axis2 中都可看作為 AXIOM。它把延遲構建和輕型的可定制對象模型結合了起來,盡可能地減輕對系統資源特別是 CPU 和內存的壓力。
    關于 Axis 2.x 的消息處理過程與 AXIOM 對象模型將在下節再作進一步介紹。

     

    5.2 Axis 2.x 安裝部署
    Axis 2.x 可以在 http://axis.apache.org/axis2/java/core/index.html 下載,當中包括Binary Distribution、WAR 等多個版本,使用WAR 版本更方便把 Web 服務部署到 Tomcat、WebLogic 等服務管理器上,在開發階段,使用 Binary Dirstribution 等版本更便于服務的調試。
    完成下載后在環境變量中把 Axis2_Home 綁定到 Axis 2.x 的根目錄,在 path 加入設置  ".;%Axis2_Home%\bin "。
    Axis 1.x 當中只是包括了幾個工具包,而 Axis 2.x 更像是一個框架,在 Axis 2.x 項目的“\WebRoot\WEB-INF\” 文件夾內包含了 Axis 2.x 多個儲存庫,在 “ conf ” 文件夾內的 “ axis2.xml ” 文件是 Axis 2.x 全局描述符,所有的系統級配置都是通過 “ axis2.xml ” 文件完成的。在 “ services” 文件夾是用于存放后綴名為 “ *.aar ” 的服務模塊的,在 “ modules ” 文件夾內用于存放后綴名為 “ *.mar ” 的自定義模塊的,在 “ pojo ” 文件夾內用于存放傳統的 POJO 對象服務文件。 而服務描述符 “services.xml” 文件 與模塊描述符 “module.xml”文件則存放于“ \WebRoot\META-INF ” 文件夾當中。

     

    5.3 將傳統的 POJO 對象作為服務對象部署

    Axis 2.x 為用戶提供了最簡約的服務部署方式,能把簡單的一個 POJO 對象作為服務發布。
    首先在一個缺省包里建立一個 POJO 對象,再把被編譯后的 Example.class 文件加入到 “\WebRoot\WEB-INF\pojo\” 文件夾內,此時 Example 即會被默認為POJO 服務。

    1 public class Example {
    2     public String HelloWorld(String name){
    3         return "Hello "+name;
    4     }
    5 }

    運行程序后,你就可以 http://leslie-laptop:8080/axis2-1.6.2/services/Example?wsdl 上看到 Example 服務的 wsdl 信息。

     

    5.4 以存檔文件部署服務

    使用 POJO 對象部署服務固然簡單,但由于在安全性事務、消息監聽等方面缺乏支持,所以 Axis 2.x 更多時候是使用存檔文件方式部署服務的。首先在項目內建立服務接口 PersonService 和 服務類PersonServiceImpl。

     1 public class PersonEntity implements Serializable {
     2     private Integer id;
     3     private String name;
     4     private Integer age;
     5     private String address;
     6     
     7     public PersonEntity(Integer id,String name,Integer age,String address){
     8         this.id=id;
     9         this.name=name;
    10         this.age=age;
    11         this.address=address;
    12     }
    13     
    14     public Integer getId(){
    15         return id;
    16     }
    17     
    18     public void setId(Integer id){
    19         this.id=id;
    20     }
    21     ........
    22 }
    23 
    24 public interface PersonService {
    25     PersonEntity getPerson(int id);
    26     PersonEntity[] getList();
    27     List<PersonEntity> getListByName(String name);
    28 }
    29 
    30 public class PersonServiceImpl implements PersonService {
    31 
    32     @Override
    33     public PersonEntity[] getList(){
    34         PersonEntity[] list=new PersonEntity[2];
    35         PersonEntity person1=new PersonEntity(1,"Leslie",32,"tianhe");
    36         PersonEntity person2=new PersonEntity(2,"Elva",31,"henan");
    37         list[0]=person1;
    38         list[1]=person2;
    39         return list;
    40     }
    41     
    42     @Override
    43     public List<PersonEntity> getListByName(String name){
    44         List<PersonEntity> list=new LinkedList<PersonEntity>();
    45         PersonEntity person1=new PersonEntity(1,name+" Lee",32,"tianhe");
    46         PersonEntity person2=new PersonEntity(2,name+" Chen",31,"henan");
    47         list.add(person1);
    48         list.add(person2);
    49         return list;
    50     }
    51     
    52     @Override
    53     public PersonEntity getPerson(int id){
    54         return new PersonEntity(id,"Leslie",32,"tianhe");
    55     }
    56 }

    在 “ \WebRoot\META-INF ” 文件夾內加入配置文件 services.xml 。當中 ServiceClass 的 parameter 用于綁定服務實現類,而 operation 用于綁定要暴露的服務方法。
    Axis 2.x 支持三種信息交換模式,包括 In-Only,Robust-In,In-Out 。In-Only 消息交換模式只接收 SOAP 請求,而無需返還信息;Robust-In 消息交換模式發送SOAP 請求,只有在出錯的情況下才返回應答;  In-Out 消息交換模式總是對 SOAP 請求返還信息。在服務的 messageReceive 設置中有 RPCMessageReceiver、RawXMLINOutMessageReceiver、RawXMLINOnlyMessageReceiver 等多個選項可以針對不同 Web 服務方法設置不同的信息交換模式。

     1  <service name="PersonService">  
     2    <description>This is a sample Web Service.</description>
     3    <!--ServiceClass指定實現服務的類。   -->  
     4    <parameter name="ServiceClass" locked="false">
     5        axis2.serviceImpl.PersonServiceImpl
     6    </parameter>  
     7    <!-- operation 與Java Class中方法名對應。 -->  
     8    <operation name="getPerson">  
     9       <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>  
    10    </operation>
    11    <operation name="getList">  
    12       <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>  
    13    </operation> 
    14    <operation name="getListByName">  
    15       <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>  
    16    </operation> 
    17 </service> 

    完成配置后,把 “META-INF\services.xml ” 文件(包含文件夾 META-INF)和服務類 PersonEntity.class、PersonService.class、PersonServiceImpl 復制到自定義文件夾 “axis2serivces” 當中。打開命令提示符,進入 axix2services 文件夾輸入命令 “ jar  cvf  axisService.aar  . ” (注意:“.” 代表生成包含文件夾所有文件)。最后把 “ axisService.aar ” 文件加入到 “\WebRoot\WEB-INF\services” 文件夾當中,啟動 Axis2.x 項目,打開 http://leslie-laptop:8080/axis2-1.6.2/services/PersonService?wsdl 就可看到 PersonService 服務的 wsdl 信息。在 wsdl 中可以看到 axis2 支持 SOAP 1.1、 SOAP 1.2 等多種傳輸格式。


    Axis 2.x 支持多種客戶端生成工具,包括原有 WSDL2Java 工具
    WSDL2Java -uri http://localhost/axis2-1.6.2/services/PersonSerivce.wsdl -p 包名 -o 文件夾
    還有支持 JAX-WS 的 WsImport 工具
    Wsimport  -p  包名  -keep -extension  http://localhost/axis2-1.6.2/services/PersonSerivce.wsdl
    也可使用 MyEclipse 自帶的 JAX-WS 客戶端生成工具完成。
    生成客戶端后可以進行測試

     1     public static void main(String[] args) throws  MalformedURLException {
     2         // TODO Auto-generated method stub
     3         getList();
     4     }
     5     
     6     private static void getList() throws MalformedURLException{
     7          PersonService personService=new PersonService();
     8          PersonServicePortType personServicePortType=personService
     9                  .getPersonServiceHttpSoap12Endpoint();
    10          List<PersonEntity> personList=personServicePortType.getList();
    11          for(PersonEntity person:personList)
    12              displayPersonProperty(person);
    13     }
    14 
    15     private static void displayPersonProperty(PersonEntity person){
    16         System.out.println("Id:"+person.getId().getValue()+"  Name:"
    17            +person.getName().getValue()+"  Age:"+ person.getAge().getValue()
    18            +"  Address:"+person.getAddress().getValue());
    19     }

    測試結果


     回到目錄

    六、AXIOM 對象模型

    6.1 AXIOM 的特點

    AXIOM(Axis Object Model, Axis 對象模型)是 Axis 2.x 對 XML 信息處理的核心部分,它把延遲構建和可定制對象模型技術結合起來,極大地提高了 SOAP 信息構建的靈活度。對應 Axis 1.x 的 SAX ( Simple API for XML)推式(Push)解析器,Axis 2.x 使用更具靈活性的 StAX(Streaming API for XML ) 拉式(Pull)解析器,可盡量減輕對系統資源的壓力。在使用推方式(Push)的情況下,系統會先定義數據的處理程序,然后在數據錄入時對處理程序進行回調。然而回調操作只能對錄入的數據進行如讀取、修改等某些操作,除非引發異常,否則無法左右 XML 文檔的錄入。而 AXIOM 所使用的拉式(Pull)解析器,實際上是一個高效的迭代器,它使用 XML 樹形結構方式,支持延時構建,可以根據需要對文檔中的不同部分進行遍歷。在大型的 XML 文件中,使用拉式解析器更具吸引力,它可以僅對部分 XML 數據進行處理,剩下的留給解析器完成操作。
    在 Web服務開發過程中,大部分的開發人員都是以對象的形式進行信息傳遞,并使用 WSDL2Java 等工具構建服務代理以實現 XML 數據與對象之間的轉換。然而使用此方式限制了Web 服務框架中的數據綁定的靈活程度,利用 AXIOM 的特性更便于 XML 與 Java 對象之間轉換,大部分的 JAVA 對象都可以利用 AXIOM 轉換成 SOAP 信息。

     

    6.2 AXIOM 的使用方式

    AXIOM 建立于 StAX 拉式解析器的基礎上,它為開發人員準備了完善的 API ,其中最常用到的是 OMFactory 工廠,它提供了createOMNamespace、createOMElement、createOMAttribute、createOMDocument、createOMText 等多個方法用于建立 XML 文檔信息。在 BeanUtil 類中還包括了 getPullParser、getOMElement、processObject 等多個靜態方法用于處理自定義對象與XML之間的轉換。
    下面以POCO服務作為一個例子,演示一下 AXIOM 對象綁定方式。在客戶端 Web服務分為 SOAP 請求數據綁定與返回信息處理兩個階段,在服務請求階段系統會把設定的服務地址、傳輸方式綁定到 ServiceClient 請求對象當中,然后利用 serviceClient.sendReceive 的方法把已定義的 OMElement 對象信息加入到 SOAP 當中發送到服務端。當接收到返回信息后,再把 OMElement 信息轉換為對象顯示。

     1      public static void main(String[] args) throws AxisFault {
     2          excute();
     3      }
     4  
     5      public static void excute() throws AxisFault{
     6          //設置 endpoint 地址
     7          EndpointReference targetEndpoint=new EndpointReference(
     8          "http://leslie-laptop:8080/axis2-1.6.2/services/PersonService"); 
     9          Options options=new Options();   
    10          options.setTo(targetEndpoint); 
    11          
    12          //設置傳輸方式
    13          //可使用 TRANSPORT_JMS;TRANSPORT_HTTP;TRANSPORT_MAIL;TRANSPORT_TCP;
    14          options.setTransportInProtocol(Constants.TRANSPORT_HTTP);   
    15          
    16          //把設置的地址、傳輸方式綁定到Service請求當中
    17          ServiceClient sender=new ServiceClient();   
    18          sender.setOptions(options);   
    19          
    20          //設置請求的 SOAP 信息
    21          OMElement requestOMElement=getPersonRequest(1);   
    22          OMElement responseOMElement=sender.sendReceive(requestOMElement);   
    23          
    24          //對返回的SOAP進行處理,顯示返回值
    25          PersonEntity person=convertToPerson(responseOMElement);
    26          displayPersonProperty(person);
    27      }
    28      
    29      private static OMElement getPersonRequest(Integer id){
    30          //新建OMFactory工廠
    31          OMFactory factory=OMAbstractFactory.getOMFactory();   
    32          
    33          //加入OMNamespace、OMElement、OMText 等數據
    34          OMNamespace omNs=factory.createOMNamespace(
    35                 "http://ws.apache.org/axis2","myNS");     
    36          OMElement value=factory.createOMElement("id",omNs);   
    37          value.addChild(factory.createOMText(value,id.toString()));  
    38          
    39          //加入請求方法名
    40          OMElement method=factory.createOMElement("getPerson",omNs); 
    41          method.addChild(value);  
    42          return method;  
    43      }
    44      
    45      //把返回OMElement對象轉換成 person對象 
    46      private static PersonEntity convertToPerson(OMElement element) 
    47              throws AxisFault{
    48          PersonEntity person =null;
    49          OMElement omElement = element.getFirstElement().getFirstElement();
    50          String localName=omElement.getLocalName().toLowerCase();
    51          if (localName.equals("personentity")) {
    52             person = (PersonEntity) BeanUtil.processObject(omElement,
    53             PersonEntity.class, null, true, new DefaultObjectSupplier(), null);      
    54          }
    55          return person;
    56      }
    57      
    58      private static void displayPersonProperty(PersonEntity person){
    59          System.out.println("Id:"+person.getId()+"  Name:"+person.getName()
    60             +"  Age:"+ person.getAge() +"  Address:"+person.getAddress());
    61      }

    發送的 SOAP 請求


    在服務端,系統會從發送的SOAP信息中獲取請求的 id 值,并通過 BeanUtil.getPullParser 等方法把 personEntity 對象轉換成 SOAP 信息返還到客戶端。

     1 public class PersonService {
     2 
     3     public OMElement getPerson(OMElement element){
     4         //獲取請求條件 Id
     5         Integer id=Integer.valueOf(element.getText());
     6         //模擬返回數據
     7         PersonEntity person=new PersonEntity(id,"Leslie",32,"tianhe");
     8         //把person對象轉換為OMElement
     9         javax.xml.stream.XMLStreamReader reader=BeanUtil.getPullParser(person);
    10         StreamWrapper parser=new StreamWrapper(reader);
    11         OMXMLParserWrapper stAXOMBuilder=OMXMLBuilderFactory
    12                 .createStAXOMBuilder(OMAbstractFactory.getOMFactory(), parser);
    13         return stAXOMBuilder.getDocumentElement();
    14     }
    15 }

    返還的 SOAP 信息


     

    6.3 突顯 AXIOM 的優勢

    在面向對象的 Web服務開發模式下,系統都會利用集成工具進行XML信息與對象的自動化轉換。數據的搜索與查找都會在JAVA對象中進行,在信息交換密度頻繁的系統當中,這將占用大量內存空間,對系統造成壓力。所以,在返回信息中直接對 XML 數據進行攔截、分類、篩選是常用的方法。Axis 2.x 使用更具靈活性的 StAX 拉式解析器,它可以使用虛擬文檔的方式構建 XML 樹。每個節點都可被視為一個容器 OMContainer,它可以使用 OMContainer.getChildren 方法獲取子節點,再以 Iterator 迭代器的方式對節點進行遍歷。此外系統還提供了 OMNode.getNextOMSibling、OMNode.getPreviousOMSibling 等多個方法,以進行節點之間的跳轉。這意味著它可以跳過其他的子節點,直接找到需要的節點再進行遍歷。在數據量較大的系統當中使用此種遍歷方式更能突顯出 StAX 拉式(Pull)解析器的優勢。
    以下的例子主要為了展示使用 StAX 拉式解析器進行遍歷的方式,BookService 服務主要是根據客戶所輸入的出版社信息進行查找,然后把該出版社的書本進行按類分配,返還到客戶端。
    下面是服務端的代碼:

      1 public class BookEntity {
      2     private Integer id;
      3     private String title;
      4     private String author;
      5     private String publishing;
      6     private String introduction;
      7     private String type;
      8 
      9     public BookEntity(Integer id,String title,String author
     10           ,String type,String publishing,String introduction){
     11        this.id=id;
     12        this.title=title;
     13        this.author=author;
     14        this.type=type;
     15        this.publishing=publishing;
     16        this.introduction=introduction;
     17     }
     18     
     19     public Integer getId(){
     20         return id;
     21     }
     22     
     23     public void setId(Integer id){
     24         this.id=id;
     25     }
     26     ........
     27 }
     28 
     29 public interface BookService {
     30    OMElement getList(OMElement element);
     31 }
     32 
     33 public class BookServiceImpl implements BookService{
     34 
     35     @Override
     36     public OMElement getList(OMElement element) {
     37         //獲取請求信息 publishing 出版社名稱
     38         OMElement child=(OMElement)element.getChildren().next();
     39         String publishing=child.getText();
     40         
     41         // 構建 OMFactory 工廠
     42         OMFactory factory=OMAbstractFactory.getOMFactory(); 
     43         OMNamespace omNamespace=factory.createOMNamespace(
     44                 "http://serviceImpl.axis2","ns");   
     45         
     46         //獲取計算機類書本子節computerElement
     47         List<BookEntity> computerTypeList=getBooks(
     48                 publishing,"computer");
     49         OMElement computerElement=convertToOMElement(
     50                 computerTypeList,"computer",omNamespace);
     51         
     52         //獲取文學類書本子節literatureElement
     53         List<BookEntity> literatureTypeList=getBooks(
     54                 publishing,"literature");
     55         OMElement literatureElement=convertToOMElement(
     56                 literatureTypeList,"literature",omNamespace);
     57         //加入多個類型的書本
     58         ...........
     59         //構建XML樹
     60         OMElement response=factory.createOMElement(
     61                 "getListResponse",omNamespace); 
     62         OMElement returnValue=factory.createOMElement
     63                 ("return",omNamespace);
     64         OMElement books=factory.createOMElement(
     65                 "publishing",omNamespace);
     66         
     67         books.addAttribute("name", publishing, omNamespace);
     68         books.addChild(computerElement);
     69         books.addChild(literatureElement);
     70         .........
     71         returnValue.addChild(books);
     72         response.addChild(returnValue);
     73         return response;
     74     }
     75 
     76     //把計算機類書本對象轉換為XML信息    
     77     private OMElement convertToOMElement(List<BookEntity> list
     78             ,String typeName,OMNamespace omNamespace){    
     79         OMElement omElement=BeanUtil.getOMElement(new QName("theme")
     80           ,list.toArray(),new QName("book"),false,null);
     81         omElement.addAttribute("name",typeName,omNamespace);
     82         return omElement;
     83     }
     84     
     85     //根據書本類型查找數據
     86     private List<BookEntity> getBooks(String publishing,String type){
     87         List<BookEntity> list=new ArrayList<BookEntity>();
     88         for(BookEntity book:virtualDatabase(publishing))
     89             if(book.getType()=="computer")
     90                 list.add(book);
     91         return list;
     92     }
     93     
     94     //虛擬數據
     95     private List<BookEntity> virtualDatabase(String publishing){
     96         List<BookEntity> list=new ArrayList<BookEntity>();
     97         BookEntity book1=new BookEntity(
     98             1,"Core JAVA Advanced Features","Gary Cornell",
     99             "computer",publishing,
    100             "Core Java by Cay S. Horstmann and Gary Cornell is a book\n"+
    101             "in the Java series of Sun Microsystems Press, published \n"+
    102             "by Prentice-Hall. The book is aimed at experienced \n"+
    103             "programmers who want to learn how to write useful Java \n" +
    104             "applications and applets. No hype, no toy code, no language \n"+
    105             "lawyering, just solid facts and in-depth research to help you \n"+
    106             "write real programs."
    107         );
    108         list.add(book1);
    109         ........
    110         return list;
    111     }
    112 }

    在配置services.xml文件時,需要把 messageReceiver 設置為 org.apache.axis2.receivers.RawXMLINOutMessageReceiver

    1  <service name="BookService">  
    2    <description>This is a sample Web Service.</description>  
    3    <!--ServiceClass指定實現服務的類。   -->
    4    <parameter name="ServiceClass" locked="false">axis2.serviceImpl.BookServiceImpl</parameter>  
    5    <!-- operation 與Java Class中方法名對應。 -->  
    6    <operation name="getList">  
    7       <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>  
    8    </operation>
    9  </service>   

    返還的 SOAP 信息


    在客戶端利用 StAX 就可以輕松地對返還數據進行分類處理,例如要在返回數據當中顯示計算機類型的Book信息,可以使用 Iterator 方式進行遍歷,利用 StaX 推時分析的特點跳過其他類型的節點,直至遇到 ns:name=computer 的節點時,才把該節點的XML樹放入容器進行處理。使用此種遍歷方式,所占用的內存空間更小,在返回數據量較大的系統當中更能突顯其優勢。

     1     public static void main(String[] args) throws AxisFault {
     2         //設置請求的endpoint地址
     3         EndpointReference targetEndpoint=new EndpointReference(
     4             "http://leslie-laptop:8080/axis2-1.6.2/services/BookService"); 
     5         Options options=new Options();   
     6         options.setTo(targetEndpoint); 
     7         
     8         //設置傳輸方式
     9         //可使用 TRANSPORT_JMS;TRANSPORT_HTTP;TRANSPORT_MAIL;TRANSPORT_TCP;
    10         options.setTransportInProtocol(Constants.TRANSPORT_HTTP);   
    11         
    12         //把設置的地址、傳輸方式綁定到Service請求當中
    13         ServiceClient sender=new ServiceClient();   
    14         sender.setOptions(options);   
    15         
    16         //設置請求的 SOAP 信息,輸入出版社名稱
    17         OMElement requestOMElement=getBookRequest("China Machine Press");  
    18         //發送請求
    19         OMElement responseOMElement=sender.sendReceive(requestOMElement); 
    20         //遍歷返回值,在返回信息中獲取computer類的Element
    21         OMElement computerBookElement=getComputerElement(responseOMElement);
    22         //把XML轉換為BookEntity對象集
    23         List<BookEntity> list=convertToBooks(computerBookElement);
    24         for(BookEntity book:list)
    25             DisplayBook(book);
    26     }
    27 
    28     //把XML數據轉換為BookEntity對象集
    29     private static List<BookEntity> convertToBooks(OMElement element)
    30             throws AxisFault{
    31         List<BookEntity> list=new ArrayList<BookEntity>();
    32         Iterator books=element.getChildElements();
    33         while(books.hasNext()){
    34             OMElement bookElement=(OMElement)books.next();
    35             BookEntity book=(BookEntity) BeanUtil.processObject(bookElement,
    36                 BookEntity.class, null, true, new DefaultObjectSupplier(), null);
    37             list.add(book);
    38         }
    39         return list;
    40     }
    41     
    42     //對OMElement元素進行遍歷,找到computer類型的節點
    43     private static OMElement getComputerElement(OMElement element){
    44         OMElement returnOMElement=(OMElement)element
    45             .getChildElements().next();
    46         OMElement publishingOMElement=(OMElement)returnOMElement
    47             .getChildElements().next();
    48         Iterator themes=publishingOMElement.getChildElements();
    49         OMElement theme=null;
    50         while(themes.hasNext()){
    51             theme=(OMElement)themes.next();
    52             OMAttribute themeName=(OMAttribute)theme.getAllAttributes().next();
    53             if(themeName.getAttributeValue().equals("computer"))
    54                break;
    55         }
    56         return theme;
    57     }
    58     
    59     //構建請求文檔
    60     private static OMElement getBookRequest(String publishing){
    61         //新建OMFactory工廠
    62         OMFactory factory=OMAbstractFactory.getOMFactory();   
    63         
    64         //綁定OMNamespace,請求數據
    65         OMNamespace omNamespace=factory.createOMNamespace(
    66                 "http://serviceImpl.axis2","ns");     
    67         OMElement value=factory.createOMElement("publishing",omNamespace);   
    68         value.addChild(factory.createOMText(value,publishing.toString()));  
    69         
    70         //綁定請求方法名
    71         OMElement method=factory.createOMElement("getList",omNamespace); 
    72         method.addChild(value);  
    73         return method;  
    74     }
    75     
    76     private static void DisplayBook(BookEntity book){
    77         System.out.println("##Id##:"+book.getId()+"  ##Title##:"+book.getTitle()
    78             +"\n##Author##:"+book.getAuthor()+"  ##Type##:"+book.getType()
    79             +"  ##Publishing##:"+book.getPublishing()+"\n##Introduction##:\n"
    80             +book.getIntroduction()+"\n");
    81     }

    發送的SOAP請求


    顯示結果


     回到目錄

    七、Module 模塊獨立化處理方式

    7.1 Axis 2.x 信息處理流程

    Axis 2.x 對信息處理流程作出了較大幅的修改,在介紹模塊處理結構前,需要簡單介紹一下 Axis 2.x 的信息處理機制。Axis 1.x 只接受請求-響應的信息處理模式,而 Axis 2.x 支持 In-Only、In-Out 和 Robust-In 三種消息交換模式。而這三種消息交換機制是建立在 TransportListener 和 TransportSender 之上的,在 SOAP 信息進站時,系統會通過 TransportListener 進行監聽。通過一系列處理后,最后會由 TransportSender 進行信息的回送。
    系統定義了 InFlow、OutFlow 兩種流用于處理服務器端的請求消息和響應消息。而 InFaultFlow、OutFaultFlow 只會在請求或者響應出現錯誤時才會被調用。當TransportListener 監聽到入站信息時會把信息送到 InFlow 流當中,系統可通過修改 “ \WEB-INF\conf\axis2.xml” 配置文件,把多個 Phase 綁定到 InFlow 當中。每個 Phase 相當于一個階段,同一個階段可以綁定多個 Handler 進行處理。數據通過 InFlow 流處理后就會被發送到 MessageReceiver,在 services.xml 中會綁定對應的 MessageReceiver 服務方法。最后通過 OutFlow 流對返回信息進行處理后,由 TransportSender 把 SOAP 響應回發到客戶端。

     

     

     

    7.2 Module 模塊結構

    Axis 2.x 把 Handler 放入Module 模塊當中,進行了獨立化處理。每個 Module 模塊是一個容器,當中可以包含多個 Handler 處理程序、第三方庫、模塊相關資源和模塊配置文件。系統把Module 模塊定義為后綴名為 “ *.mar ” 的文件,系統可通過 “ jar  cvf  myModule.mar  . ” 命令可以生成 *.mar 的模板文件。當中必須包含 module.xml 文件對 Handler 進行部署,否則系統會無法識別此模塊。想要在某個 Web服務的 InFlow 流或 OutFlow 流中調用 Module 模塊中的 Handler,還需要修改 axis2.xml  文件,在phaseOrder 中加入自定義的 phase, 并綁定 Handler 的處理類。最后修改 “ services.xml ” 文件,在對應此服務配置中加入 <module ref="ModuleName"> 字節 。
    下面先以一個簡單的例子,說明 Module 模塊的使用方式。在例子中將建立一個 MyModule 模塊,在模塊中加入一個 InputHandler 處理文件對 InFlow 流進行檢測。首先建立 org.apache.axis2.modules.Module 的子類 MyModule,此類是用于對模塊init 、engageNotify 等事件進行監測的。然后建立 InputHandler 類,此類必須繼承 org.apache.axis2.engine.Handler 且實現 org.apache.axis2.engine.Handler.AbstractHandler 接口的 public InvocationResponse invoke(MessageContext context) 方法,此方法的返回值 InvocationResponse 包括 CONTINUE,SUSPEND,ABORT 三個選項,可以"繼續"或者"停止"流的執行。
    在流輸入時此方法將會被自動執行,它所帶的 MessageContext 參數對象中將包括此服務的上下文信息。
    此例子的主要目的是為開發人員顯示一下在 InFlow 流可以獲取到的數據信息,所以在此先介紹一下 MessageContext 常用方法:

    方法  說明
    getCurrentMessageContext()  獲取當前上下文對象
    getExecutedPhases()  獲取包含在此流中的 Phase 集合
    getAxisService()  獲取被調用的 AxisService 服務對象
    getEnvelope()  獲取 SOAP,在 InFlow 中,此方法將顯示該請求的 SOAP 信息
    getFrom()  獲取客戶端地址  
    getTo()  獲取服務地址

     MessageContext 常用方法


    當中 getAxisService 方法所返回的 AxisService 對象正是當前被調用的 Web服務對象。

    方法 說明
    getOperationContext() 返回當前被調用的 OperationContext 上下文對象
    getOperations() 返回此服務所包含的所有 Operation 對象
    getParameters() 返回此服務的所包含的所有 Parameters 對象
    getFileName() 返回此*.aar 服務文件路徑
    getTargetNamespace() 返回此服務的 targetNamespace 名稱
    getEndpointName() 返回此服務的 Endpoint 名稱

     AxisService 常用方法

     1 public class MyModule implements Module{
     2  
     3      @Override
     4      public void applyPolicy(Policy arg0, AxisDescription arg1)
     5          throws AxisFault {
     6          // TODO Auto-generated method stub
     7      }
     8  
     9      @Override
    10      public boolean canSupportAssertion(Assertion arg0) {
    11          // TODO Auto-generated method stub
    12          return false;
    13      }
    14  
    15      @Override
    16      public void engageNotify(AxisDescription arg0) throws AxisFault {
    17          // TODO Auto-generated method stub
    18      }
    19  
    20      @Override
    21      public void init(ConfigurationContext arg0, AxisModule arg1)
    22              throws AxisFault {
    23          // TODO Auto-generated method stub
    24      }
    25  
    26      @Override
    27      public void shutdown(ConfigurationContext arg0) throws AxisFault {
    28          // TODO Auto-generated method stub
    29      }  
    30  }
    31  
    32  public class InputHandler
    33        extends AbstractHandler implements Handler{
    34      
    35      public InvocationResponse invoke(MessageContext context){
    36          //顯示當前上下文信息
    37          System.out.println("##from:##\n  "+context.getFrom()
    38                  +"\n##to:##\n  "+context.getTo());
    39          //顯示所執行的phase信息
    40          phasesMessageDisplay(context.getExecutedPhases());
    41          //顯示服務對象信息
    42          AxisService axisService=context.getAxisService();
    43          serviceMessageDisplay(axisService);
    44          //顯示當前operation信息
    45          AxisOperation operation=context.getOperationContext().getAxisOperation();
    46          currentOperationDisplay(operation);
    47          //顯示服務的所有operation信息
    48          operationsMessageDisplay(axisService.getOperations());
    49          //顯示服務參數parameters信息
    50          parametersMessageDisplay(axisService.getParameters());
    51          return InvocationResponse.CONTINUE;
    52      }
    53      
    54      //顯示所執行的phases
    55      private void phasesMessageDisplay(Iterator<Handler> iterator){
    56          String data="##phaseList:##\n";
    57          while(iterator.hasNext()){
    58              Handler handler=(Handler)iterator.next();
    59              data+="  "+handler.getName();  
    60          }
    61          System.out.println(data);
    62      }
    63      
    64      //顯示服務信息
    65      private void serviceMessageDisplay(AxisService axisService){
    66          System.out.println("\n##serviceFile:##\n  "+axisService.getFileName()+ 
    67              "\n##targetNamespace:##\n  "+axisService.getTargetNamespace()+
    68              "\n##endpointName##:\n  "+axisService.getEndpointName()+"\n");
    69      }
    70      
    71      //顯示當前Operation信息
    72      private void currentOperationDisplay(AxisOperation operation){
    73          System.out.println("##currentOperation:##\n  name:"
    74                  +operation.getName().getLocalPart()+"\n  messageReceive:"
    75                  +operation.getMessageReceiver().toString()+"\n");
    76      }
    77      
    78      //顯示服務的所有Operation信息
    79      private void operationsMessageDisplay(Iterator operations){
    80          while(operations.hasNext()){
    81              AxisOperation operation=(AxisOperation)operations.next();
    82              System.out.println("##operation:##\n  name:"
    83                  +operation.getName().getLocalPart()+"\n  messageReceive:"
    84                  +operation.getMessageReceiver().toString());
    85          }
    86          System.out.println();
    87      }
    88      
    89      //顯示parameter信息
    90      private void parametersMessageDisplay(List<Parameter> parameters){
    91          for(Parameter parameter:parameters){
    92              System.out.println("##parameter:##\n  name:"+parameter.getName()
    93                      +"\n  value:"+parameter.getValue().toString());
    94          }
    95      }
    96  }

    在 “ \WebRoot\META-INF\ ” 內加入 “ module.xml ” 配置文件

    1 <module name="myModule" class="axis2.module.MyModule">
    2     <InFlow>
    3        <handler name="inputHandler" class="axis2.handler.InputHandler">
    4           <order phase="orderInPhase"/>
    5        </handler>
    6     </InFlow>
    7 </module>

    把 “module.xml ” 配置文件(包含 “ META-INF ”文件夾)和編譯后的 MyModule.class、InputHandler.class 加入到自定義文件夾,使用命令提示符進行入自定義文件夾內輸入 “ jar  cvf  myModule.mar  . ” 命令生成 “ myModule.mar ” 包,把生成的包加入 “\WEB-INF\modules ” 文件夾內。
    最后修改 “ \WEB-INF\conf\axis2.xml” 配置文件,加入自定義的 phase 配置。此時重啟系統,即完成了 myModule.mar 自定義模塊的配置。

    注意:自定義 handler 可以在 axis2.xml 或者 module.xml 中進行綁定。

    axis2.xml 中所配置的是全局變量,如果直接在 axis2.xml 文件中加入對 handler 進行綁定,那所有的服務在 InFlow 和 OutFlow 中都執行此 handler。
    如果只在 axis2.xml 中建立自定義 phase,然后在 module.xml 中綁定 handler,那只有在服務綁定此 module 時,該 handler 才會被執行 。配置應該按需要而定,一般只有登錄、日志記錄、系統信息監視等 handler 才會在 axis2.xml 中直接綁定。

    1     <phaseOrder type="InFlow">
    2         <phase name="orderInPhase">
    3            <handler name="inputHandler" class="axis2.handler.InputHandler"/>
    4         </phase>
    5     </phaseOrder>

    想要在某 Web 服務中調用此模塊,只需要修改對應的 services.xml 配置文件,在服務配置內加入“ <module ref=‘myModule’ /> ” 字節即可。

     1 <service name="PersonService">  
     2    <description>This is a sample Web Service.</description>
     3    <!--使用myModule模塊-->  
     4    <module ref="myModule"/>
     5    <!-- ServiceClass指定實現服務的類。 -->  
     6    <parameter name="ServiceClass" locked="false">axis2.serviceImpl.PersonServiceImpl</parameter>  
     7    <!-- operation 與Java Class中方法名對應。   -->
     8    <operation name="GetPerson">  
     9       <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>  
    10    </operation>
    11    <operation name="GetList">  
    12       <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>  
    13    </operation> 
    14    <operation name="GetListByName">  
    15       <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>  
    16    </operation> 
    17 </service>   

    在啟動此Web服務,調用 GetPerson 服務方法時,InputHandler 將會對服務流進行處理,顯示測試結果:


     

    7.3 Module 實用方式

    以上對 Module 的使用方式進行了簡單的介紹,下面想以一個更為實際的訂單管理例子介紹一下 Module 的用途。在Web服務項目當中,很多的服務在操作前都需要先進行登錄驗證,所以下面例子當中會把用戶登錄功能獨立開來,作為一個自定義 Handler 置于模塊當中,這樣可以使登錄服務的功能更為獨立,易于管理。用戶在調用 OrderService 服務時,會先在頭文件中加入用戶信息, 在服務端接收到 SOAP 請求時,在 InFlow 流中加入 OrderInputHandler 進行處理,獲取頭文件信息進行登錄,登錄成功就會在 Session 中記錄 User 對象信息。
    像 Order 管理這類服務中,訂單費用的計算往往是一個長期不變的規則,但銷售商很多時候會進行產品的抽獎,優惠等銷售策略,這些策略都是短期的,具有多變性。如果直接把這些業務規則寫入 OrderService 服務中,OderService 就會經常需要修改。此時,可以嘗試利用 OutFlow 流 ,建立 OrderOutputHandler 對完成操作的 Order 進行檢測。若通過得獎規則,則在SOAP返還信息的頭文件中加入獎勵信息。
    由于本節的目的主要是為了展示 Module 的獨立性與靈活性,所以省略了 OrderManager、UserManager、FavourableManager 等操作對象。
    首先建立 OrderInputHandler 在 SOAP 信息進入 InFlow 流時進行登錄處理。
    然后建立 OrderOutputHandler 在 SOAP 信息進行 OutFlow 時對已處理Order對象進行檢測。

      1 public class MyModule implements Module{
      2     
      3         @Override
      4         public void applyPolicy(Policy arg0, AxisDescription arg1)
      5             throws AxisFault {
      6             // TODO Auto-generated method stub
      7         }
      8     
      9         @Override
     10         public boolean canSupportAssertion(Assertion arg0) {
     11             // TODO Auto-generated method stub
     12             return false;
     13         }
     14     
     15         @Override
     16         public void engageNotify(AxisDescription arg0) throws AxisFault {
     17             // TODO Auto-generated method stub    
     18         }
     19     
     20         @Override
     21         public void init(ConfigurationContext arg0, AxisModule arg1)
     22                 throws AxisFault {
     23             // TODO Auto-generated method stub
     24         }
     25     
     26         @Override
     27         public void shutdown(ConfigurationContext arg0) throws AxisFault {
     28             // TODO Auto-generated method stub
     29         }  
     30     }
     31     
     32     public class OrderInputHandler 
     33        extends AbstractHandler implements Handler {
     34     
     35         public InvocationResponse invoke(MessageContext context){
     36             //判斷被調用的是否OrderSerivce的addOrder方法
     37             if(context.getOperationContext().getAxisOperation()
     38                     .getName().getLocalPart().equals("addOrder")){
     39                 //獲取頭文件信息
     40                 SOAPHeader head=context.getEnvelope().getHeader();
     41                 //把頭文件信息轉換成User對象進行登錄
     42                 String[] userMes=head.getFirstElement().getText().split(",");
     43                 //用戶登錄
     44                 UserEntity user=UserManager.Login(userMes[0],userMes[1]);
     45                 .......
     46                 if(user!=null){
     47                    //登錄成功記錄User
     48                    SessionContext session=context.getSessionContext();
     49                    if(session.getProperty("User")==null)
     50                        session.setProperty("User", user);
     51                 } 
     52             }
     53             return InvocationResponse.CONTINUE;
     54         }
     55     }
     56     
     57     public class OrderOutputHandler 
     58         extends AbstractHandler implements Handler{
     59          
     60         public InvocationResponse invoke(MessageContext context){
     61             //判斷被調用的是否OrderSerivce的addOrder方法
     62             if(context.getOperationContext().getAxisOperation()
     63                     .getName().getLocalPart().equals("addOrder")){
     64               //獲取返回信息的SOAPBody,判斷訂單總體價格是否高于 200 dollar
     65               SOAPBody body=context.getEnvelope().getBody();
     66               OMElement element=body.getFirstElement();
     67               try {
     68                  OrderEntity order = (OrderEntity) BeanUtil.processObject(element,
     69                      OrderEntity.class, null, true, new DefaultObjectSupplier(), null);
     70                 
     71                  //總體價格高于 200 dollar的訂單在頭文件中輸入獲獎信息
     72                  if(order.getTotalPrice()>200){
     73                  //在數據庫中記錄獲獎訂單
     74                  Favourable favourable=FavourableManager.addOrder(order); 
     75                  .......
     76                  //修改頭文件,加入獲獎信息 
     77                  setHead(context.getEnvelope().getHeader(),favourable);
     78               } catch (AxisFault e) {
     79                  e.printStackTrace();
     80               }      
     81           }
     82           return InvocationResponse.CONTINUE;
     83         }
     84         
     85         //修改頭文件,加入獲獎信息
     86         private void setHead(SOAPHeader head,favourable){
     87             OMFactory factory=OMAbstractFactory.getOMFactory(); 
     88             OMNamespace omNamespace=factory.createOMNamespace(
     89                     "http://serviceImpl.axis2","ns");    
     90             OMElement element=factory.createOMElement("favourable",omNamespace);
     91             element.setText("Congratulations! Price is higher than 200 dollar ......");
     92             //加入favourable 信息
     93             .........
     94             head.addChild(element);
     95         }
     96     }
     97     
     98     public class OrderEntity implements Serializable {
     99         private Integer id;
    100         private String orderCode;
    101         private Double totalPrice;
    102         .........
    103      
    104         public OrderEntity(Integer id,String orderCode,Double totalPrice,........){
    105             this.id=id;
    106             this.orderCode=orderCode;
    107             this.totalPrice=totalPrice;
    108             ........
    109         }
    110         ..........
    111     }

    完成自定義Handler后,進行 module.xml 配置,分別在 InFlow 流 OutFlow 綁定 OrderInputHandler 和 OrderOutputHandler

     1 <module name="myModule" class="axis2.module.MyModule">
     2     <InFlow>
     3        <handler name="orderInputHandler" class="axis2.handler.OrderInputHandler">
     4           <order phase="orderInPhase"/>
     5        </handler>
     6     </InFlow>
     7     <OutFlow>
     8         <handler name="orderOutputHandler" class="axis2.handler.OrderOutputHandler">
     9             <order phase="orderOutPhase"/>
    10         </handler>
    11     </OutFlow>
    12 </module>

    修改 axis2.xml 文件,建立自定義的 phase ,在 InFlow 流和 OutFlow 流中加入 orderInPhase 和 orderOutPhase 。

    1      <phaseOrder type="InFlow">
    2         <phase name="orderInPhase"/>
    3      </phaseOrder>
    4      <phaseOrder type="OutFlow">
    5          <!-- 調用自定義模塊進行處理 -->
    6          <phase name="orderOutPhase"/>
    7      </phaseOrder>

    建立 Web 服務OrderService ,當調用 addOrder 前先檢測用戶是否登錄成功,若用戶未登錄則釋放出異常。若登錄成功,把輸入的Order對象加入數據庫,然后把處理后的 Order 轉換為OMElement 返還到客戶端。

     1     public interface OrderService {
     2        OMElement addOrder(OMElement element) throws Exception;
     3     } 
     4     
     5     public class OrderServiceImpl implements OrderService{
     6         
     7         @Override
     8         public OMElement addOrder(OMElement element) throws Exception{
     9             //驗證是否登錄成功
    10             if(isLogged()){
    11                 //把訂單加入數據庫,把更新后的訂單返回客戶端
    12                 OrderEntity order = (OrderEntity) BeanUtil.processObject(
    13                    element.getFirstElement(),OrderEntity.class, 
    14                    null, true, new DefaultObjectSupplier(), null);
    15                 //加入訂單,計算總體價格,Code號碼等信息
    16                 OrderEntity orderRefresh=OrderManager.addOrder(order);
    17                 .......
    18                 //把修改后order對象轉換為OMElement
    19                 XMLStreamReader reader=BeanUtil.getPullParser(orderRefresh);
    20                 StreamWrapper parser=new StreamWrapper(reader);
    21                 OMXMLParserWrapper stAXOMBuilder=OMXMLBuilderFactory
    22                   .createStAXOMBuilder(OMAbstractFactory.getOMFactory(), parser);
    23                 return  stAXOMBuilder.getDocumentElement();
    24             }
    25             else
    26                 throw new Exception();
    27         }
    28         
    29         //驗證用戶是否已經登錄
    30         private boolean isLogged(){
    31             MessageContext context=MessageContext.getCurrentMessageContext();
    32             SessionContext session=context.getSessionContext();
    33             return session.getProperty("User")!=null;    
    34         }
    35     }

    在 services.xml 文件加入 module 節點

     1 <service name="OrderService">  
     2    <description>This is a sample Web Service.</description>  
     3    <module ref="myModule"/>
     4    <!--  ServiceClass指定實現服務的類。 -->  
     5    <parameter name="ServiceClass" locked="false">axis2.serviceImpl.OrderServiceImpl</parameter>  
     6    <!-- operation 與Java Class中方法名對應。   -->
     7    <operation name="addOrder">  
     8       <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>  
     9    </operation>
    10  </service>   

    當調用OrderService 服務后,數據進入 OutFlow 流后系統將檢測返還數據,若 Order 符合得獎條件,OrderOutputHandler 將在SOAP頭部加入得獎信息。下面是 totalPrice 超過 200 dollor (符合得獎條件) 所返回的SOAP信息。


     

    在客戶端發送 OrderService.addOrder 請求時,在頭文件加入用戶userName,password等資料。為了在使用Session存儲User對象,需要在客戶端使用options.setManageSession(bool)方法打開 sessionContext 。由于使用方式與 Axis1.x 較為相像,在此不再詳細說明了。

     1      public static void main(String[] args) throws RemoteException, OrderServiceExceptionException {
     2          // TODO Auto-generated method stub
     3          excute();
     4      }
     5      
     6      public static void excute() throws AxisFault{
     7          EndpointReference targetEndpoint=new EndpointReference(
     8                  "http://leslie-laptop:8080/axis2-1.6.2/services/OrderService"); 
     9          Options options=new Options();   
    10          options.setManageSession(true);
    11          options.setTo(targetEndpoint); 
    12         
    13          //設置傳輸方式
    14          //可使用 TRANSPORT_JMS;TRANSPORT_HTTP;TRANSPORT_MAIL;TRANSPORT_TCP;
    15          options.setTransportInProtocol(Constants.TRANSPORT_HTTP);   
    16          
    17          //把設置的地址、傳輸方式綁定到Service請求當中
    18          ServiceClient sender=new ServiceClient();   
    19          sender.setOptions(options);   
    20          
    21          //設置請求的 SOAP 信息
    22          OMElement requestOMElement=getOrderRequest(new OrderEntity(-1,null,200.5,......));   
    23          //在頭文件中加入用戶資料
    24          sender.addHeader(setHead());
    25          OMElement responseOMElement=sender.sendReceive(requestOMElement);   
    26         
    27          //對返回的SOAP進行處理,顯示返回值
    28          OrderEntity order=convertToOrder(responseOMElement);
    29          displayOrderProperty(order);
    30      }
    31      
    32      //在頭文件中加入用戶資料    
    33      private static OMElement setHead(){
    34          //新建OMFactory工廠
    35          OMFactory factory=OMAbstractFactory.getOMFactory();   
    36          //綁定OMNamespace,請求數據
    37          OMNamespace omNamespace=factory.createOMNamespace(
    38                  "http://serviceImpl.axis2","ns");     
    39          //加入用戶資料
    40          OMElement user=factory.createOMElement("User",omNamespace); 
    41          user.setText("Leslie,12345678");
    42          return user;
    43      }
    44      
    45      private static OMElement getOrderRequest(OrderEntity order){
    46          //新建OMFactory工廠
    47          OMFactory factory=OMAbstractFactory.getOMFactory();     
    48          //綁定OMNamespace
    49          OMNamespace omNamespace=factory.createOMNamespace(
    50                  "http://serviceImpl.axis2","ns");     
    51          //綁定請求方法名
    52          OMElement method=factory.createOMElement("addOrder",omNamespace); 
    53  
    54          //把order對象轉換為OMElement
    55          javax.xml.stream.XMLStreamReader reader=BeanUtil.getPullParser(order);
    56          StreamWrapper parser=new StreamWrapper(reader);
    57          OMXMLParserWrapper stAXOMBuilder=OMXMLBuilderFactory
    58                  .createStAXOMBuilder(OMAbstractFactory.getOMFactory(), parser);
    59          OMElement param=stAXOMBuilder.getDocumentElement();
    60          
    61          method.addChild(param);
    62          return method;
    63      }
    64      
    65      //把返回OMElement對象轉換成 person對象 
    66      private static OrderEntity convertToOrder(OMElement element) 
    67              throws AxisFault{
    68          OrderEntity order =null;
    69          OMElement omElement = element.getFirstElement().getFirstElement();
    70          String localName=element.getLocalName().toLowerCase();
    71          if (localName.equals("orderentity")) {
    72             order = (OrderEntity) BeanUtil.processObject(element,
    73             OrderEntity.class, null, true, new DefaultObjectSupplier(), null);      
    74          }
    75          return order;
    76      }
    77      //顯示Order數據
    78      private static void displayOrderProperty(OrderEntity order){
    79          System.out.println("Id:"+order.getId()+"  Code:"+order.getOrderCode()
    80             +"  TotalPrice:"+ order.getTotalPrice());
    81      }

    發送的SOAP請求


     

     回到目錄 

    八、異步調用Web服務

    在 Axis 1.x 中服務只支持 “請求-回復” 的操作方式,客戶端在發送請求后將處于等待的狀態,在Web服務操作時間較長的情況下,這種操作方式將影響了系統的效率。從 Axis 2.x 開始客戶端支持異步操作的方式,在發送請求后,系統將使用異步線程綁定回調操作。在發出請求后,客戶端無需再處理于長期等待的狀態。生成異步操作的方法有很多,比較簡單的是使用 WSDL2Java 的 “-a” 命令:
    WSDL2Java -uri http://localhost/axis2-1.6.2/services/PersonSerivce.wsdl -p 包名 -o 文件夾 -a
    所生成的客戶端會包含一個 ServiceCallbackHandler 類,下面的例子當中,只要實現了 PersonServiceCallbackHandler 類的 receiveResultgetList 方法,在調用 personServiceStub.startgetList(PersonServiceStub.GetList , PersonServiceCallbackHandler)方法后,系統將釋放主線程。當接收到服務端的返還信息后,信息將交由 PersonServiceCallbackHandler 所綁定的方法進行處理。

    服務端

    1 public class PersonService{
    2 
    3     public List<PersonEntity> getList(){
    4         List<PersonEntity> list=new ArrayList<PersonEntity>();
    5         list.add(new PersonEntity(1,"Leslie",32,"tianhe"));
    6         list.add(new PersonEntity(2,"Elva",28,"henan"));
    7         return list;
    8     }
    9 }

    客戶端

     1     public static void main(String[] args)
     2             throws InterruptedException, RemoteException {
     3         // TODO Auto-generated method stub
     4         threadMessage("start "); 
     5         //建立服務對象
     6         PersonServiceStub personService=new PersonServiceStub();        
     7         PersonServiceStub.GetList getList=new PersonServiceStub.GetList();
     8         //建立回調函數
     9         PersonServiceCallbackHandler callback=new PersonServiceCallbackHandler(){
    10             public void receiveResultgetList(GetListResponse response){
    11                 threadMessage("callback ");
    12                 PersonEntity[] list=response.get_return();
    13                 for(Integer n=0;n<list.length;n++)
    14                     displayPersonProperty(list[n]);
    15             }
    16         };
    17         //啟動異步服務
    18         personService.startgetList(getList,callback);
    19         Thread.sleep(500);
    20     }
    21 
    22     //顯示線程id
    23     private static void threadMessage(String data){
    24            Thread thread=Thread.currentThread();
    25            System.out.println(data +"threadId: "+thread.getId());
    26     }
    27     
    28     //顯示對象信息
    29     private static void displayPersonProperty(PersonEntity person){
    30         System.out.println("Id:"+person.getId() +"  Name:"
    31            +person.getName() +"  Age:"+ person.getAge() 
    32            +"  Address:"+person.getAddress() );
    33     }

    測試結果


     回到目錄

     

    本章小結

    Aixs 的主要特點在于其操作的靈活性,它能對請求和回發的 SOAP 信息直接進行處理,在頭文件或者自定義節點中加入數據。特別在Axis 2.x 引入 AXIOM 后,其優點更為突出。它使用 StAX(Streaming API for XML ) 拉式(Pull)解析器,可盡量減輕對系統資源的壓力。Axis 2.x 使用 Module 模塊化的部署方式,使系統功能分割更為簡單, Module 可以獨立于服務進行開發。為了解決客戶端為等待返回數據而長時間處于柱塞狀態,Axis 2.x 還加入異步操作的方法,提高了客戶端的運行效率。
    由于本人并非 JAVA 方面的專家,文章難免存在錯誤之處,敬請讀者點評。
    對JAVA開發有興趣的朋友歡迎加入
    QQ群:Java高級編程(174850571)
    騰訊微博群:數碼化時代(62916150)
    新浪微博群: 一切皆是“云”(1181103)

    作者:風塵浪子

    http://www.tkk7.com/Leslies2/archive/2012/09/14/leslieBlog-java-axis.html

    原創作品,轉載時請注明作者及出處

     

     

     

     

     

     

    posted on 2012-09-14 10:33 風塵浪子 閱讀(2780) 評論(0)  編輯  收藏 所屬分類: Java遠程通信技術


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     

    導航

    統計

    公告

     個人簡介

    02年畢業于中山大學物理系,專門從事.NET、JAVA的項目開發,研究大型企業系統架構。對領域驅動設計DDD、面向服務架構SOA、分布式開發、.NET與JAVA的相互調用等方面有著深厚的興趣。本博客中的文章皆屬原創,轉載時請注明出處。


    Java高級編程

    技術交流
    歡迎加入以下小組共同探討
    QQ群:
    JAVA 高級編程 174850571
    騰訊微博群:
    數碼化時代 62916150
    新浪微博群:
    一切皆是“云” 1181103

    常用鏈接

    留言簿

    隨筆分類(1)

    隨筆檔案(2)

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 中文日韩亚洲欧美制服| 在线观看亚洲成人| 最新国产成人亚洲精品影院| 最近中文字幕mv免费高清电影 | 猫咪免费观看人成网站在线| 成年女人18级毛片毛片免费观看| 亚洲人配人种jizz| 成人免费一区二区三区在线观看| 亚洲日韩中文字幕一区| 国产成人在线免费观看| 菠萝菠萝蜜在线免费视频| 相泽亚洲一区中文字幕| 国产性生大片免费观看性| 久久夜色精品国产嚕嚕亚洲av| 青青青国产手机频在线免费观看| 亚洲视频在线视频| 青青久在线视频免费观看| 亚洲欧美成人综合久久久| 亚洲成人一区二区| 久草视频在线免费看| 亚洲丰满熟女一区二区v| 在线观看免费亚洲| caoporn成人免费公开| 亚洲另类激情综合偷自拍| 大学生一级毛片免费看| 粉色视频在线观看www免费| 亚洲色精品88色婷婷七月丁香| 96免费精品视频在线观看| 99亚偷拍自图区亚洲| 亚洲精品视频在线观看你懂的| 久久大香香蕉国产免费网站| 亚洲国产乱码最新视频| 亚洲色偷拍区另类无码专区| 免费A级毛片av无码| 久久久久亚洲国产AV麻豆 | 国产免费高清69式视频在线观看| 亚洲国产精品无码久久久蜜芽| 毛片A级毛片免费播放| 日本高清免费中文在线看| 亚洲第一页中文字幕| mm1313亚洲精品无码又大又粗|