JavaWebのデコレーションHttpService Requestオブジェクト

7449 ワード


HttpServeretRequestオブジェクトの装飾
 
需要:HttpServeretRequestオブジェクトがServeretに到達する前に、ユーザーが入力した余分なスペースをすべて削除します.
シナリオ:HttpServiceletRequestオブジェクトのリクエストパラメータはjavaに実際に含まれているからです.util.Mapオブジェクトには、Mapは修正が許可されていないため、HttpServeretRequestオブジェクトに含まれるリクエストパラメータは変更できません.
ソリューション:デコレータモード
 
装飾モードを使用してHttpServiceletRequestを強化する理由(HttpServiceletRequestWrapperを使用する理由)まず、機密コンテンツ処理を実現するフィルタの実現を見てみましょう.
 
 
package org.rabbitx.web.javaweb.filter.example;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.rabbitx.web.javaweb.filter.HttpFilter;
import org.rabbitx.web.javaweb.filter.MyHttpServletRequest;

public class ContentFilter extends HttpFilter{

    public void doFilter(HttpServletRequest request,
    		HttpServletResponse response, FilterChain filterChain)
    		throws IOException, ServletException {
    	//1.      content     
    	String content = request.getParameter("content");
    	
    	//2.     fuck, shit          ****
    	if(content.contains(" fuck ")){
    		//ServletRequest, HttpServletRequest          setParameter(paramName, paramValue)
    		//        . 
    		
    		//  :    HttpServletRequest   getParameter(String)      :          
    		//   " fuck ",      " **** "
    	}
    	
    	//3.       
    	filterChain.doFilter(req, response);
    }

}
  
 
実装において、SetParameter(paramName,paramValue)のような方法は提供する、SetpServertRequest,HttpServertRequestには提供されていないという問題がある.getParameter(String)メソッドを書き換えるしかありません.
1.クラスのメソッドに不満がある場合は、書き換える必要があり、最も一般的な方法は、親クラスを継承し、書き換える方法である.実現するにはorgを継承する必要がある.apache.catalina.connector.RequestFacade、これはTomcatサーバの実装のみであり、サーバを交換するとこのスキームは使用できない.具体的な容器と結合する、移植性がない.
2.HttpServertRequestインタフェースの実装クラスを直接書く:面倒で、具体的な容器と結合する必要がある.
 
上記の2つの方法が理想的ではないことがわかりました.3つ目の方法を見てみましょう.
 
現在のHttpServiceletRequestオブジェクトを装飾する:getParameterメソッドを装飾するが、他のメソッドはその実装と同じである.HttpServiceletRequestインタフェースを実装クラスを作成し、現在のdoFilterのrequestをそのクラスに転送し、そのメンバー変数として、そのメンバー変数を用いてインタフェースのすべての方法を実現する.強化や変更を必要としない方法は、装飾クラスで書き換えることができます. 
 
具体的な実装
 
 
package org.rabbitx.web.javaweb.filter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class MyHttpServletRequest extends HttpServletRequestWrapper{

	public MyHttpServletRequest(HttpServletRequest request) {
		super(request);
	}
	
	@Override
	public String getParameter(String name) {
		String val = super.getParameter(name);
		if(val != null && val.contains(" fuck ")){
			val = val.replace("fuck", "****");
		}
		return val;
	}
}
  
 
 
 
package org.rabbitx.web.javaweb.filter.example;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.rabbitx.web.javaweb.filter.HttpFilter;
import org.rabbitx.web.javaweb.filter.MyHttpServletRequest;

public class ContentFilter extends HttpFilter{

    public void doFilter(HttpServletRequest request,
    		HttpServletResponse response, FilterChain filterChain)
    		throws IOException, ServletException {
    	//1.      content     
    	String content = request.getParameter("content");
        //      
    	HttpServletRequest req = new MyHttpServletRequest(request);

    	//3.       
    	filterChain.doFilter(req, response);
    }

}
 
 
 
HttpServeretWrapperとHttpServeretResponseWrapper
 
1). サーブレットAPIには、元のrequestオブジェクトをパッケージするHttpサーブレットRequestWrapperクラスが用意されています.
HttpServereRequestWrapperクラスは、HttpServereRequestインタフェースのすべての方法を実装します.
これらのメソッドの内部実装は,パッケージされたrequestオブジェクトを呼び出すだけの対応メソッドである.
 
