一.基本定义:
过滤器实际上就是对web资源进行拦截,做一些处理后再交给下一个过滤器或servlet处理
通常都是用来拦截request进行处理的,也可以对返回的response进行拦截处理
二.新建一个Filter:
可以直接new一个Filter类.输入过滤器名称,跟创建Servlet一样,这里我们直接使用**@WebFilter**注解,不再去web,xml中进行配置了。创建完成后默认代码,可以看到,CharsetFilter实现了Filter接口,实现了3个方法。3个方法的作用已经在注释中写清楚了。
package com.fym.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(filterName = "CharSetFilter")
public class CharSetFilter implements Filter {
// 销毁时调用
public void destroy() {
}
//过滤方法(真正做事的方法) 主要是对request和response进行一些处理,然后交给下一个过滤器或Servlet处理
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//doFilter()之前是,对请求的过滤
chain.doFilter(req, resp);//放行操作,交给下一个过滤器或者是servlet处理
//doFilter()之后是,对响应的过滤
}
//初始化方法 接收一个FilterConfig类型的参数 该参数是对Filter的一些配置
public void init(FilterConfig config) throws ServletException {
}
}
三.Filter的相关配置(@webFilter):
可配置的属性和常用的配置项:
①urlPatterns
配置要拦截的资源
以指定资源匹配。例如"/index.jsp"
以目录匹配。例如"/servlet/"
以后缀名匹配,例如".jsp"
通配符,拦截所有web资源。"/*"
②initParams
配置初始化参数,跟Servlet配置一样
③.dispatcherTypes (枚举类型)
配置拦截的类型,可配置多个。默认为DispatcherType.REQUEST**
例如
下面是一个最简单的字符编码的过滤器
package com.fym.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;
@WebFilter(filterName = "CharSetFilter", urlPatterns = "/*",//通配符(*)表示对所有的web资源进行拦截
initParams = {
@WebInitParam(name = "charset", value = "utf-8")//这里可以放一些初始化的参数,例如设置编码
})
public class CharSetFilter implements Filter {
private String filterName;
private String charset;
// 销毁时调用
public void destroy() {
System.out.println(filterName + "销毁");
}
//过滤方法(真正做事的方法) 主要是对request和response进行一些处理,然后交给下一个过滤器或Servlet处理
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println(filterName + "doFilter()");
//doFilter()之前是,对请求的过滤
req.setCharacterEncoding(charset);
chain.doFilter(req, resp);//放行操作,交给下一个过滤器或者是servlet处理
//doFilter()之后是,对响应的过滤
resp.setCharacterEncoding(charset);
}
//初始化方法 接收一个FilterConfig类型的参数 该参数是对Filter的一些配置
public void init(FilterConfig config) throws ServletException {
filterName = config.getFilterName();
charset = config.getInitParameter("charset");
System.out.println("过滤器名称:" + filterName);
System.out.println("字符集编码:" + charset);
}
}
启动服务器是,执行init()方法
需要注意的是
过滤器是在服务器启动时就会创建的,只会创建一个实例,常驻内存,也就是说服务器一启动就会执行Filter的init(FilterConfig config)方法.
当Filter被移除或服务器正常关闭时,会执行destroy方法
四.多个Filter的执行顺序:
在我们的请求到达Servle之间是可以经过多个Filter的,一般来说,建议Filter之间不要有关联,各自处理各自的逻辑即可。这样,我们也无需关心执行顺序问题。
如果一定要确保执行顺序,就要对配置进行修改了,执行顺序如下
①在web.xml中,filter执行顺序跟的顺序有关,先声明的先执行
②使用注解配置的话,filter的执行顺序跟名称的字母顺序有关,例如AFilter会比BFilter先执行
③如果既有在web.xml中声明的Filter,也有通过注解配置的Filter,那么会优先执行web.xml中配置的Filter
五.设计一个登录校验的过滤器:
①注册过滤器,并设置不需要过滤的资源
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<filter>
<filter-name>CheckLoginFilter</filter-name>
<filter-class>com.fym.filter.CheckLoginFilter</filter-class>
<!-- 设置不需要过滤的资源 -->
<init-param>
<param-name>UnCheckURI</param-name>
<param-value>/login,/login.jsp</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CheckLoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
②.servlet,做一个简单的页面跳转,并把登录信息保存到session中
package com.fym.filter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/login")
public class CheckLoginServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//获取请求参数
String username = req.getParameter("username");
String password = req.getParameter("password");
//这里是直接写死的,实际应用中应该是与数据库中的数据作比较
if("admin".equals(username)&&"123".equals(password)){
//将用户信息添加到session中
req.getSession().setAttribute("USER_IN_SESSION", username);
}
//跳转到welcome.jsp页面中
req.getRequestDispatcher("/welcome.jsp").forward(req, resp);
}
}
③过滤器代码,判断是否登录
package com.fym.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class CheckLoginFilter implements Filter{
//定义一个list,用来存放那些不需要过滤的资源
private List<String> list ;
@Override
public void init(FilterConfig arg0) throws ServletException {
//得到初始化参数,并存放到list集合中
String unCheckURI = arg0.getInitParameter("UnCheckURI");
list = Arrays.asList(unCheckURI.split(","));
}
@Override
public void doFilter(ServletRequest requset, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//servletRequest里没有获取请求资源的方法(该方法存在于它的子类中,所以需要进行强转)
HttpServletRequest req = (HttpServletRequest) requset;
HttpServletResponse resp = (HttpServletResponse) response;
// 获取当前客户的发出请求的资源
String requestURI = req.getRequestURI();
//判断是否有和不需要过滤的资源相等的资源(取反,就是需要进行检查登录的资源)
if (!list.contains(requestURI)) {
// 登录检查过滤器(先获取session对象,再获取session中的数据)
Object obj = req.getSession().getAttribute("USER_IN_SESSION");
if (obj == null) {
resp.sendRedirect("/login.jsp");
return;
}
}
// 放行(这一步是是必须要做的,但是往往会忽略这个,需要牢记)
chain.doFilter(req, resp);
}
@Override
public void destroy() {
}
}
④.效果:访问/login.jsp和/login资源时,过滤器不做拦截,访问其他资源时,先判断是否登录,登录即可访问,没有登录,即跳转到登录页面.