本篇内容介绍了“过滤器Filter和拦截器HandlerIntercepter的区别及用法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
最近在代码中,看到有同事既在用拦截器又在用过滤器做登录校验,就觉得很晕,似乎二者都可以实现业务需求,但是到底采用哪种方式较好呢,二者又有什么区别?
依赖于servlet容器,在实现上基于函数回调,可以对几乎所有请求进行过滤,一个过滤器实例只能在容器初始化时调用,它是随你的web应用启动而启动的,只初始化一次,以后就可以拦截相关的请求,只有当你的web应用停止或重新部署的时候才能销毁。
使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等。
依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。
由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,而不用修改handler自身的实现。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。
①拦截器是基于java的反射机制的,而过滤器是基于函数回调。
②拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
④拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
⑤在action的生命周期中,拦截器可以多次被调用(这里是指拦截器里的三个方法是可以在一次action中的不同时期调用,细粒度控制),而过滤器只能一次请求过滤一次,不能在不同的生命周期里作用。
⑥拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
在javax.servlet.Filter接口中定义了3个方法:
void init(FilterConfig filterConfig) 用于完成过滤器的初始化
void destroy() 用于过滤器销毁前,完成某些资源的回收
void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) 实现过滤功能,该方法对每个请求增加额外的处理
public class FilterUtil implements Filter{
@SuppressWarnings("unused")
private FilterConfig filterConfig;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
System.out.println("过滤器Filter初始化");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
throw new ServletException("FilterUtil just supports HTTP requests");
}
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpRequest.setCharacterEncoding(this.filterConfig.getInitParameter("encoding"));
httpResponse.setCharacterEncoding(this.filterConfig.getInitParameter("encoding"));
chain.doFilter(httpRequest, httpResponse);
}
@Override
public void destroy() {
System.out.println("过滤器Filter销毁");
}
}
web.xml配置:
<filter>
<filter-name>encodingFilter</filter-name>
<!-- <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> -->
<filter-class>com.cn.util.FilterUtil</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
chain.doFilter(request, response)这个方法的调用作为分水岭。事实上调用Servlet的doService()方法是在chain.doFilter(request, response)这个方法中进行的。
preHandle()这个方法是在过滤器的chain.doFilter(request, response)方法的前一步执行。
postHandle()方法之后,在return ModelAndView之前进行,可以操控Controller的ModelAndView内容。
afterCompletion()方法是在过滤器返回给前端前一步执行,也就是在[chain.doFilter(request, response)][System.out.println("after...")]之间执行。
注意:重定向:会在当前页面代码执行完毕后,跳转到指定的页面执行其他代码。 转 发:在本页面代码执行到转发语句后,即跳转到指定的页面执行其他代码,执行完毕后返回接着执行转发语句后的代码。
/**
* 用户身份认证的拦截器
*/
public class LoginInterceptor implements HandlerInterceptor {
@Value("${TT_TOKEN_KEY}")
private String TT_TOKEN_KEY;
@Value("${SSO_URL}")
private String SSO_URL;
@Autowired
private UserLoginService loginservice;
//在进入目标方法之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//用户的身份认证在此验证
//1.取cookie中的token
//1.从cookie中获取用户的token
String token = CookieUtils.getCookieValue(request, TT_TOKEN_KEY);
//2.判断token是否存在,
if(StringUtils.isEmpty(token)){
//3.如果不存在,说明没登录 ---》重定向到登录的页面
//request.getRequestURL().toString():就是访问的URL localhost:8092/order/order-cart.html
response.sendRedirect(SSO_URL+"/page/login?redirect="+request.getRequestURL().toString());
return false;
}
//4.如果token存在,调用SSO的服务 查询用户的信息(看是否用户已经过期)
TAotaoresult result = loginservice.getUserByToken(token);
if(result.getStatus()!=200){
//5.用户已经过期 --》重定向到登录的页面
response.sendRedirect(SSO_URL+"/page/login?redirect="+request.getRequestURL().toString());
return false;
}
//6.用户没过期(说明登录了)--》放行
//设置用户信息到request中 ,目标方法的request就可以获取用户的信息
request.setAttribute("USER_INFO", result.getData());
return true;
}
//在进入目标方法之后,在返回modelandview之前执行
//共用变量的一些设置。
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
}
//返回modelandview之后,渲染到页面之前
//异常处理 ,清理工作
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
}
}
SpringMVC的机制是由同一个Servlet来分发请求给不同的Controller,其实这一步是在Servlet的service()方法中执行的。所以过滤器、拦截器、service()方法,dispatche'r()方法的执行顺序如下
拦截器更加适合做细粒度的Handler控制,尤其是一些公共处理代码,授权校验等,过滤器更加适合请求内容和视图内容的相关处理,比如multipart 表单,GZIP压缩等。 回头在看之前的疑惑,最佳的解决方案是使用拦截器做登录校验。
“过滤器Filter和拦截器HandlerIntercepter的区别及用法”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/woniuyi/blog/3106046