设计模式的应用-模版方法解决多种角色的登录过滤
在报名系统中,登录的有两类用户,后台管理员和报名参与者,而他们都有些操作必须登录才能执行,传统的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>
总结
对于某一类问题,具有相同的解决步骤,但是每一步具体的实现可能不一致,可能这个时候就可以使用模版方法。
那么这个问题能否用策略模式解决了????不能