Filter与Servlet差不多,需要实现Filter接口,实现init,destroy,doFilter这三个方法。
一般常用的Filter的功能有,给字符串编码、权限的过滤。
例子, 权限过滤的使用:
web.xml文件声明一个filter:
<filter>
<filter-name>AuthorityFilter</filter-name>
<filter-class>news.filter.AuthorityFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AuthorityFilter</filter-name>
<url-pattern>/faces/success.jsp</url-pattern>
</filter-mapping>
Filter可以使用通配符用来过滤一个、多个url,或者过滤一个、多个的Servlet。
例子在JSF框架里面过滤success.jsp,防止非法用户绕过登录页面直接输入/ faces/success.jsp进入到成功页面。
编写Filter实现类:
public class AuthorityFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
String isLogin = (String) req.getSession().getAttribute("isLogin");
if(isLogin == null || !isLogin.equals("yes")){
res.sendRedirect(req.getContextPath()+"/faces/error.jsp");
}
try {
chain.doFilter(request, response);
}
catch(Throwable t) {
}
}
public void destroy() {
}
public void init(FilterConfig filterConfig) {
}
}
代码分析:从session里面取得isLogin,判断是否登录,否的话重定向到错误页面,成功的话chain.doFilter(request,response);允许通过。
另外,Filter是不需要过滤登录页面login.jsp的,因此,如果login.jsp和其它登录后的操作页面在统一目录的时候,使用通配符来过滤<url-pattern>/faces/*</url-pattern>的话行不通。我们可以在Filter里面使用HttpServletRequest的getServletPath()方法来判断:
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
//判断是否login.jsp,是就放过,否则判断用户登录与否
if(req.getServletPath().equals("/faces/login.jsp")){
chain.doFilter(request, response);
}
else{
String isLogin = (String) req.getSession().getAttribute("isLogin");
if(isLogin == null || !isLogin.equals("yes")){
res.sendRedirect(req.getContextPath()+"/faces/error.jsp");
}
chain.doFilter(request, response);
}
其实,我觉得最理想的做法是web.xml文件<filter-mapping>包含一个<url-pattern-excluded>来处理例外情况,而且将excludedPages放到配置文件可以灵活变动,硬编码没有这个好处。可惜JavaEE没有提供,不过我们可以自己写,达到这种效果。
方法如下:
编写Filter:
public class CheckLoginFilter implements Filter {
private String excludedPages; //存储web.xml里面配置的filter的init-param的init-value
private String[] pages; //excludedPages调用split方法后的String[]
public void init(FilterConfig arg0) throws ServletException {
excludedPages = arg0.getInitParameter("excludedPages"); //获取init-value
pages = excludedPages.split(","); //使用,号分割excluded pages
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
boolean isExcludedPage = false;
for(int i=0 ; i<pages.length ; i++){
//判断请求的页面是否excluded page
if(req.getServletPath().equals(pages[i])){
isExcludedPage = true;
break;
}
}
if(isExcludedPage){
chain.doFilter(request, response);
}
else{
String isLogin = (String) req.getSession().getAttribute("isLogin");
if(isLogin == null || !isLogin.equals("yes")){
res.setCharacterEncoding("utf-8");
PrintWriter out = res.getWriter();
out.println("你还没有登录");
out.close();
}
else{
chain.doFilter(request, response);
}
}
}
public void destroy() {
}
}
在web.xml添加filter配置:
<filter>
<filter-name>checkLoginFilter</filter-name>
<filter-class>myfilters.CheckLoginFilter</filter-class>
<init-param>
<param-name>excludedPages</param-name>
<!-- 这里配置excluded pages,每隔page之间用,号隔开 -->
<param-value>/index.jsp,/login.jsp</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>checkLoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>