我们知道拦截器和过滤器都是在项目中起到拦截过滤请求的功能,所以可能在设置的时候会傻傻分不清。这里我们先来比较它们的区别。
- 过滤器Filter是JavaEE标准,在Servlet的规范中定义的,是Servlet容器支持的,是属于Servlet容器的,依赖Servlet容器;拦截器Interceptor是Spring的组件之一,是属于Spring框架的,依赖于Spring框架,归Spring管理,配置在Spring的文件中,因此能使用Spring里的任何资源和对象,例如Service对象、数据源、事务管理等,所以可以通过Spring的IOC注入方式注入即可,而Filter不可以。(若用配置文件方式配置,Filter配置在web.xml中,Interceptor配置在Spring MVC的配置文件中。多个过滤器的执行顺序跟在web.xml文件中定义的先后关系有关。多个拦截器它们之间的执行顺序跟在SpringMVC的配置文件中定义的先后顺序有关。)
- 过滤器Filter是基于函数回调实现;拦截器是基于java的反射机制实现,属于面向切面编程(AOP)的一种运用。
- 拦截器(依赖Spring框架所以)只能对Controller请求进行拦截而对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理,而过滤器则可以对几乎所有的请求起作用。
- 拦截器(是Spring组件之一)所以可以访问action上下文、值栈里的对象,而过滤器不能访问。
- 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化是被调用一次。
拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑
通过上面,我们知道了拦截器和过滤器的区别,下面我们来看看它们是怎么设置的。
过滤器
过滤器的设置得通过实现Filter接口,并且重写init(初始化过滤器)、doFilter(过滤请求)、destroy(销毁过滤器)
public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest request = (HttpServletRequest)arg0;
HttpServletResponse response = (HttpServletResponse)arg1;
HttpSession session = request.getSession();
if(session.getAttribute("_CURRENT_USER")==null && request.getRequestURI().indexOf("/home.action") == -1
&& request.getRequestURI().indexOf("/login.action") == -1 // -1表示不存在该url
){
// 没有登录
response.sendRedirect(request.getContextPath()+"/home.action");
}else{
// 已经登录,继续请求下一级资源(继续访问)
arg2.doFilter(arg0, arg1);
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
对于过滤器,我们需要在web.xml配置这个类。
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>cn.itcast.util.LoginFilter</filter-class>//这个class对应的是上面过滤器的位置
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<!-- 所有的管理页面需要登录后才能访问 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
拦截器
拦截器的设置需要实现HandlerInterceptor接口,并且重写preHandle(在调用controller之前)、postHandle(在Controller调用之后, DispatcherServlet返回渲染视图之前被调用)、afterCompletion(在视图渲染完毕后调用)
@Component
public class MyItercepter implements HandlerInterceptor {
/**
* 在调用 Controller 之前调用
* @param request
* @param response
* @param obj
* @return true 表示继续流程(调用下一个拦截器或处理器) false 表示中断流程, 不在调用其它拦截器或处理器, 需要通过 response 来响应。
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
// 在拦截点执行前拦截,如果返回true则不执行拦截点后的操作(拦截成功)
// 返回false则不执行拦截
HttpSession session = request.getSession();
//String uri = request.getRequestURI(); // 获取登录的uri,这个是不进行拦截的
//if(session.getAttribute("LOGIN_USER")!=null || uri.indexOf("system/login")!=-1) {// 说明登录成功 或者 执行登录功能
if(session.getAttribute("LOGIN_USER")!=null) {
// 登录成功不拦截
return true;
}else {
// 拦截后进入登录页面
response.sendRedirect(request.getContextPath()+"/system/login");
return false;
}
}
/**
* 在Controller调用之后, DispatcherServlet返回渲染视图之前被调用, 可操作ModelAndView对象对试图进行渲染操作。
* 注意: ModelAndView对象有可能为null
* @param request
* @param response
* @param obj
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object obj, ModelAndView modelAndView) throws Exception {
// 在处理过程中,执行拦截
}
/**
* 在视图渲染完毕后调用
* @param request
* @param response
* @param obj
* @param e
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object obj, Exception e) throws Exception {
// 执行完毕,返回前拦截
}
}
配置拦截器的时候也需要在 spring-mvc.xml中配置这个类
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 拦截所有mvc控制器 -->
<mvc:mapping path="/**"/>
<!-- mvc:exclude-mapping是另外一种拦截,它可以在你后来的测试中对某个页面进行不拦截,这样就不用在
MyItercepter的preHandler方法里面获取不拦截的请求uri地址了(优选) -->
<mvc:exclude-mapping path="/system/login" />
<bean class="com.lingshi.bookstore.interceptor.MyItercepter"></bean>
</mvc:interceptor>
</mvc:interceptors>