过滤器Filter笔记
文章目录
PS:使用@Slf4j注解
此注解就是为了能够少写两行代码,不用每次都在类的最前边写上:
private static final Logger logger = LoggerFactory.getLogger(this.XXX.class);
我们只需要在类前面添加注解@Slf4j,即可使用log日志的功能了
首先必须要有该插件
并且加入该依赖
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
使用:
1.当你使用过滤器时必须得配置过滤什么
第一次使用filter时:
方法里面什么都没有,并且前端网页不显示了
这是因为被过滤器默认过滤掉了所有的接口
2.过滤器的方法
- init(): 此方法在只在过滤器创建的时候执行一次,用于初始化过滤器的属性
- doFilter(): 该方法会对请求进行拦截,用户需要在该方法中自定义对请求内容以及响应内容进行过滤的,调用该方法的入参 FilterChain对象的 doFilter 方法对请求放行执行后面的逻辑,若未调用 doFilter 方法则本次请求结束,并向客户端返回响应失败
- destroy(): 此方法用于销毁过滤器,过滤器被创建以后只要项目一直运行,过滤器就会一直存在,在项目停止时,会调用该方法销毁过滤器,也可以用于过滤器销毁前,完成某些资源的回收。
3.过滤器大致运行原理
4.过滤器常用的地方
-
- Authentication Filters,即用户访问权限过滤
-
- Logging and Auditing Filters, 日志过滤,可以记录特殊用户的特殊请求的记录等
-
- Image conversion Filters,图像转换过滤器
-
- Data compression Filters ,数据转换
-
- Encryption Filters ,安全加密
-
- Tokenizing Filters ,词法分析
-
- Filters that trigger resource access events ,资源访问事件触发过滤器
-
- XSL/T filters
-
- Mime-type chain Filter ,文件类型链过滤器
5.过滤器的过滤
成功过滤 /filter
问题: 但使用==servletRequest.getParameter==取出数据的时候int数据会变成字符串
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
log.info("请求地址:"+request.getRequestURI());
HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper((HttpServletResponse) servletResponse);
log.info("对请求进行过滤");
// 请求url中包含/filter,继续执行,否则直接放行
if (request.getRequestURI().contains("/filter")){
// 交给下一个过滤器或servlet处理
log.info("过滤了filter");
if ( servletRequest.getParameter("size") == "2"){
log.info("page size :{}",servletRequest.getParameter("size")+"拦截size为2的请求");
}else {
log.info("page size :{}",servletRequest.getParameter("size"));
filterChain.doFilter(servletRequest,servletResponse);
}
}else {
filterChain.doFilter(servletRequest,servletResponse);
log.info("对返回进行过滤");
}
}
使用 : filterChain.doFilter(servletRequest,servletResponse); 放行请求
request.getRequestURI() 获取请求的URL(即Controller中的url)
解决: int size=Integer.parseInt(request.getParameter(“size”));//强转成整型
6.过滤器重定向到其他方法
servletRequest.getRequestDispatcher("/selectall").forward(servletRequest,servletResponse);
7.完整过滤器代码(2024.3.5)
PS:若是用注解配置则需要在启动类加入@ServletComponentScan(“com.example.demofilter.filter”)
@Slf4j
@Component
@WebFilter(filterName = "MyFilter",
/**
* 通配符(*)表示对所有的web资源进行拦截
*/
urlPatterns = "/*"
)
public class LogFilter implements Filter {
/**
* 过滤器初始化
* explain:在容器中创建当前过滤器的时候自动调用
*
* @param filterConfig
**/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("==================初始化过滤器=============");
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
log.info("------------- LogFilter 开始 -------------");
log.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
log.info("远程地址: {}", request.getRemoteAddr());
// HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper((HttpServletResponse) servletResponse);
HttpServletResponse resp = (HttpServletResponse) servletResponse;
log.info("对请求进行过滤");
//记录当前时间
long startTime = System.currentTimeMillis();
// 请求url中包含/filter,继续执行,否则直接放行
if (request.getRequestURI().contains("/filter")){
// 交给下一个过滤器或servlet处理
log.info("过滤了filter");
int size=Integer.parseInt(request.getParameter("size"));//强转成整型
if ( size == 2){
log.info("page size :{}",servletRequest.getParameter("size")+"拦截size为2的请求");
//拦截后重定向到其他方法
// servletRequest.getRequestDispatcher("/selectall").forward(servletRequest,servletResponse);
log.info("------------- LogFilter 结束 耗时:{} ms -------------", System.currentTimeMillis() - startTime);
}else {
log.info("page size :{}",servletRequest.getParameter("size"));
filterChain.doFilter(servletRequest,servletResponse);
log.info("------------- LogFilter 结束 耗时:{} ms -------------", System.currentTimeMillis() - startTime);
}
}else {
filterChain.doFilter(servletRequest,servletResponse);
log.info("对返回进行过滤");
log.info("------------- LogFilter 结束 耗时:{} ms -------------", System.currentTimeMillis() - startTime);
}
}
@Override
public void destroy() {
log.info("===================销毁过滤器==============");
Filter.super.destroy();
}
}
配置类:
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean myFilterBean(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
//指明需要被注册的过滤器
filterRegistrationBean.setFilter(new LogFilter());
//添加过滤路径
filterRegistrationBean.addUrlPatterns("/filter");
return filterRegistrationBean;
}
}
配置过滤器,使用FilterRegistrationBean中的方法:
1.setFilter
将建好的过滤器类对象传进去
指明需要被注册的过滤器,即是哪个过滤器的Bean
2.setOrder
设置过滤器执行次序
数字越小越先执行
为保证一定最先执行,可以使用Integer.MIN_VALUE
3.addUrlPatterns
配置过滤器规则
4.setName
设置过滤器名称
5.setUrlPatterns
配置多个过滤规则,参数List
7.HttpServletResponse.sendRedirect方法和RequestDispatcher.forward方法
下面是HttpServletResponse.sendRedirect方法实现的请求重定向与RequestDispatcher.forward方法实现的请求转发的总结比较:
(1)RequestDispatcher.forward方法只能将请求转发给同一个WEB应用中的组件;而 HttpServletResponse.sendRedirect 方法不仅可以重定向到当前应用程序中的其他资源,还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。如果传递给HttpServletResponse.sendRedirect 方法的相对URL以“/”开头,它是相对于整个WEB站点的根目录 ;如果创建RequestDispatcher对象时指定的相对URL以“/”开头,它是相对于当前WEB应用程序的根目录 。
(2)调用HttpServletResponse.sendRedirect方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的URL地址变成重定向的目标URL;而调用RequestDispatcher.forward 方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变。
(3)HttpServletResponse.sendRedirect方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的访问请求,这个过程好比有个绰号叫“浏览器”的人写信找张三借钱,张三回信说没有钱,让“浏览器”去找李四借,并将李四现在的通信地址告诉给了“浏览器 ”。于是,“浏览器”又按张三提供通信地址给李四写信借钱,李四收到信后就把钱汇给了“浏览器”。可见,“浏览器”一共发出了两封信和收到了两次回复,“ 浏览器”也知道他借到的钱出自李四之手。RequestDispatcher.forward方法在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器程序内部发生了转发行为。这个过程好比绰号叫“浏览器”的人写信找张三借钱,张三没有钱,于是张三找李四借了一些钱,甚至还可以加上自己的一些钱,然后再将这些钱汇给了“浏览器”。可见,“浏览器”只发出了一封信和收到了一次回复,他只知道从张三那里借到了钱,并不知道有一部分钱出自李四之手。
(4)RequestDispatcher.forward方法的调用者与被调用者之间共享相同的request对象和response对象,它们属于同一个访问请求和响应过程 ;而HttpServletResponse.sendRedirect方法调用者与被调用者使用各自的request对象和response对象,它们属于两个独立的访问请求和响应过程。对于同一个WEB应用程序的内部资源之间的跳转,特别是跳转之前要对请求进行一些前期预处理,并要使用HttpServletRequest.setAttribute方法传递预处理结果,那就应该使用 RequestDispatcher.forward方法。不同WEB应用程序之间的重定向,特别是要重定向到另外一个WEB站点上的资源的情况,都应该使用HttpServletResponse.sendRedirect方法。
(5)无论是RequestDispatcher.forward方法,还是HttpServletResponse.sendRedirect方法,在调用它们之前,都不能有内容已经被实际输出到了客户端。如果缓冲区中已经有了一些内容,这些内容将被从缓冲区中清除。
(6) 代码的执行:
无论是 request.getRequestDispatcher(path).forward(request, response)还是response.sendRedirect,程序都会在执行完该句的情况下继续向下执行,因此在必要的时候应该使用return终止该方法.
对于 request.getRequestDispatcher(path).forward(request, response),在执行完该方法的时候再进行对request的操作已经没有任何意义,如果在该方法之后再进行request.setAttribute(),该值将不会被放进当前请求的request中.
response.setRedirect:该方法执行之后,接下来的方法也会被执行.但是使用该方法的时候,会发送一个全新的request,将不再使用原先的request,因此不论在该方法执行之前,还是在该方法执行之后,对request操作,都是无效的.
8、中文乱码问题