積累生活學習的點點滴滴

          Best Wishes ^_^

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            21 Posts :: 10 Stories :: 42 Comments :: 0 Trackbacks
          http://www.silvery-lunar.com/simple/index.php?t295.html
          Handler的基本概念

          J2EE Web 服務(wù)中的Handler技術(shù)特點非常像Servlet技術(shù)中的Filter。我們知道,在Servlet中,當一個HTTP到達服務(wù)端時,往往要經(jīng)過多個Filter對請求進行過濾,然后才到達提供服務(wù)的Servlet,這些Filter的功能往往是對請求進行統(tǒng)一編碼,對用戶進行認證,把用戶的訪問寫入系統(tǒng)日志等。相應的,Web服務(wù)中的Handler通常也提供一下的功能:

          對客戶端進行認證、授權(quán);
          把用戶的訪問寫入系統(tǒng)日志;
          對請求的SOAP消息進行加密,解密;
          為Web Services對象做緩存。
          SOAP消息Handler能夠訪問代表RPC請求或者響應的SOAP消息。在JAX-RPC技術(shù)中,SOAP消息Handler可以部署在服務(wù)端,也可以在客戶端使用。

          下面我們來看一個典型的SOAP消息Handler處理順序:
          某個在線支付服務(wù)需要防止非授權(quán)的用戶訪問或者撰改服務(wù)端和客戶端傳輸?shù)男畔?,從而使用消息摘要(Message Digest)的方法對請求和響應的SOAP消息進行加密。當客戶端發(fā)送SOAP消⑹保?突Ф說?andler把請求消息中的某些敏感的信息(如信用卡密碼)進行加密,然后把加密后的SOAP消息傳輸?shù)椒?wù)端;服務(wù)端的SOAP消息Handler截取客戶端的請求,把請求的SOAP 消息進行解密,然后把解密后的SOAP消息派發(fā)到目標的Web服務(wù)端點。

          Apache axis是我們當前開發(fā)Web服務(wù)的較好的選擇,使用axisWeb服務(wù)開發(fā)工具,可以使用Handler來對服務(wù)端的請求和響應進行處理。典型的情況下,請求傳遞如圖1所示。




          圖1 SOAP消息的傳遞順序


          在圖中,軸心點(pivot point)是Apache與提供程序功能相當?shù)牟糠郑ㄟ^它來和目標的Web服務(wù)進行交互,它通常稱為Provider。axis中常用的Provider有Java:RPC,java:MSG,java:EJB。一個Web服務(wù)可以部署一個或者多個Handler。

          Apache axis中的Handler體系結(jié)構(gòu)和JAX-RPC 1.0(JSR101)中的體系結(jié)構(gòu)稍有不同,需要聲明的是,本文的代碼在axis中開發(fā),故需要在axis環(huán)境下運行。

          在axis環(huán)境下,SOAP消息Handler必須實現(xiàn)org.apache.axis.Handler接口(在JAX-RPC 1.0規(guī)范中,SOAP消息Handler必須實現(xiàn)javax.xml.rpc.handler.Handler接口),org.apache.axis.Handler接口的部分代碼如下:

          例程1 org.apache.axis.Handle的部分代碼


          public interface Handler extends Serializable {
          ? public void init();
          ? public void cleanup();
          ? public void invoke(MessageContext msgContext) throws AxisFault ;

          ? public void onFault(MessageContext msgContext);
          ? public void setOption(String name, Object value); ?
          ? public Object getOption(String name);
          ?
          ? public void setName(String name); ?
          ? public String getName(); ?
          ? public Element getDeploymentData(Document doc);
          ? public void generateWSDL(MessageContext msgContext) throws AxisFault;
          ? …
          }



          為了提供開發(fā)的方便,在編寫Handler時,只要繼承org.apache.axis.handlers. BasicHandler即可,BasicHandler是Handler的一個模板,我們看它的部分代碼:

          例程2 BasicHandler的部分代碼


          public abstract class BasicHandler implements Handler {
          ? protected static Log log =
          ? ? LogFactory.getLog(BasicHandler.class.getName());
          ? protected Hashtable options;
          ? protected String name;
          ? //這個方法必須在Handler中實現(xiàn)。
          public abstract void invoke(MessageContext msgContext) throws AxisFault;
          public void setOption(String name, Object value) {
          ? ? if ( options == null ) initHashtable();
          ? ? options.put( name, value );
          ? }

          }



          BasicHandler中的(MessageContext msgContext)方法是Handler實現(xiàn)類必須實現(xiàn)的方法,它通過MessageContext來獲得請求或者響應的SOAPMessage對象,然后對SOAPMessage進行處理。

          在介紹Handler的開發(fā)之前,我們先來看一下目標Web服務(wù)的端點實現(xiàn)類的代碼,如例程3所示。

          例程3 目標Web服務(wù)的端點實現(xiàn)類


          package com.hellking.webservice;
          public class HandleredService
          {
          //一個簡單的Web服務(wù)
          public String publicMethod(String name)
          {
          return "Hello!"+name;
          }
          }
          //另一個Web服務(wù)端點:
          package com.hellking.webservice;
          public class OrderService
          {
          ? ? //web服務(wù)方法:獲得客戶端的訂單信息,并且對訂單信息進行對應的處理,
          通常情況是把訂單的信息寫入數(shù)據(jù)庫,然后可客戶端返回確認信息。
          public String orderProduct(String name,String address,String item,int quantity,Card card)
          {
          String cardId=card.getCardId();
          String cardType=card.getCardType();
          String password=card.getPassword();
          String rderInfo="name="+name+",address="+address+",item="+item+",quantity="+quantity+"
          ,cardId="+cardId+",cardType="+cardType+",password="+password;
          System.out.println("這里是客戶端發(fā)送來的信息:");
          System.out.println(orderInfo);
          return orderInfo;
          }
          }



          下面我們分不同情況討論Handler的使用實例。

          使用Handler為系統(tǒng)做日志

          Handler為系統(tǒng)做日志是一種比較常見而且簡單的使用方式。和Servlet中的Filter一樣,我們可以使用Handler來把用戶的訪問寫入系統(tǒng)日志。下面我們來看日志Handler的具體代碼,如例程4所示。

          例程4 LogHandler的代碼


          package com.hellking.webservice;

          import java.io.FileOutputStream;
          import java.io.PrintWriter;
          import java.util.Date;

          import org.apache.axis.AxisFault;
          import org.apache.axis.Handler;
          import org.apache.axis.MessageContext;
          import org.apache.axis.handlers.BasicHandler;

          public class LogHandler extends BasicHandler {

          ? /**invoke,每一個handler都必須實現(xiàn)的方法。
          */
          ? public void invoke(MessageContext msgContext) throws AxisFault
          ? {
          ? ? //每當web服務(wù)被調(diào)用,都記錄到log中。
          ? ? try {
          ? ? ? ? Handler handler = msgContext.getService();
          ? ? ? ? String filename = (String)getOption("filename");
          ? ? ? ? if ((filename == null) || (filename.equals("")))
          ? ? ? ? ? throw new AxisFault("Server.NoLogFile",
          ? ? ? ? ? ? ? ? ? ? ? "No log file configured for the LogHandler!",
          ? ? ? ? ? ? ? ? ? ? ? ? null, null);
          ? ? ? ? FileOutputStream fos = new FileOutputStream(filename, true); ? ? ? ?
          ? ? ? ? PrintWriter writer = new PrintWriter(fos); ? ? ? ?
          ? ? ? ? Integer counter = (Integer)handler.getOption("accesses");
          ? ? ? ? if (counter == null)
          ? ? ? ? ? counter = new Integer(0);
          ? ? ? ?
          ? ? ? ? counter = new Integer(counter.intValue() + 1); ? ? ? ?
          ? ? ? ? Date date = new Date();
          ? ? ? ? msgContext.getMessage().writeTo(System.out);
          ? ? ?
          ? ? ? ? String result = "在"+date + ": Web 服務(wù) " +
          ? ? ? ? ? ? ? ? ? msgContext.getTargetService() +
          ? ? ? ? ? ? ? ? ? " 被調(diào)用,現(xiàn)在已經(jīng)共調(diào)用了 " + counter + " 次.";
          ? ? ? ? handler.setOption("accesses", counter); ? ? ? ?
          ? ? ? ? writer.println(result); ? ? ? ?
          ? ? ? ? writer.close();
          ? ? } catch (Exception e) {
          ? ? ? ? throw AxisFault.makeFault(e);
          ? ? }
          ? }
          }



          前面我們說過,Handler實現(xiàn)類必須實現(xiàn)invoke方法,invoke方法是Handler處理其業(yè)務(wù)的入口點。LogHandler的主要功能是把客戶端訪問的Web服務(wù)的名稱和訪問時間、訪問的次數(shù)記錄到一個日志文件中。

          下面部署這個前面開發(fā)的Web服務(wù)對像,然后為Web服務(wù)指定Handler。編輯Axis_Home/WEB-INF/ server-config.wsdd文件,在其中加入以下的內(nèi)容:



          <service name="HandleredService" provider="java:RPC">
          <parameter name="allowedMethods" value="*"/>
          <parameter name="className" value="com.hellking.webservice.HandleredService"/>
          <parameter name="allowedRoles" value="chen"/>
          <beanMapping languageSpecificType="java:com.hellking.webservice.Card"
          qname="card:card" xmlns:card="card"/>
          <requestFlow>
          <handler name="logging" type="java:com.hellking.webservice.LogHandler">
          <parameter name="filename" value="c:\\MyService.log"/>
          </handler>
          </requestFlow>
          </service>





          </globalConfiguration>

          <handler name="logging" type="java:com.hellking.webservice.LogHandler">
          <parameter name="filename" value="c:\\MyService.log"/>
          </handler>

          <service name="HandleredService" provider="java:RPC">

          <requestFlow>
          <handler type="logging"/>
          ? …<!--在這里可以指定多個Handler-->
          </requestFlow>
          </service>




          http://127.0.0.1:8080/handler/services/HandleredService?wsdl&method=publicMethod&name=chen



          注意:這個URL需要根據(jù)具體情況改變。



          在Sun Jul 06 22:42:03 CST 2003: Web 服務(wù) HandleredService 被調(diào)用,現(xiàn)在已經(jīng)共調(diào)用了 1 次.
          在Sun Jul 06 22:42:06 CST 2003: Web 服務(wù) HandleredService 被調(diào)用,現(xiàn)在已經(jīng)共調(diào)用了 2 次.
          在Sun Jul 06 22:42:13 CST 2003: Web 服務(wù) HandleredService 被調(diào)用,現(xiàn)在已經(jīng)共調(diào)用了 3 次.

          使用Handler對用戶的訪問認證

          使用Handler為用戶訪問認證也是它的典型使用,通過它,可以減少在Web服務(wù)端代碼中認證的麻煩,同時可以在部署描述符中靈活改變用戶的訪問權(quán)限。

          對用戶認證的Handler代碼如下:

          例程5 認證的Handler


          package com.hellking.webservice;
          import….

          //此handler的目的是對用戶認證,只有認證的用戶才能訪問目標服務(wù)。
          public class AuthenticationHandler extends BasicHandler
          {
          /**invoke,每一個handler都必須實現(xiàn)的方法。
          */
          public void invoke(MessageContext msgContext)throws AxisFault
          {
          ? ? SecurityProvider provider = (SecurityProvider)msgContext.getProperty("securityProvider");
          if(provider==null)
          {
          ? provider= new SimpleSecurityProvider();
          ? ? ? ? msgContext.setProperty("securityProvider", provider);
          ? ? ? }
          ? ? if(provider!=null)
          ? ? { ? ? ?
          ? ? ? String userId=msgContext.getUsername();
          ? ? ? String password=msgContext.getPassword();
          ? ? ?
          ? ? ? //對用戶進行認證,如果authUser==null,表示沒有通過認證,
          拋出Server.Unauthenticated異常。
          ? ? ? ? org.apache.axis.security.AuthenticatedUser authUser
          = provider.authenticate(msgContext);
          ? ? ? ? if(authUser==null)
          ? ? ? ? throw new AxisFault("Server.Unauthenticated",
          Messages.getMessage("cantAuth01", userId), null,null);
          ? ? ? ? //用戶通過認證,把用戶的設(shè)置成認證了的用戶。
          ? ? ? ? msgContext.setProperty("authenticatedUser", authUser);
          ? ? }
          ? }
          }



          在AuthenticationHandler代碼里,它從MessageContext中獲得用戶信息,然后進行認證,如果認證成功,那么就使用msgContext.setProperty("authenticatedUser", authUser)方法把用戶設(shè)置成認證了的用戶,如果認證不成功,那么就拋出Server.Unauthenticated異常。

          部署這個Handler,同樣,在server-config里加入以下的內(nèi)容:



          <handler name="authen" type="java:com.hellking.webservice.AuthenticationHandler"/>

          <service name="HandleredService" provider="java:RPC">
          <parameter name="allowedRoles" value="chen"/>

          </service>



          WEB-INF/users.lst文件中加入以下用戶:



          hellking hellking
          chen chen




          http://127.0.0.1:8080/handler/services/HandleredService?wsdl&method=publicMethod&name=chen



          將會提示輸入用戶名和密碼,如圖2所示。




          圖2 訪問web服務(wù)時的驗證

          如果客戶端是應用程序,那么可以這樣在客戶端設(shè)置用戶名和密碼:

          例程6 在客戶端設(shè)置用戶名和密碼


          http://127.0.0.1:808
          String endpointURL = "http://127.0.0.1:8080/handler/services/HandleredService?wsdl"; ? ? ? ?
          ? ? ? ? Service service = new Service();
          ? ? ? ? Call ? call ? = (Call) service.createCall();
          ? ? ? ? call.setTargetEndpointAddress( new java.net.URL(endpointURL) );
          ? ? ? ? call.setOperationName( new
          QName("HandleredService", "orderProduct") );//設(shè)置操作的名稱。
          ? ? ? ? //由于需要認證,故需要設(shè)置調(diào)用的用戶名和密碼。
          ? ? ? ? call.getMessageContext().setUsername("chen");
          ? ? ? ? call.getMessageContext().setPassword("chen");??????


          posted on 2007-01-14 17:05 嘎崩豆 閱讀(608) 評論(1)  編輯  收藏

          Feedback

          # re: Axis 學習筆記(ZZ)[未登錄] 2007-01-15 10:55 壞男孩
          頂  回復  更多評論
            


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


          網(wǎng)站導航:
           
          主站蜘蛛池模板: 镇雄县| 云安县| 信阳市| 山阴县| 邮箱| 丹寨县| 西丰县| 壤塘县| 岳阳市| 台湾省| 芮城县| 闽清县| 枝江市| 广宁县| 施甸县| 南溪县| 六枝特区| 威宁| 宜黄县| 土默特左旗| 东乌珠穆沁旗| 肇东市| 宜兴市| 台北县| 昌吉市| 龙泉市| 特克斯县| 高陵县| 丹江口市| 东台市| 乃东县| 普兰店市| 曲沃县| 冷水江市| 双鸭山市| 玉门市| 岱山县| 彭山县| 曲阳县| 友谊县| 贵定县|