Filter
Filter简单介绍
web 服务器的三大组件 Servlet Filter Listener
Filter是用来执行过滤任务的一个对象,他的作用范围:
- 请求一个资源(动态资源Servlet,JSP,静态资源)
- 来自一个资源的响应
- 以上两个都可以
filter过滤请求和响应
- filter可以拦截请求,可以修改请求头,请求内容
- filter可以拦截来自服务端的响应。(response),可以修改响应头和响应内容。
- 放行请求
Filter的实现
- Filter是一个接口,所以需要实现这个接口
public HelloFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException{}
//执行过滤方法
@Override
public void doFilter(ServletRequest request,ServletResponse response,
FilterChain chain) throws IOException, ServletException{
String money = request.getParameter("money");
if(money != null){
//带钱了
chain.doFilter(request,response);//放行
//在chain.doFilter(request,response);之前拦截request,在chain.doFilter之后拦截response。
}else{
//没带钱
response.getWriter.write("no money,no way");
}
}
@Override
public void destroy(){}
}
- 在实现了Filter接口之后,我们需要对Filter进行初始化和配置,所以需要在web.xml中配置
<!--配置filter的映射信息-->
<filter>
<!-- filter 起的别名-->
<filter-name>HelloFilter</filter-name>
<!-- filter 起的全类名-->
<filter-name>com.atguigu.filter.HelloFilter</filter-name>
</filter>
<filter-mapping>
<!--filter的别名-->
<filter-name>HelloFilter</filter-name>
<!-- 要过滤哪些地址的请求,b下面表示访问hello.jsp的请求-->
<url-pattern>/hello.jsp</url-pattern>
</filter-mapping>
- 配置完成之后就可以使用Filter了
Filter的生命周期
我们在实现接口的时候发现Filter有init方法和destroy方法
服务器管理的Filter也有生命周期(从创建到销毁的过程)
- 创建-初始化。项目加载进服务器,创建Filter对象,并执行Filter对象的构造器方法和init方法。单例多线程。(这一步与Servlet不一样)
- 每次拦截执行doFilter方法。服务器启动的时候需要初始化Filter。
- 销毁,当项目从服务器中卸载时Filter销毁
@Override
public void init(FilterConfig filterConfig) throws ServletException{
}
@Override
public void destroy()
url-parttern 匹配规则
- 精确匹配 (写要拦截的资源的详细路径() /hello.jsp /page/a.jsp)
- 路径匹配:/路径名/* 该目录下的所有资源。
拦截所有访问路径名下的匹配。 - 后缀匹配:*.后缀名,(模糊匹配)
所有以给定的后缀结尾的都拦截。 - 如果以上三种都不能满足要求,则以在filter中动态配置
@Override
public void dpFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException,ServletException{
HttpServletRequest req = (HttpServletRequest) request;
String uri = req.getRequestURI();
//这样就获得的请求地址,可以通过对该地址进行判断,从而执行是否过滤。
}
Filter乱码问题(web请求和响应过程的原理)
如果在chain.doFilter(request,response);之前使用response返回,会发生乱码问题,为什么?
现象:
- 在放行之前response写中文,中文在客户端显示乱码。
- 在放行之后写中文,中文在客户端正常显示。
- 若不放行,依然显示乱码
根本原因:都是在放行之前操作,或者直接操作(没放行直接响应)。
因为我们知道响应乱码的解决一定要在response写东西之前设置。jsp页面一执行就设置编码。放行请求就是等jsp写完页面之后的response,这个response已经设置后编码了。但是如果在请求之前给response写东西,那么就是在设置编码格式之前东西,这就会使response编码格式混乱,以至于出现乱码问题。
在整个客户端与服务器的交互过程中,一个请求对应一个响应,只要请求来了,立马先造一个响应对象。以后处理整个请求,都用的是这个request和这个response
jsp就是一个servlet,给接收到的response添加响应内容。
chain只有一个功能就是放行请求,只要不显式调用,请求不放行。
init方法中的filterConfig
init方法中的filterConfig参数可以获得一些Filter的初始化信息,并且可以获得该项目的ServletContext。
@Override
public void init(FilterConfig filterConfig) throws ServletException{
String filterName = filterConfig.getFilterName;//filter别名
//filter初始化参数
String filterinitParameter = filterConfig.getInitParameter("keyvalue");
//ServletContext-->对应web应用
ServletContext servletContext = filterConfig.getServletContext();
//获取web初始化参数
String initParmeter = servletContext.getInitParameter("key");
//在web.xml中配置,context-param中可以获得。
}
Filter链 多个filter拦截同一个资源
如果有多个Filter拦截同一个页面,那么多个Filter会按照在web.xml中的顺序执行拦截的顺序。具体过程如下图所示
Filter中 dispatcher的配置
dispatcher共有以下四种配置,告诉服务器拦截哪些资源。
- FORWARD 拦截转发过来的
- INCLUDE 拦截包含的
- REQUEST 直接请求的
- ERROR 发生错误的,去全局配置的一个错误页面就会被拦截,不是指页面上的errpage,因为errpage是请求转发的。
默认设置为REQUEST,直接请求会拦截
<filter-mapping>
<!--filter的别名-->
<filter-name>HelloFilter</filter-name>
<!-- 要过滤哪些地址的请求,b下面表示访问hello.jsp的请求-->
<url-pattern>/hello.jsp</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
使用Filter实现事务控制
思想:请求过来处理一些工作(包含一系列工作)–>响应结束。整个过程都是一个线程只要监控这一个线程即可,线程执行期间发生异常,回滚。
通过Filter来监控线程
请求->第一次被Filter拦截->执行其他->回到Filter被拦截->响应完成,都是一个线程在执行。在执行其他工作中有很多步骤,比如修改图书,保存订单,保存订单项。只要执行这些操作作用同一个连接而且这个连接需要手动关闭。
我们在第一次被Filter拦截的时候将每个线程对应的连接保存到map中,并将该链接的自动commit关闭。调用chain.doFilter(request,response);方法。
因为所有的Servlet的方法的执行都是被chain.doFilter(request,response);该方法调用,所以在整个过程发生异常的时候,我们让异常都throws到该方法,该方法就可以捕获异常,一旦捕获到异常,回滚事务,没有捕获到异常,提交事务。