设计模式的应用-模版方法解决多种角色的登录过滤

在报名系统中,登录的有两类用户,后台管理员和报名参与者,而他们都有些操作必须登录才能执行,传统的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>

总结

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

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

posted @ 2017-02-23 22:20  MarioLuo  阅读(1027)  评论(0编辑  收藏  举报