天天看點

設計模式的應用-模版方法解決多種角色的登入過濾

在報名系統中,登入的有兩類使用者,背景管理者和報名參與者,而他們都有些操作必須登入才能執行,傳統的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>
           

總結

對于某一類問題,具有相同的解決步驟,但是每一步具體的實作可能不一緻,可能這個時候就可以使用模版方法。

那麼這個問題能否用政策模式解決了????不能

繼續閱讀