参考:
过滤器和拦截器的区别_至今没搞明白的博客-CSDN博客_过滤器和拦截器的区别
拦截器与过滤器的区别_℡tang的博客-CSDN博客_拦截器和过滤器的区别
Filter 过滤器,Servlet规范中三个技术 Servlet Listener Filter(顺序为L F S)
Filter是sun公司中servlet2.3后增加的一个新功能,在javaEE中定义了一个接口 javax.servlet.Filter来描述过滤器
通过Filter可以拦截访问web资源的请求与响应操作,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
在java web中,针对传入的request,或response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者 struts的action前统一设置字符集,或者去除掉一些非法字符。
相当于:一大堆请求中,只要选择符合要求的请求留下。定义这个要求的工具就是过滤器
(一堆字母中,取一个A)
Filter是javax.servlet包下的一个接口主要有以下三个方法
destory()
doFilter(ServletRequest request,ServletResponse response,FilterCjain chain)
init(FilterConfig filterConfig)
多个Filter对同一个资源进行了拦截,那么当我们在开始的Filter中执行chain.doFilter(request,response)时,是访问下一个Filter,直到最后一个Filter执行时,它后面没有了Filter,才会访问web资源
那么怎么保证顺序的?
执行顺序取决于在web.xml文件中配置的先后顺序
Filter生命周期
过滤器是JavaEE标准,采用函数回调的方式进行。是在请求进入容器之后,还未进入Servlet之前进行预处理,并且在请求结束返回给前端这之间进行后期处理。
通过 @WebFilter 注解,将类声明为 Bean 过滤器类,在启动类添加注解 @ServletComponentScan ,让 Spring 可以扫描到。
实现javax.servlet.Filter接口,重写三个关键方法
package com.ung.myflowable.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author: wenyi
* @create: 2022/10/19
* @Description: @WebFilter 属性中没有配置顺序的,执行顺序和 Filter 类名称字符排序有关 所以这个需要注意
*/
@WebFilter(
filterName = "filter1",//自定义过滤器的名称
urlPatterns = "/filter1/*"//自定义需要拦截的URL,可以使用正则匹配,若没指定该参数值,则默认拦截所有请求
)
public class MyFilter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String filter1 = filterConfig.getInitParameter("filter1");
System.out.println("==========================filter1 init" + filter1);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//业务处理 获取ip地址
HttpServletRequest request = (HttpServletRequest) servletRequest;
String remoteAddr = request.getRemoteAddr();
System.out.println("MyFilter1 访问的ip:" + remoteAddr);
//放行
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
package com.ung.myflowable;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
/**
* @author: wenyi
* @create: 2022/10/18
* @Description:
*/
@SpringBootApplication
@ServletComponentScan//启动类添加注解 @ServletComponentScan
public class MyFlowableApplication {
public static void main(String[] args) {
SpringApplication.run(MyFlowableApplication.class, args);
}
}
FilterRegistrationBean对象配置Filter,注解声明Bean,交由 Spring 容器管理
FilterRegistrationBean.setOrder() 决定 Filter 执行顺序。 数字小的先执行
过滤器1 MyFilter1
package com.ung.myflowable.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author: wenyi
* @create: 2022/10/19
* @Description: @WebFilter 属性中没有配置顺序的,执行顺序和 Filter 类名称字符排序有关 所以这个需要注意
*/
//@WebFilter(
// filterName = "filter1",//自定义过滤器的名称
// urlPatterns = "/filter1/*"//自定义需要拦截的URL,可以使用正则匹配,若没指定该参数值,则默认拦截所有请求
//)
public class MyFilter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String filter1 = filterConfig.getInitParameter("filter1");
System.out.println("==========================filter1 init" + filter1);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//业务处理 获取ip地址
HttpServletRequest request = (HttpServletRequest) servletRequest;
String remoteAddr = request.getRemoteAddr();
System.out.println("MyFilter1 访问的ip:" + remoteAddr);
//放行
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
过滤器2 MyFilter2
package com.ung.myflowable.filter;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author: wenyi
* @create: 2022/10/19
* @Description:
*/
public class MyFilter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String filter2 = filterConfig.getInitParameter("filter2");
System.out.println("==========================filter2 init" + filter2);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//业务处理 获取ip地址
HttpServletRequest request = (HttpServletRequest) servletRequest;
String remoteAddr = request.getRemoteAddr();
System.out.println("MyFilter2 访问的ip:" + remoteAddr);
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
配置类
package com.ung.myflowable.config;
import com.ung.myflowable.filter.MyFilter1;
import com.ung.myflowable.filter.MyFilter2;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author: wenyi
* @create: 2022/10/19
* @Description:
*/
@Configuration
public class MyFilterConfig {
/**
* 注册 过滤器 Filter
*/
@Bean
public FilterRegistrationBean<Filter> myFilter1() {
//匹配拦截 URL
String urlPatterns = "/myFilter1/*,/system/*";
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<Filter>();
registration.setDispatcherTypes(DispatcherType.REQUEST);
registration.setFilter(new MyFilter1());
registration.addUrlPatterns(StringUtils.split(urlPatterns, ","));
//设置名称
registration.setName("filter1");
//设置过滤器链执行顺序
registration.setOrder(1);
//启动标识
registration.setEnabled(true);
//添加初始化参数
registration.addInitParameter("filter1", "filter1filter1filter1filter1");
return registration;
}
/**
* 注册 过滤器 Filter
*/
@Bean
public FilterRegistrationBean<Filter> myFilter2() {
//匹配拦截 URL
String urlPatterns = "/myFilter2/*,/system/*";
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<Filter>();
registration.setDispatcherTypes(DispatcherType.REQUEST);
registration.setFilter(new MyFilter2());
registration.addUrlPatterns(StringUtils.split(urlPatterns, ","));
//设置名称
registration.setName("filter2");
//设置过滤器链执行顺序
registration.setOrder(3);
//启动标识
registration.setEnabled(true);
//添加初始化参数
registration.addInitParameter("filter2", "filter2filter2filter2filter2filter2");
return registration;
}
}
Interceptor 拦截器是spring容器的,是spring支持的java里的拦截器是动态拦截Action调用的对象,是面向切面编程(AOP,Aspect Oriented Program)的。
就是在你的Service或者一个方法前调用一个方法,或者在方法后调用一个方法。比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。
相当于:一个流程在进行的时候,干预它的进展,甚至可以终止结束,就是拦截器的工作。
(一堆字母中,进行干预,验证,做些其他事情)
1.实现接口HandlerInterceptor 实现拦截器
2.在WebMvc配置类中配置拦截器,并设置拦截规则
第一步很好做:
preHandle: 预先处理,在目标的controller方法执行之前,进行处理
postHandle: 在目标的controller方法执行之后,到达指定页面之前进行处理
afterCompletion: 在页面渲染之后进行处理
package com.ung.myflowable.interceptor;
import com.ung.myflowable.annotation.AbolishInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
/**
* @author: wenyi
* @create: 2022/10/19
* @Description:
*/
@Slf4j
public class MyInterceptor implements HandlerInterceptor {
/**
* 当url已经匹配到controller层中某个方法时,在方法执行前执行
* 它会决定是否放行,返回true,放行,返回false,不会执行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
String methodName = method.getName();
log.debug("方法名:{}", methodName);
// 通过方法,可以获取该方法上的自定义注解,然后通过注解来判断该方法是否要被拦截
// @AbolishInterceptor 是自定义的注解
AbolishInterceptor annotation = method.getAnnotation(AbolishInterceptor.class);
log.info("annotation===============,{}", annotation);
Parameter[] parameters = method.getParameters();
if (parameters != null) {
System.out.println("传入的参数name:" + parameters[0]);
}
if (annotation != null) {
return true;
}
// String token = request.getParameter("token");
// if (token == null || "".equals(token)) {
// log.info("未登录");
// return false;
// }
// 返回true才会继续执行,返回false则取消当前请求
return true;
}
/**
* url 匹配到Controller 中的某个方法,且执行完了该方法,
* 但是在 DispatcherServlet 视图渲染之前执行。在这个方法中有个 ModelAndView 参数,可以在此做一些修改动作。
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
/**
* 在整个请求处理完成后(包括视图渲染)执行,
* 做一些资源的清理工作,这个方法只有在 preHandle(……) 被成功执行后并且返回true才会被执行
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
springboot2.0后 推荐使用两种方式配置WebMvc
区别:
首先从SpringBoot自动装配来讲,SpringBoot对WebMvc做了自动配置
可以找到 自动配置类 WebMvcAutoConfiguration
里面蓝色框表示: WebMvcConfigurer 类存在bean容器,WebMvc自动配置生效
红色框表示:WebMvcConfigurationSupport 类存在bean容器, 自动配置就不生效
WebMvcConfigurer 配置类是spring内部的配置方式,采用JavaBean的方式代替 xml的方式,可以进行自定义Handler,Interceptor,ViewResolver,MessageConverter
常用方法
/* 拦截器配置 */
void addInterceptors(InterceptorRegistry var1);
/* 视图跳转控制器 */
void addViewControllers(ViewControllerRegistry registry);
/**
*静态资源处理
**/
void addResourceHandlers(ResourceHandlerRegistry registry);
/* 默认静态资源处理器 */
void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer);
/**
* 这里配置视图解析器
**/
void configureViewResolvers(ViewResolverRegistry registry);
/* 配置内容裁决的一些选项*/
void configureContentNegotiation(ContentNegotiationConfigurer configurer);
/** 解决跨域问题 **/
public void addCorsMappings(CorsRegistry registry) ;
WebMvcConfigurationSupport 是mvc的基本实现并包含了WebMvcConfigurer接口中的方法
WebMvcAutoConfiguration 是mvc的自动装配类并部分包含了WebMvcConfigurer接口中的方法
如果项目没有使用 WebMvcConfigurationSupport 就会使用自动配置类,进行默认配置,比如对静态资源的访问
如果自动配置类不生效,会怎样?
WebMvcProperties 和 ResourceProperties 失效
两个配置类中的属性都在 WebMvcAutoConfiguration 中使用。当WebMvc自动配置失效(WebMvcAutoConfiguration自动化配置)时,会导致无法视图解析器无法解析并返回到对应的视图。
虽然 Bean容器里面有 WebMvcConfigurationSupport 但是 这个类没有 WebMvcProperties 和 ResourceProperties属性;
解决:可以实现WebMvcConfigurer并重写相关方法来达到类似的功能
@EnableWebMvc 注解
该注解会关闭默认配置
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}
DelegatingWebMvcConfiguration这个类是继承了WebMvcConfigurationSupport的,这就是它为什么可以关闭默认配置的原因了。
希望关闭默认配置,自己完全重新实现一个
@EnableWebMvc
@Configuration
public class WebConfig implements WebMvcConfigurer {
你希望重写部分配置
//@EnableWebMvc
@Configuration
public class WebConfig implements WebMvcConfigurer {
或
@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcAutoConfiguration {
配置类
package com.ung.myflowable.config;
import com.ung.myflowable.interceptor.MyInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author: wenyi
* @create: 2022/10/19
* @Description: 拦截器配置类
*/
@Configuration
public class MyInterceptor2Config implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
System.out.println("添加到容器中啦+++++++++++++++++++++");
registry.addInterceptor(new MyInterceptor())//添加拦截器
.addPathPatterns("/**")//拦截路径
.excludePathPatterns("/login", "/static/*");//忽略的拦截路径
}
}
①:拦截器是基于java的反射机制(动态代理)的,而过滤器是基于函数的回调。
②:拦截器不依赖于servlet容器,而过滤器依赖于servlet容器。
③:拦截器只对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
④:拦截器可以访问action上下文、值、栈里面的对象,而过滤器不可以。
⑤:在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
⑥:拦截器可以获取IOC容器中的各个bean,而过滤器不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
过滤器是请求进入servlet之前进行处理,请求结束返回也是,在servlet处理后,返回给前端前执行,
过滤器包裹servlet,servlet包裹拦截器
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。
1、日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
2、权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;
3、性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);
4、通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。
5、OpenSessionInView:如hibernate,在进入处理器打开Session,在完成后关闭Session。