zoukankan      html  css  js  c++  java
  • 设计模式的应用-模版方法解决多种角色的登录过滤

    在报名系统中,登录的有两类用户,后台管理员和报名参与者,而他们都有些操作必须登录才能执行,传统的Java Web应用中使用过滤器对指定的路径进行过滤。

    管理员登录拦截器

    下面拦截管理员,定义登录过滤器AuthorLoginFilter

    /**
     * 管理员的登录过滤器
     */
    public class ManagerLoginFilter implements Filter {
    
        /** 白名单:从web.xml中读取配置 */
        protected Set<String> whiteList = new HashSet<>();
        
        /**
         * 过滤动作
         */
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
                throws IOException, ServletException {
    
            //1. 得到应用的uri
            if(!whiteList.contains(uri)) {
                //2. 不在白名单的路径(需要过滤的)
                //3. 获取session中的值?
                if( author == null) {
                    //4. 未登录或登录超时,设置提示信息,重定向到指定路径?
                    return;
                }
            }
            chain.doFilter(req, resp);
        }
        ....
    }
    

    web.xml中使用过滤器:

    <filter>
        <description>管理员登录过滤</description>
        <filter-name>managerLoginFilter</filter-name>
        <filter-class>web.filter.ManagerLoginFilter</filter-class>
        <init-param>
            <!-- 登录页面和登录动作 -->
            <param-name>whiteList</param-name>
            <param-value>
                /manage/login.do;/manage/;
            </param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>managerLoginFilter</filter-name>
        <url-pattern>/manage/*</url-pattern>
    </filter-mapping>
    

    发现问题,重构

    现在定义UserLoginFilter过滤,拦截活动参与者需要登录才能执行的URL。于是COPY上面的代码,改改!!!

    doFilter(...) {
        ...
        // 修改第3步中获得session中的key值: session.getAttribute("CURRENT_USER");
        // 修改第4步中的重定向URL
    }
    

    But问题来了????,有没有发觉代码和处理流程惊人的相似,除了上面需要修改的地方。

    定义抽象方法

    于是我使用模版方法重构, 定义一个抽象公共的父过滤器LogFilter:

    /**
     * 抽象的登录过滤器
     * 利用模版设计模式,实现封装
     * @author 
     *
     */
    public abstract class LoginFilter implements Filter {
    
        protected Set<String> whiteList = new HashSet<>();
    
        /**
         * 对应第3步:获取不同类型的登录对象
         * @param session
         * @return
         */
        protected abstract Object getLoginObject(HttpSession session);
        
        /**
         * 对应第4步:获得重定向路径
         * @param request
         * @return
         */
        protected abstract String getRedirectPath(HttpServletRequest request);
        
        
        public void destroy() {
        }
    
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
                throws IOException, ServletException {
    
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) resp;
            HttpSession session = request.getSession();
            
            // 第1步:得到出去应用名的uri
            String uri = request.getRequestURI();
            String contextPath = request.getContextPath();
            if(uri.startsWith( contextPath )) {
                uri = uri.replaceFirst(contextPath,"");
            }
            
            // 第2步:拦截不在白名单中,且未登录的请求
            if(!whiteList.contains(uri)) {
                // 第3步:钩子方法,利用多态特效,调用具体实现的方法
                Object targetObject= getLoginObject(session);
                if(targetObject == null) {
                    session.setAttribute("message", "登录超时,重新登录");
                    // 第4步:钩子方法,利用多态特性,调用具体的方法实现
                    response.sendRedirect( getRedirectPath(request));
                    return;
                }
            }
            
            chain.doFilter(req, resp);
        }
    
        public void init(FilterConfig config) throws ServletException {
            String configWhiteData = config.getInitParameter("whiteList");
            // 有配置参数
            if( !StringUtil.isBlank(configWhiteData) ) {
                String[] whites = configWhiteData.split(";"); 
                for (String white : whites) {
                    this.whiteList.add(white.trim());
                }
            }
        }
    
    }
    
    

    具体的过滤器实现

    /**
     * 管理员登录过滤器
     * @author 
     *
     */
    public class ManagerLoginFilter extends LoginFilter{
    
        @Override
        protected Object getLoginObject(HttpSession session) {
            return session.getAttribute("CURRENT_MANAGER");
        }
    
        @Override
        protected String getRedirectPath(HttpServletRequest request) {
            return request.getContextPath() + "/manage/login.do";
        }
    
    }
    
    /**
     * 参与者(用户)登录过滤器
     * @author 
     *
     */
    public class UserLoginFilter extends LoginFilter{
    
        @Override
        protected Object getLoginObject(HttpSession session) {
            return session.getAttribute("CURRENT_USER");
        }
    
        @Override
        protected String getRedirectPath(HttpServletRequest request) {
            return request.getContextPath() + "/index.do";
        }
    
    }
    

    web.xml配置文件

    <filter>
        <description>管理员登录过滤</description>
        <filter-name>managerLoginFilter</filter-name>
        <filter-class>web.filter.ManagerLoginFilter</filter-class>
        <init-param>
            <param-name>whiteList</param-name>
            <param-value>
                /manage/login.do;/manage/;
            </param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>managerLoginFilter</filter-name>
        <url-pattern>/manage/*</url-pattern>
    </filter-mapping>
    
    <filter>
        <description>参与者登录过滤</description>
        <filter-name>userLoginFilter</filter-name>
        <filter-class>web.filter.UserLoginFilter</filter-class>
        <init-param>
            <param-name>whiteList</param-name>
            <param-value></param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>userLoginFilter</filter-name>
        <url-pattern>/user/*</url-pattern>
    </filter-mapping>
    

    总结

    对于某一类问题,具有相同的解决步骤,但是每一步具体的实现可能不一致,可能这个时候就可以使用模版方法。

    那么这个问题能否用策略模式解决了????不能

  • 相关阅读:
    得到cxgrid筛选后的记录数
    服务器之ipmitool
    CentOS6.8部署SVN
    NGINX快速部署
    Nginx模块系列之auth_basic模块
    持续集成、持续交付、持续部署
    CentOS6.X 升级内核至 3.10
    Dmidecode
    新建虚拟机
    Linux之(tomcat)服务之服务调优
  • 原文地址:https://www.cnblogs.com/lkqm/p/6435740.html
Copyright © 2011-2022 走看看