在報名系統中,登入的有兩類使用者,背景管理者和報名參與者,而他們都有些操作必須登入才能執行,傳統的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>
總結
對于某一類問題,具有相同的解決步驟,但是每一步具體的實作可能不一緻,可能這個時候就可以使用模版方法。
那麼這個問題能否用政策模式解決了????不能