理解过滤器就要很好的理解这个设计模式才行-------责任链设计模式(或者说过滤器设计模式)
参看责任链设计模式(过滤器、拦截器)
责任链设计模式(Chain of Responsibility)的应用有:Java Web中的过滤器链、Struts2中的拦截器栈。
先看一个问题:
给定一个字符串“被就业了:),敏感信息,
本文主要以该问题设计方法的演变来讲解责任链设计模式。
第一种设计:没有任何设计模式
设计了一个MsgProcessor类,完成字符串处理的主要工作。MainClass类是本设计中的测试类。
public class MainClass {
public static void main(String[] args) {
//需要被过滤的语句
String msg = "被就业了:),敏感信息,
//实例化处理类
MsgProcessor mp = new MsgProcessor(msg);
String r = mp.process();
System.out.println(r);
}
}
public class MsgProcessor {
private String msg;
public MsgProcessor(String msg){
this.msg = msg;
}
public String process(){
String r = msg;
//过滤msg中的HTML标记
r = r.replace("<", "<").replace(">", ">");
//过滤敏感词
r = r.replace("敏感", "").replace("被就业", "就业");
return r;
}
}
第二种设计:增加一个Filter接口
在第一种设计中,对字符串的所有处理都放在MsgProcessor类中,扩展性极差。如果要过滤字符串中的笑脸(将”:)”替换成”^_^”),则需要改动MSgProcessor中的process方法。
public interface Filter {
String doFilter(String str);
}
public class HtmlFilter implements Filter {
public String doFilter(String msg) {
String r = msg;
//过滤msg中的HTML标记
r = r.replace("<", "<").replace(">", ">");
return r;
}
}
public class SensitiveFilter implements Filter {
public String doFilter(String msg) {
String r = msg;
//过滤敏感词
r = r.replace("敏感", "").replace("被就业", "就业");
return r;
}
}
public class MsgProcessor {
private String msg;
private Filter[] filters = {new HtmlFilter(),new SensitiveFilter()};
public MsgProcessor(String msg){
this.msg = msg;
}
public String process(){
String r = msg;
for(Filter f : filters){
r = f.doFilter(r);
}
return r;
}
}
此时,如果需要过滤字符串中的笑脸,只需要创建一个类FaceFilter实现Filter接口,并在MsgProcessor类中的filters字段中登记即可。
第三种设计:责任链模式(FilterChain)定义:将一个事件处理流程分派到一组执行对象上去,这一组执行对象形成一个链式结构,事件处理请求在这一组执行对象上进行传递。责任链模式的主要参与角色:
① 事件处理请求对象(Request)
② 执行对象(Handler)
public class FilterChain implements Filter {
public List filters= new ArrayList();
public FilterChain addFilter(Filter f){
filters.add(f);
return this;
}
public String doFilter(String msg) {//执行filters中的doFilter方法即可
String r = msg;
for(Filter f : filters){
r = f.doFilter(r);
}
return r;
}
}
public class MsgProcessor {
private String msg;
private FilterChain chain = new FilterChain();
public MsgProcessor(String msg,Filter Chain){
this.msg = msg;
this.chain = chain;
}
public String process(){
return chain.doFilter(msg);
}
}
public class MainClass {
public static void main(String[] args) {
//需要被过滤的语句
String msg = "被就业了:),敏感信息,
//搞一个过过滤链
FilterChain chain = new FilterChain();
chain.addFilter(new HtmlFilter()).addFilter(new SensitiveFilter());
//实例化处理类
MsgProcessor mp = new MsgProcessor(msg,chain);
String r = mp.process();
System.out.println(r);
}
}
责任链模式加强版
上面的实现的过滤链可以用下图a)表示出来,整个过程只对msg过滤了一次。而JavaWeb中的过滤器链和Struts2中的拦截器栈执行的过程可以形象的表示为图b,☆很重要)。
下面用程序模拟JavaWeb中的过滤器,实现类似于对Request和Response的过滤。主要涉及的类如下所示:
public interface Filter {
void doFilter(Request req,Response resp,FilterChain chain);
}
public class HtmlFilter implements Filter {
public void doFilter(Request req, Response resp, FilterChain chain) {
//过滤req.reqStr中的HTML标记
req.reqStr = req.reqStr.replace("<", "<").replace(">", ">");
req.reqStr += "---HtmlFilter()---";
chain.doFilter(req, resp);
resp.respStr += "---HtmlFilter()---";
}
}
public class SensitiveFilter implements Filter {
public void doFilter(Request req, Response resp, FilterChain chain) {
// 过滤req.reqStr中的敏感词
req.reqStr = req.reqStr.replace("敏感", "").replace("被就业", "就业");
req.reqStr += "===SensitiveFilter";
chain.doFilter(req, resp);
resp.respStr += "===SensitiveFilter";
}
}
public class FilterChain{
private List filters = new ArrayList();
//调用链上的过滤器时,记录过滤器的位置用
private int index = 0;
public FilterChain addFilter(Filter f){
filters.add(f);
return this;
}
public void doFilter(Request req, Response resp) {
if(index == filters.size()) return;
//得到当前过滤器
Filter f = filters.get(index);
index++;
f.doFilter(req, resp, this);
}
}
public class Request {
//在Request中只保持了一个reqStr字段记录对Request的操作
//为了方便模拟,没有将reqStr设置为private
String reqStr;
}
public class Response {
//在Response中只保持了一个respStr字段记录对Response的操作
//为了方便模拟,没有将respStr设置为private
String respStr;
}
package org.flyne.fiter;
public class MainClass {
public static void main(String[] args) {
// 需要被过滤的语句
String msg = "被就业了:),敏感信息,
//创建Request、Response对象
Request req = new Request();
Response resp = new Response();
req.reqStr = msg;
resp.respStr = "response";
//搞一个过滤链,链上有两个过滤器
FilterChain chain = new FilterChain();
chain.addFilter(new HtmlFilter())
.addFilter(new SensitiveFilter());
//开始过滤
chain.doFilter(req, resp);
System.out.println(req.reqStr);
System.out.println(resp.respStr);
}
}
转载请注明: 东风化宇 2014年09月07日 于 Flyne 发表---------------------------------------------------------------------------------------------------------
下面我们看看Servlet中实现过滤器的操作,何其相似,如出一辙
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
public class EncodeFilter extends HttpServlet implements Filter
{
private FilterConfig filterConfig;
String encoding;
public void init(FilterConfig filterConfig) throws ServletException
{
encoding = filterConfig.getInitParameter("encoding");
this.filterConfig = filterConfig;
}
// Process the request/response pair
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
{
try
{
request.setCharacterEncoding(encoding);
response.setContentType("text/html;charset=UTF-8");
filterChain.doFilter(request, response);
} catch (ServletException sx)
{
filterConfig.getServletContext().log(sx.getMessage());
} catch (IOException iox)
{
filterConfig.getServletContext().log(iox.getMessage());
}
}
// Clean up resources
public void destroy()
{
}
}
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginFilter extends HttpServlet implements Filter
{
private static final long serialVersionUID = 1L;
private FilterConfig filterConfig;
// Handle the passed-in FilterConfig
public void init(FilterConfig filterConfig) throws ServletException
{
this.filterConfig = filterConfig;
}
// Process the request/response pair
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain)
{
try
{
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
HttpSession sess = request.getSession();
String page = request.getServletPath();
if (!"/index.jsp".equals(page) && !"/image.jsp".equals(page))
{
// 当前访问的不是登录页面
// 有没有登录过
if (sess.getAttribute("userName") == null)
{
// 没有登录
response.sendRedirect("index.jsp");
}
}
filterChain.doFilter(req, resp);
} catch (ServletException sx)
{
filterConfig.getServletContext().log(sx.getMessage());
} catch (IOException iox)
{
filterConfig.getServletContext().log(iox.getMessage());
}
}
// Clean up resources
public void destroy()
{
}
}
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class RightFilter extends HttpServlet implements Filter
{
private static final long serialVersionUID = 1L;
private FilterConfig filterConfig;
// Handle the passed-in FilterConfig
public void init(FilterConfig filterConfig) throws ServletException
{
this.filterConfig = filterConfig;
}
// Process the request/response pair
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain)
{
try
{
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
PrintWriter out = response.getWriter();
HttpSession sess = request.getSession();
// 从Session取出用户可以访问的地址
String[] rightUrl = (String[]) sess.getAttribute("rightUrl");
System.out.println("执行用户权限过滤");
String page = request.getServletPath();
System.out.println("你当前访问的路径为:" + page);
if ("/login.do".equals(page) || ("/myRight.do").equals(page))
{
filterChain.doFilter(request, response);
return;
}
boolean isCall = false;
for (int i = 0; i < rightUrl.length; i++)
{
if (page.equals(rightUrl[i]))
{
isCall = true;
break;
} else
{
isCall = false;
}
}
if (isCall == true)
{
System.out.println("允许访问");
filterChain.doFilter(request, response);
} else
{
System.out.println("无权访问");
out.print("对不起,您无权访问");
}
} catch (ServletException sx)
{
filterConfig.getServletContext().log(sx.getMessage());
} catch (IOException iox)
{
filterConfig.getServletContext().log(iox.getMessage());
}
}
// Clean up resources
public void destroy()
{
}
}上面三个过滤器就是使用了责任链设计模式的加强版本
下面看在web.xml当中的配置
encodefilter
com.sanqing.filter.EncodeFilter
encoding
UTF-8
encodefilter
/*
loginFilter
com.sanqing.filter.LoginFilter
loginFilter
*.jsp
rightfilter
com.sanqing.filter.RightFilter
rightfilter
*.do
不难想像Tomcat容器对这些配置和实现类做了什么事情,读取配置文件,将这些实现类全部加入到FilterChain中的List集合中去,当请求来的时候,首先调用FilterChain的doFilter()方法
------