//包装類はサーブレットRequestインタフェースを実現する. 
public class ServletRequestWrapper implements ServletRequest {
 
//ラッピングされたサーブレットリクエストオブジェクト
    private ServletRequest request;
 
//コンストラクタ受信サーブレットRequest実装クラスオブジェクト
    public ServletRequestWrapper(ServletRequest request) {
if (request == null) {
   throw new IllegalArgumentException("Request cannot be null");   
}
this.request = request;
    }
 
//サーブレットRequestを具体的に実装する方法:パッケージされたメンバー変数を呼び出す方法実装. 
    public Object getAttribute(String name) {
return this.request.getAttribute(name);
}
 
    public Enumeration getAttributeNames() {
return this.request.getAttributeNames();
}    
 
//...
}
 
同様のサーブレットAPIでは、元のresponseオブジェクトをパッケージするHttpサーブレットResponseWrapperクラスも提供されています.
 
2). 作用:HttpServeretRequestまたはHttpServeretResponseのいずれかの方法を修正または強化する.
 
public class MyHttpServletRequest extends HttpServletRequestWrapper{
 
public MyHttpServletRequest(HttpServletRequest request) {
super(request);
}
 
@Override
public String getParameter(String name) {
String val = super.getParameter(name);
if(val != null && val.contains("fuck ")){
val = val.replace("fuck", "****");
}
return val;
}
}
 
3). 使用:Filterで、受信したHttpServertRequestをMyHttpServertRequestに置き換えます.
 
HttpServletRequest req = new MyHttpServletRequest(request);
filterChain.doFilter(req, response);
 
この時点でターゲットサーブレットまたはJSPに到達するHttpサーブレットRequestは、実際にはMyHttpサーブレットRequestである
 
 
Decoratorモード
 
継承関係のため,あるオブジェクトの動作を変更する必要がある場合,そのオブジェクトが属するクラスを拡張し,その関連メソッドを書き換えるだけで目的を達成できる.ただし、動作を変更するオブジェクトがアプリケーション内の別のサブシステム(たとえば、オブジェクトファクトリまたはサーブレットコンテナ)によって構成されている場合、継承メカニズムは機能しません.
 
 
Decoratorモード----シナリオ
 
既知:Messagerクラスの定義(派生先の1つなど)Messagerオブジェクトは常にオブジェクトファクトリ(MessagerFactory)から作成されます.このファクトリでは、作成した各Messagerオブジェクトを初期化できます.getMessage()メソッドを呼び出すことで得られるmessageプロパティも例外ではありません.つまり、Messagerオブジェクトを初期化できません.
仮定:MessagerクラスのgetMessage()メソッドを使用する必要があります.Utilの使用ツールクラスがあります.このクラスには次の方法があります.
      public static void broadcast(Message messager){
          System.out.println(messager.getMessage());
      }
 
Decoratorモード----需要、方案
 
需要:broadcastメソッドで印刷するアルファベットはすべて大文字です
シナリオ:Messagerクラスからサブクラスが派生し、サブクラスオブジェクトをbroadcastメソッドに渡します.オブジェクトファクトリのみがMessagerオブジェクトを初期化する方法を知っているため、このスキームは意味がありません.
Decoratorモード:
MessagerクラスからサブクラスMessagerDecoratorが派生し、サブクラスオブジェクトをbroadcastメソッドに渡す
Messager Decoratorクラスでコンストラクタを実装する:入力パラメータとしてMessagerオブジェクトを受け入れるが、このMessagerは装飾したいオブジェクトである:public Messager Decorator(Messager)
getMessageメソッドを書き換え、書き換えメソッドを大文字でmessageプロパティに戻す
 
 
HttpServeretRequestWrapperクラス
 
サーブレットAPIには、元のrequestオブジェクトをパッケージングするためのHttpサーブレットRequestWrapperクラスが用意されています.HttpサーブレットRequestWrapperクラスは、パッケージングされたrequestオブジェクトを呼び出すだけの対応方法です.
同様のサーブレットAPIでは、元のresponseオブジェクトをパッケージするHttpサーブレットResponseWrapperクラスも提供されています.