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クラスも提供されています.