过滤器与拦截器
过滤器(Filter)
过滤器是Java EE中的组件。
过滤器是执行在Servlet之前的组件。
过滤器可以对请求进行过滤,如果不满足自行指定的条件,可以拦截下来,不予放行,请求就不会被Servlet处理。
过滤器也需要在web.xml中配置注册,通常,映射的路径范围较大,因为它通常用于处理多个甚至所有Servlet需要执行的任务。
同一个应用中可以存在多个过滤器,形成“过滤器链”,当某个请求被服务器处理时,会依次执行各个过滤器,只有全部放行,才会被Servlet处理。
1.过滤器的优点
a.可以在不修改源代码的基础上,为应用添加新的功能。
b.可以将多个组件相同的功能集中写在过滤器里面,方便代码的维护。
2.如何写一个过滤器
step1.写一个java类,实现Filter接口。
step2.在doFilter方法里面,实现拦截处理逻辑。
step3.配置过滤器。(web.xml)
<filter>
<filter-name>commentFilter2</filter-name>
<filter-class>web.CommentFilter2</filter-class>
<init-param>
<param-name>size</param-name>
<param-value>5</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>commentFilter2</filter-name>
<url-pattern>/comment</url-pattern>
</filter-mapping>
<filter>
<filter-name>commentFilter</filter-name>
<filter-class>web.CommentFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>commentFilter</filter-name>
<url-pattern>/comment</url-pattern>
</filter-mapping>
容器启动后会检查配置文件,把里面所以有的过滤器先实例化,将实例化后的对象放到FilterChain对象中(过滤器链),顺序按照优先级存放(配置文件的先后顺序),
package filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(filterName = "CommentFilter",urlPatterns = "/comment")
public class CommentFilter implements Filter {
/**
* 容器启动之后,会立即创建过滤器实例。
* 注:
* 只会创建一个实例!
*/
public CommentFilter() {
System.out.println("------------CommentFilter()-------------------");
}
/**
* 容器在创建好过滤器实例之后,会立即
* 调用该实例的init方法。
* 注:
* 该方法只会调用一次!
*/
public void init(FilterConfig config) throws ServletException {
System.out.println("-----------CommentFilter----init()-----------------------");
}
/**
* 容器在调用完过滤器的init方法之后,
* 会调用doFilter方法来处理请求。
* 注:(了解)
* ServletRequest是HttpServletRequest
* 的父接口,ServletResponse是
* HttpServletResponse的父接口。
*
* FilterChain(过滤器链):
* 如果调用了该对象的doFilter方法,
* 表示继续向后调用;否则,中断请求,返回
* 处理结果。
*
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
System.out.println("------------commentFileter's doFilter()---------------");
chain.doFilter(request, response);
}
public void destroy() {
}
}
控制台输出:
过滤器的配置与Servlet非常相似:
<filter>
<filter-name></filter-name>
<filter-class></filter-class>
</filter>
<filter-mapping>
<filter-name></filter-name>
<url-pattern></url-pattern>
</filter-mapping>
拦截器(Interceptor)
1基本概念
拦截器是SpringMVC中的组件,执行时优先于控制器(其实,每个拦截器都会执行3次,1次在控制器之前,2次在控制器之后,通常关注的是在控制器之前执行的那一次)。
2基本使用
step1:写拦截器类
自定义拦截器需要实现HandlerInterceptor
接口,该接口中共3个抽象方法,其中,preHandle()
方法是在控制器之前执行的,可以起到拦截效果,该方法的返回值表示是否拦截,为true
时放行,为false
时拦截。
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
// 测试输出
System.out.println("LoginInterceptor.preHandle()");
// 拦截规则:
// 如果未登录,重定向到登录,并拦截
// 如果已登录,直接放行
HttpSession session = httpServletRequest.getSession();
if (session.getAttribute("username") == null) {
httpServletResponse.sendRedirect("../user/login.do");
return false;
}
return false;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
step2:在spring的配置文件中配置拦截器
在spring的配置文件中配置拦截器
<!-- 拦截器链 -->
<mvc:interceptors>
<!-- 第1个拦截器 -->
<mvc:interceptor>
<!-- 1. 黑名单 -->
<mvc:mapping path="/user/*"/>
<!-- 2. 白名单 -->
<mvc:exclude-mapping path="/user/reg.do"/>
<mvc:exclude-mapping path="/user/login.do"/>
<mvc:exclude-mapping path="/user/handle_reg.do"/>
<mvc:exclude-mapping path="/user/handle_login.do"/>
<!-- 3. 拦截器类 -->
<bean class="cn.tedu.spring.LoginInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
在配置时,可以使用星号*
作为通配符,但是,它只能匹配1级路径,例如:/user/*
可以通配/user/reg.do
、/user/login.do
等,却无法匹配/user/a/list.do
!如果需要表示多级路径中的通配,则需要使用2个星号**
!
过滤器与拦截器的区别
使用环境不同:过滤器是Java EE中的组件,任何Java Web项目都可以使用;拦截器是SpringMVC中的组件,仅当项目中使用了SpringMVC框架后才可以使用!
执行时间节点不同:过滤器是执行在Servlet之前的,拦截器是执行在Controller之前的(暂不考虑拦截器在控制器之后的2次执行)!
使用复杂程度不同:过滤器只能配置1个路径(<url-pattern>
)表示过滤范围,拦截器可以配置若干个<mvc:mapping>
表示拦截范围,同时还可以使用若干个<mvc:exclude-mapping>
表示例外(白名单),所以配置时更加灵活!
当然,也有一些相同之处,例如:都在控制器之前执行,都可以起到“拦截效果”,都可以形成“链”。