概述
Filter过滤器是JavaWeb三大组件之一。三大组件分别是:Servlet、Listener、Filter
Filter过滤器它是javaEE的规范,也就是接口
Filter过滤器的作用:拦截请求,过滤响应
拦截请求常见的应用场景:
权限检查
日记操作
事务管理
处理中文乱码
登录验证….
Filter的生命周期
Filter的生命周期包含几个方法:
构造器方法:Web工程启动时候执行
init初始化方法:Web工程启动时候执行
doFilter过滤方法:每次拦截到请求就会执行
destroy销毁方法:停止Web工程时候就会执行(停止Web工程,也会销毁Web过滤器)
配置过滤器(Filter)拦截路径
配置Filter的拦截路径有2种方式,一种是注解,一种是xml方式,我们分别进行讲解。
注解方式
我们如果使用注解来进行配置,那么我们就需要使用@WebFilter
filterName:该filter的名字
initParams:初始化参数
displayName:filter显示名称
servletNames:指定对哪些servlet进行过滤
asyncSupported:是否支持异步模式
urlPatterns:指定拦截路径
value:指定拦截路径
Filter的拦截路径
精确匹配
<url-pattern>/target.jsp</url-pattern>
以上配置的路径,表示请求地址为:http://ip:port/工程路径/target.jsp
目录匹配
<url-pattern>/admin/*</url-pattern>
以上配置的路径,表示请求地址为:http://ip:port/工程路径/admin/*
后缀名匹配
<url-pattern>*.html</url-pattern>
以上配置的路径,表示请求地址必须以.html结尾才可拦截到
<url-pattern>*.do</url-pattern>
以上配置的路径,表示请求地址必须以.do结尾才可拦截到(.abc)
注:Filter过滤器只关心请求的地址是否匹配,不关心请求的资源是否存在!!!!
注意:urlPatterns和value是一样的。urlPatterns和value只能配置一个,不能两个都配置,两个都配置就会报错。
对于使用@WebFilter,里面的多个参数用 , 进行分隔。
说明:如果我们仅仅需要配置一个拦截路径,那么我们可以直接简写@WebLister(“拦截路径”),如@WebFilter(“/*”)就是拦截所有请求。
javapackage com.test01.javaweb01.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/filter")
public class FiltetrConfigTest01 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
FilterConfig类
方法名 | 作用 |
---|---|
getFilterName(): | 获取filter的名称 |
getServletContext(): | 获取ServletContext |
getInitparamter(String var1): | 获取配置的初始参数的值 |
getInitParamterNames(): | 获取配置的所有参数名称 |
测试获取配置信息
package com.test01.javaweb01.filter;
import javax.servlet.*;
import java.io.IOException;
import java.util.Enumeration;
public class FilterConfigTest01 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("-----------获取全部key:value------------");
//得到所有配置参数的名字
Enumeration<String> names = filterConfig.getInitParameterNames();
while (names.hasMoreElements()) {
//得到每一个名字
String name = names.nextElement();
System.out.println(name+" = "+filterConfig.getInitParameter(name));
}
System.out.println("-----------end.....------------");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
}
@Override
public void destroy() {
}
}
web,xml配置参数
<filter>
<filter-name>myFilterConfig</filter-name>
<filter-class>com.test01.javaweb01.filter.FilterConfigTest01</filter-class>
<init-param>
<param-name>driver</param-name>
<param-value>com.mysql.cj.jdbc.Driver</param-value>
</init-param>
<init-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/datasource</param-value>
</init-param>
<init-param>
<param-name>username</param-name>
<param-value>root</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>123456</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>myFilterConfig</filter-name>
<url-pattern>/admin</url-pattern>
</filter-mapping>
验证获取
FilterChain
我们查看类图,可以发现FilterChain就只有一个方法,其实这个方法就是用来对拦截进行放行的,如果有多个拦截器,那么就会继续调用下一个Filter进行拦截。doFilter方法需要传入个参数,一个是ServletRequest,一个是ServletResponse参数,这个直接传入进行。
Tomcat在调用过滤器时,默认就会传入Request和Response,这个参数封装了请求和响应,我们直接使用就行。ServletResquest和ServletResponse可以直接强转成HttpServletRequest和HttpServletResponse,然后使用相应的方法。
filter01
package com.test01.javaweb01.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/admin/*")
public class Filter01 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("调用过滤器01对请求进行过滤~~~~");
//放行,如果还有过滤器,那么就执行下一个过滤器
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("调用过滤器01对响应进行过滤~~~~");
}
@Override
public void destroy() {
}
}
filetr02
package com.test01.javaweb01.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/admin/*")
public class Filter02 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("调用过滤器02对请求进行过滤~~~~");
//放行,如果还有过滤器,那么就执行下一个过滤器
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("调用过滤器02对响应进行过滤~~~~");
}
@Override
public void destroy() {
}
}
多个Filter的执行顺序
上面我们配置了2个过滤器,那么我们怎么知道那个过滤器先执行呢?其实大家可以直接使用代码进行验证,培养独立思考的习惯,这里我就直接给出答案了。
如果我们是在web.xml中配置的过滤器,那么过滤器的执行顺序就是在web配置的顺序,配置在上面那么就会先执行。
如果我们是使用@WebFilter进行配置的,那么执行顺序就是字符比较顺序来执行,例如有2个过滤器,一个是AFilter,一个是BFilter,那么AFilter就会先执行。
如果注解和xml混用,那么在web.xml中配置的会先执行。
实现Filet接口,重写对应的方法即可。
实例:登录验证
LoginFiler过滤器
package com.test01.javaweb01.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class LoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("LoginFilter过滤器开始初始化");
}
// Chain 链
// 1.过滤中链中的所有代码,在过滤特定请求的时候都会执行
// 2.必须要让过滤器继续同行
// chain.doFilter(request,response);
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpSession session = httpServletRequest.getSession();
Object user =session.getAttribute("people01");
if (user ==null){
servletRequest.getRequestDispatcher("/login.html").forward(servletRequest,servletResponse);
return;
}else {
// 让程序继续往下访问用户的目标资源文件,不写的话就会在这块拦截停止掉了
filterChain.doFilter(servletRequest,servletResponse);
}
System.out.println(user);
System.out.println("LoginFilter过滤器继续执行");
}
@Override
public void destroy() {
System.out.println("LoginFilter销毁");
}
// 初始化:web服务器启动,就已经初始化了,随时等待过滤对象出现
}
登录用的Servlet程序
package com.test01.javaweb01.filter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.websocket.Session;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
@WebServlet(value = "/loginTest")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 解决乱码问题
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
resp.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
if ("people01".equals(username) && "123456".equals(password)){
req.getSession().setAttribute("people01",new People(username,password));
resp.getWriter().write("验证成功!");
HttpSession session = req.getSession();
People people01 = (People) session.getAttribute("people01");
System.out.println(people01);
}else {
System.out.println("验证失败!!");
req.getRequestDispatcher("/login.html").forward(req,resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
protected void removeSession(HttpServletRequest req,HttpServletResponse resp) throws UnsupportedEncodingException {
// 解决乱码问题
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=utf-8");
HttpSession session = req.getSession();
session.removeAttribute("person01");
// 手动注销session
// session.invalidate();
}
}
html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<form action="http://localhost:8080/JavaWeb01/loginTest" method="get">
<label>用户名:<input type="text" name="username"></label>
<label>密码:<input type="text" name="password"></label>
<input type="submit">
</form>
</body>
</html>
配置filter过滤器的路径
<filter>
<filter-name>loginFilter</filter-name>
<filter-class>com.test01.javaweb01.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loginFilter</filter-name>
<!-- 过滤该路径下的所有请求-->
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
在webapps目录下创建admin/private.html页面,当外界想要访问到该文件目录下的资源时,我们的过滤器就会去session里面获取person01对象,如果有就让客户端继续访问资源进行相关的操作,否则就拦截并重定向到login.html页面。