为什么要用过滤器
在我们项目开发的过程中,经常会遇到需要重复写一些代码的时候,例如:编码的设置、登录权限的判断等等。为了减少一些工作量,同时也为了让代码的结构更好,我们可以用过滤器来实现一些重复的代码。
多个Filter的执行顺序
按照类名的字典序来执行
用过滤器实现统一设置编码和登录权限的判断
统一设置编码:
// 一定要加注解,urlPatterns = "/*"表示对所有路径的访问都要经过该过滤器
@WebFilter(filterName = "encoding", urlPatterns = "/*")
// 注意这里是实现implements,而不是继承。Filter一定要选择javax.servlet.Filter
// 实现接口之后,重写三个方法(主要是doFilter方法的实现,另外两个可以仅重写不做任何操作,这里只是打印了一下方法名)
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("EncodingFilter.init");
}
// 我们需要做的一些拦截操作都在doFilter方法的重写中实现,做完需要的操作后,
// 执行chain.doFilter(request, response),如果有下一个过滤器,就执行下一
// 个过滤器,如果没有就访问这次请求要访问的后台资源
// doFilter里的ServletRequest和ServletResponse分别是HttpServletRequest和HttpServletResponse的父类
// 所以这里相当于ServletRequest request = new HttpServletRequest();
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("EncodingFilter.doFilter");
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String method = httpServletRequest.getMethod();
// 如果是post请求,解决post请求乱码问题
if (method.equalsIgnoreCase("post")) {
httpServletRequest.setCharacterEncoding("UTF-8");
}
// 如果是post,解决乱码问题之后,继续往后执行
chain.doFilter(request, response);
}
@Override
public void destroy() {
System.out.println("EncodingFilter.destroy");
}
}
登录权限的判断:
@WebFilter(filterName = "login", urlPatterns = "/*")
public class LoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("LoginFilter.init");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("LoginFilter.doFilter");
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
String servletPath = httpServletRequest.getServletPath();
System.out.println(servletPath);
// /user?method=login
String method = httpServletRequest.getParameter("method");
// 这些操作就是要去完成登录,不需要去验证后面是不是登录的流程
if (servletPath.equals("/login.jsp")
|| servletPath.equals("/user") && (method.equals("login"))
|| servletPath.equals("/fail.html")) {
// 继续执行后面的Filter或者放行(即让浏览器进行这次访问)
chain.doFilter(request, response);
return;
}
HttpSession session = httpServletRequest.getSession();
User user = (User) session.getAttribute("user");
if (user == null) {
// 没有登录的凭证
httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + "/login.jsp");
return;
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
System.out.println("LoginFilter.destroy");
}
}
登录权限判断的实现中的注意点
在LoginFilter中,我们需要“放行”一些本来就是去完成登录的操作,这些操作我们不需要去验证后面是不是登录的流程。如果不执行这些“放行”,那么浏览器会出现重定向次数过多的错误。因为没有登录信息,那么我们在LoginFilter里重定向到login.jsp页面让他去登录,重定向相当于让浏览器请求到我们重定向的地址,但是该请求又会被拦截,会再次重定向到login.jsp页面……,这样一直执行下去,就会出现重定向次数过多的错误,所以我们需要在判断是否有登录信息之前,获取这次请求的路径,判断该请求是否是要去完成登录操作,如果是的话,我们就执行chain.doFilter(request, response),继续执行Filter链之后的内容,然后return即可,就不需要对这次访问进行权限判断。