发布时间:2023-06-03 14:30
Filter是Servlet技术中最实用的技术,通过Filter过滤技术,对web服务器上所有的web资源进行管理:例如Jsp,
Servlet, 静态图片文件或静态 html 文件等进行拦截/放行,从而能够实现一些特殊的功能。
比如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能 处理编码。
它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。
使用Filter的完整流程:
具体描述----->>>>
1,在HttpServletRequest到达 Servlet 之前,拦截客户的HttpServletRequest。根据需要检查HttpServletRequest,也可以修改HttpServletRequest 头和数据。
2,在HttpServletResponse到达客户端之前,拦截HttpServletResponse根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。
3Filter接口中有一个doFilter方法,当开发人员编写好Filter,并配置对哪个web资源进行拦截后,Web服务器每次在调用web资源的service方法之前,都会先调用一下filter的doFilter方法**,doFilter方法中有一个filterChain对象,用于继续传递给下一个filter,**在传递之前我们可以定义过滤请求的功能,在传递之后,我们可以定义过滤响应的功能
简单的框架实现---->>>
首先定义一个servlet
public class MyServlet1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding(\"UTF-8\");
resp.setContentType(\"text/html;charset=UTF-8\");
resp.getWriter().println(\"MyServlet1--invoke\");
}
}
然后定义一个过滤器----->>>
自定义过滤器要实现servlet包下的Filter接口,接口中有有三个方法-----
初始化方法----init(FilterConfig filterConfig)
过滤方法---- doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
销毁过滤器方法----destroy()
其中和新方法是 doFilter方法来对请求和访问进行过滤和处理的;
import javax.servlet.*;
import java.io.IOException;
public class MyFilter implements Filter {
//初始化方法
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println(\"初始化完成\");
}
//过滤方法
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println(\"请求已过滤\");
}
//销毁方法
@Override
public void destroy() {
}
}
准备好这些后,还要指定过滤器访问哪个servlet时使用该过滤器;
配置web.xml
<web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\"
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd\"
version=\"4.0\">
<servlet>
<servlet-name>MyServlet1servlet-name>
<servlet-class>com.gavin.myfiflter.MyServlet1servlet-class>
servlet>
<servlet-mapping>
<servlet-name>MyServlet1servlet-name>
<url-pattern>/MyServlet1.dourl-pattern>
servlet-mapping>
<filter>
<filter-name>MyFilterfilter-name>
<filter-class>com.gavin.fiflter.MyFilterfilter-class>
filter>
<filter-mapping>
<filter-name>MyFilterfilter-name>
<url-pattern>/MyServlet1.dourl-pattern>
filter-mapping>
web-app>
框架搭建完毕后,运行
但是浏览器中闭关没有输出任何信息,是因为我们只是定义了过滤,对过滤之后没有进行任何处理,所以相当于给全部过滤掉了,那这个时候需要添加一些代码对请求/响应进行过滤处理,这时候服务器才能对请求做出真正的响应;
import javax.servlet.*;
import java.io.IOException;
public class MyFilter implements Filter {
//初始化方法
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println(\"初始化完成\");
}
//过滤方法
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println(\"请求已过滤\");
//放行请求,继续让过滤链中的其他过滤器过滤
filterChain.doFilter(servletRequest,servletResponse);
System.out.println(\"对响应进行过滤\");
servletResponse.getWriter().print(\"过滤之后添加的响应内容\");
}
//销毁方法
@Override
public void destroy() {
System.out.println(\"已销毁\");
}
}
再次访问之后-----
同时一个而过滤器可以过滤多个servlet对象
同servlet对象一样,Filter对象的创建也是交给web服务器完成的,在web服务器创建和使用及最后销毁filter时,会调用filter对应的方法
构造方法:
实例化一个Filter对象的方法
初始化方法:
public void init(FilterConfig filterConfig);
和我们编写的Servlet程序一样,Filter的创建和销毁由WEB服务器负责。 web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。
拦截请求方法
public void doFilter
这个方法完成实际的过滤操作。当客户请求访问与过滤器关联的URL的时候,Servlet过滤器将先执行doFilter方法。FilterChain参数用于访问后续过滤器。
销毁方法:
public void destroy();
Filter对象创建后会驻留在内存,当web应用移除或服务器停止时才销毁。在Web容器卸载 Filter 对象之前被调用。该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源。
简要描述:
1 WEB 容器启动时,会对Filter进行构造并初始化 一次
2 每次请求目标资源时,都会执行doFilter的方法
3 WEB容器关闭是,会销毁Filter对象
搭建架构-----
准备两个过滤器,一个servlet
过滤器链原理分析---->>>
web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源。
使用过滤器链的好处是我们可以将不同的过滤功能分散到多个过滤器中,分工明确,避免一个过滤器做太多的业务处理,降低了代码的耦合度,这体现了单一职责的设计原则,应用了责任链的代码设计模式.
决定过滤器的执行顺序是由filter-mapping标签决定
过滤器的配置跟servlet类似,可以在web.xml中配置一些初始化参数
那这些参数该如何取出来呢?
我们回到Filter的生命周期–
初始化的时候我们可以覆写一下 init()方法
public void init(FilterConfig filterConfig) throws ServletException
在这个方法中有一个参数FilterConfig filterConfig),通过这个参数来取出数据!
通过配置文件比较麻烦的话,我们还可以通过注解模式来开发过滤器
/*@WebServlet(name= \"MyServlet3\")*/
@WebFilter(urlPatterns = \"/MyServlet3.do\" ,initParams ={@WebInitParam(name=\"UserInfo\",value = \"张三\"),@WebInitParam(name=\"Charset\",value = \"UTF-8\") })
public class NewFilterDemo implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println(filterConfig.getFilterName());
System.out.println(filterConfig.getInitParameter(\"Charset\"));
System.out.println(filterConfig.getInitParameter(\"UserInfo\"));
filterConfig.getServletContext().setAttribute(\"userN\",\"Gavin\");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
注解两种方式---->>>
注解方式下过滤器的执行顺序------
在配置文件模式下配置的过滤器执行顺序跟过滤器的放置顺序有关系,那么在注解模式下,过滤器的执行顺序是怎样的呢?
做一个测试----->>>>
准备两个过滤器-----
Filter0_Demo
和Filter1_Demo,都对MyServlet3.do进行过滤-----结果
下面修改一下Filter0_Demo为Filter8_Demo
再次添加一个过滤器----Filter6_Demo
可以看到确实是按照名字进行排序的,所以在命名过滤器时要注意名字的命名规范,一般原则是Filter数字_过滤器描述
先看一下 form表单 通过get的方式请求,服务器获得的数据
<%--
<%@ page contentType=\"text/html;charset=UTF-8\" language=\"java\" %>
<html>
<head>
<title>$Title$title>
head>
<body>
<form action=\"PostDemo.do\" method=\"get\">
用户名:<input type=\"text\" name=\"user\" placeholder=\"请输入用户名\">
密 码:<input type=\"password\" name=\"pwd\" placeholder=\"请输入密码\">
<input type=\"submit\" value=\"提交\">
form>
body>
html>
后台得到的数据
换成post方式得到的数据---->>>
怎么办?在servlet中设置解码方式----
但是如果servlet很多的话挨个写?..
这时候过滤器就可以起作用了>
可以使得买次请求时都通过过滤器设置编码格式为UTF-8
最后实现的结果跟在每个Servlet种单独设置是一样的----->>
还有一个间接的方式----在定义过滤器时可以将charset 放到 初始化时的参数中,通过读取参数来完成charset的设置;
Cannot invoke “String.toLowerCase(java.util.Locale)” because “enc” is null 该如何解决?