大家好,又见面了,我是你们的朋友全栈君。
Interceptors are used to implement cross-cutting concerns, such as logging, auditing, and security, from the business logic. In Java EE 5, Interceptors were allowed only on EJBs. In Java EE 6, Interceptors became a new specification of its own, abstracted at a higher level so that it can be more generically applied to a broader set of specifications in the platform. They intercept invocations and life-cycle events on an associated target class. Basically, an interceptor is a class whose methods are invoked when business methods on a target class are invoked, life-cycle events such as methods that create/destroy the bean occur, or an EJB timeout method occurs. The CDI specification defines a type-safe mechanism for associating interceptors to beans using interceptor bindings.
Tables | 过滤器(Filter) | 监听器(Listener) | 拦截器(Interceptor) |
---|---|---|---|
关注的点 | wed请求 | 系统级别参数、对象 | Action(部分web请求) |
如何实现的 | 函数回调 | 事件 | Java反射机制(动态代理) |
应用场景 | 设置字符编码 | 统计网站在线人数 | 拦截未登录用户 |
URL级别的权限访问控制 | 清除过期session | 审计日志 | |
过滤敏感词汇 | |||
压缩响应信息 | |||
是否依赖servlet容器 | 依赖 | 不依赖 | |
Serverlet提供的支持 | Filter接口 | ServletContextListener抽象接口 | Action(部分web请求) |
HttpSessionListener抽象接口 | |||
Spring提供的支持 | HandlerinterceptorAdapter类 | ||
HandlerInterceptor接口 | |||
级别 | 系统级 | 系统级 | 非系统级 |
注意:拦截器的对象只能是实现了接口的类,而不能拦截URL这种链接。
java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。在AOP中,拦截器用于在某个方法或者字段被访问之前进行拦截,然后再之前或者之后加入某些操作。
大部分时候,拦截器方法都是通过代理的方式来调用的。
过滤器可以简单的理解为“取你所想取”,过滤器关注的是web请求;拦截器可以简单的理解为“拒你所想拒”,拦截器关注的是方法调用,比如拦截敏感词汇。 1.拦截器是基于java反射机制来实现的,而过滤器是基于函数回调来实现的。(有人说,拦截器是基于动态代理来实现的) 2.拦截器不依赖servlet容器,过滤器依赖于servlet容器。 3.拦截器只对Action起作用,过滤器可以对所有请求起作用。 4.拦截器可以访问Action上下文和值栈中的对象,过滤器不能。 5.在Action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时调用一次。
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class MyInterceptor implements HandlerInterceptor {
/**
* 该方法是在执行执行servlet的 service方法之前执行的
* 即在进入controller之前调用
* @return 如果返回true表示继续执行下一个拦截器的PreHandle方法;如果没有拦截器了,则执行controller
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
String url = request.getRequestURI();
System.out.println("进入Controller之前");
if(url.indexOf("login") >= 0){
return true;
}
String username = request.getParameter("username");
if(username == null){
return false;
}
return true;
}
/**
*在执行完controller之后,返回视图之前执行,我们可以对controller返回的结果做处理
* 执行顺序:先执行最后一个拦截器的postHandle方法,一次向前
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception{
System.out.println("解析视图之前.....");
}
/**
* 整个请求结束之后,即返回视图之后执行
*该方法需要同一拦截器的preHandle返回true时执行,
* 如果该拦截器preHandle返回false,则该拦截器的afterCompletion不执行
* 执行顺序:先执行最后一个返回true的拦截器的afterCompletion,在依次向前
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) throws Exception{
System.out.println("视图解析完成...");
}
}
Springboot环境中配置拦截器:
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private MyInterceptor interceptor;
public void addInterceptors(InterceptorRegistry registry) {
//addPathPatterns指定拦截器要拦截的路径
//excludePathPatterns指定拦截器不拦截的路径
registry.addInterceptor(interceptor).addPathPatterns("/**").excludePathPatterns("/logout");
}
}
Spring MVC环境中配置拦截器:
<mvc:interceptors>
<!-- 自定义拦截器 -->
<mvc:interceptor>
<!-- 进行拦截:/**表示拦截所有controller -->
<mvc:mapping path="/**" />
<!-- 不进行拦截 -->
<mvc:exclude-mapping path="/logout"/>
<bean class="com.example.demp.Interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
上面两种选一种即可 编写Controller测试:
@RestController
public class LoginController {
@RequestMapping("/login")
public String intercept(){
System.out.println("Controller执行中....");
return "Hello Interceptor!";
}
@RequestMapping("/logout")
public String logout(){
System.out.println("注销中....");
return "logouting.....!";
}
}
先访问login,测试结果如下:
进入Controller之前
Controller执行中....
解析视图之前.....
视图解析完成...
再访问logout:
注销中....
参考资料:https://www.jianshu.com/p/d25349f0ab02
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/134459.html原文链接:https://javaforall.cn