J2EE设计模式浅谈(二)之Filter
zhaum@studyJava.com
其实J2EE中太多的定义是很烦人的,设计模式也很抽象的,今天我就以Servlet2.3中新增的Filter在Web Application中的应用,来进一步的说明设计模式。 首先假设我们现在想做一个Web Application(例如BBS)。 要求具备下列功能: 1、 在用户发帖子之前,要进行身份认证,以确认该用户是已登陆用户。 2、 其次是要对删除帖子,修改帖子,进行权限检查。 3、 访问特定资源(Web 页、JSP 页)时的身份认证 那么对待这些要求我们该怎么去做,如果在每个页面中都写检查权限的代码,不是一个好想法,且使的程序的可重用性降低,对比设计模式Intercepting Filter(截获过滤)正好符合我们的要求,且在Servlet2.3中通过使用过滤器(Filter)能够使得Web Application开发者能够在请求到达Web资源之前截取请求,在处理请求之后修改应答。 一个执行过滤器的Java 类必须实现javax.servlet.Filter 接口。这一接口含有三个方法: · init(FilterConfig):这是容器所调用的初始化方法。它保证了在第一次 doFilter() 调用前由容器调用。它能获取在 web.XML 文件中指定的filter初始化参数(文章的后面有lightningboard 的web.xml文件)。 · doFilter(ServletRequest, ServletResponse, FilterChain):这是一个完成过滤行为的方法。它同样是上一个过滤器调用的方法。引入的 FilterChain 对象提供了后续过滤器所要调用的信息,Filter中因为有了 FilterChain,就使的几个FILTER 成了一个链条。 · destroy():容器在销毁过滤器实例前,doFilter()中的所有活动都被该实例终止后,调用该方法 在开源的lightningboard BBS中实现了两个Filter,如下 1、ControllerFilter在这里起到的是Front Controller(前端控制器)的作用,是MVC模式中的控制器,是该BBS的入口点。 package lightningboard;
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.Filter; import javax.servlet.FilterConfig; import javax.servlet.FilterChain; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import lightningboard.action.*;
/** * Control all *.do. * @version 0.3.5 * @author Xiaobo Liu */ public class ControllerFilter implements Filter {
/** * Action dispatch
* example: homde.do will be create HomeAction and call its excute() method. */ protected FilterConfig filterConfig;
public void init(FilterConfig config) { this.filterConfig = config; }
public void destroy() { this.filterConfig = null; } public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain filterChain) throws IOException, ServletException{ HttpServletRequest request = (HttpServletRequest)srequest; HttpServletResponse response = (HttpServletResponse)sresponse;
long timeStart=System.currentTimeMillis();
Configuration cfg=Configuration.getInstance(); String encoding=cfg.getValue('SYS.ENCODING'); request.setCharacterEncoding(encoding);
String path = (String) request.getRequestURI(); String actionString = path.substring(path.lastIndexOf('/') + 1,path.lastIndexOf('.')); String forwardPage=null; try { if(actionString.equals('forum')) forwardPage=new ForumAction().excute(request,response); else if(actionString.equals('topic')) forwardPage=new TopicAction().excute(request,response); else if(actionString.equals('user')) forwardPage=new UserAction().excute(request,response); else if(actionString.equals('userList')) forwardPage=new UserListAction().excute(request,response); else if(actionString.equals('login')) forwardPage=new LoginAction().excute(request,response); else if(actionString.equals('reGISter')) forwardPage=new RegisterAction().excute(request,response); else if(actionString.equals('post')) forwardPage=new PostAction().excute(request,response); else if(actionString.equals('postP')) forwardPage=new PostPAction().excute(request,response); else if(actionString.equals('userEdit')) forwardPage=new UserEditAction().excute(request,response); else if(actionString.equals('userEditP')) forwardPage=new UserEditPAction().excute(request,response); else if(actionString.equals('logout')) forwardPage=new LogoutAction().excute(request,response); else //default: home forwardPage=new HomeAction().excute(request,response); }catch (ActionException ex) { Debug.out(ex); request.setAttribute('actionMessage',new ActionMessage('system_error')); forwardPage='/actionMessage.jsp'; } // forward page if (forwardPage!=null){ String processTime=''+(System.currentTimeMillis()-timeStart); request.setAttribute('processTime',processTime); filterConfig.getServletContext().getRequestDispatcher(forwardPage).forward(request,response); } } }
2、此FILTER起的是Intercepting Filter(截获过滤)的作用。 package lightningboard.filter; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.Filter; import javax.servlet.FilterConfig; import javax.servlet.FilterChain; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession;
public class SessionAuthorizationFilter implements Filter { protected FilterConfig filterConfig;
public void init(FilterConfig config) { this.filterConfig = config; }
public void destroy() { this.filterConfig = null; }
private boolean passed(ServletRequest request, ServletResponse response) throws IOException, ServletException { boolean result=false; String objectName=this.filterConfig.getInitParameter('OBJECT_NAME'); HttpServletRequest req = (HttpServletRequest)request; HttpSession session =req.getSession(false); if(session!=null){ Object object=session.getAttribute(objectName); if(object!=null) result= true; } return result; }
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException{ if (passed(request,response)) filterChain.doFilter(request, response); else{ HttpServletResponse res = (HttpServletResponse)response; String errorPage=this.filterConfig.getInitParameter('ERROR_PAGE'); res.sendRedirect(errorPage); } } } 容器通过 Web 应用程序中的配置描述符 web.xml 文件解析过滤器配置信息。有两个新的标记与过滤器相关: 和 。 标记是一个过滤器定义,它必定有一个 和 子元素。 子元素给出了一个与过滤器实例相关的名字。 指定了由容器载入的实现类。您能随意地包含一个 子元素为过滤器实例提供初始化参数。 标记代表了一个过滤器的映射,指定了过滤器会对其产生作用的 URL 的子集。
lightningboard 项目中的web.xml文件如下:
controllerFilter lightningboard.ControllerFilter sessionAuthorizationFilter lightningboard.filter.SessionAuthorizationFilter ERROR_PAGE login.jsp OBJECT_NAME loginBean sessionAuthorizationFilter /post.do sessionAuthorizationFilter /postP.do sessionAuthorizationFilter /post.jsp sessionAuthorizationFilter /userEdit.do sessionAuthorizationFilter /userEditP.do sessionAuthorizationFilter /userEdit.jsp sessionAuthorizationFilter /userList.do controllerFilter *.do index.html
由于本人水平有限,不当之处还请指正,谢谢!!!
|