javaweb-filter过滤器-爱代码爱编程
Filter过滤器是JavaWeb的三大组件之一,Filter过滤器是JavaEE的规范也就是接口,Filter的作用是拦截请求,过滤响应。拦截请求常见的应用场景:权限检查、日志操作、事务管理等等。
Filter过滤器的基本使用
例如权限检查,若没有成功验证用户信息无法打开目标页面。
<%
Object user = session.getAttribute("user");
if (user == null){
request.getRequestDispatcher("/login.jsp").forward(request,response);
return;
}
%>
用户登录后会将用户登陆信息保存到Session域中,所以要检查用户是否登录,判断Session中是否包含用户登录信息。
客户端(浏览器) -> Filter过滤器(进行权限检查,检查用户是否有登录,如果有权限则程序默认执行,如果没有权限控制程序流转,不允许其访问)
package com.pero.servlet;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
public class AdminFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
/**
* doFilter方法专门用于拦截请求,可以做权限检查
* @param servletRequest
* @param servletResponse
* @param filterChain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//先获取httpServletRequest对象,通过该对象获取Session
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpSession session = httpServletRequest.getSession();
Object attribute = session.getAttribute("user");
//表示还没有登陆
if (attribute == null){
servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse);
}else {
//程序继续向下执行
filterChain.doFilter(servletRequest,servletResponse);
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<!-- Filter标签用于配置一个Filter过滤器 -->
<filter>
<!-- 配置Filter别名 -->
<filter-name>AdminFilter</filter-name>
<!-- 配置Filter全类名 -->
<filter-class>com.pero.servlet.AdminFilter</filter-class>
</filter>
<!-- 配置Filter过滤器的拦截路径 -->
<filter-mapping>
<!-- 表示当前拦截路径给哪一个Filter -->
<filter-name>AdminFilter</filter-name>
<!-- 配置拦截路径
/admin/* 表示http://ip:port/工程路径/ admin目录下的所有文件
-->
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.pero.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/loginServlet</url-pattern>
</servlet-mapping>
</web-app>
package com.pero.servlet;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
String username = request.getParameter("username");
String password = request.getParameter("password");
if ("root".equals(username) && "root".equals(password)){
request.getSession().setAttribute("user",username);
response.getWriter().write("登陆成功");
}else {
request.getRequestDispatcher("/login.jsp").forward(request,response);
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2023/3/16
Time: 22:07
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登陆页面</title>
</head>
<body>
<form action="http://localhost:8080/Filter_Web/loginServlet" method="get">
用户名:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>
<input type="submit" value="提交">
</form>
</body>
</html>
Filter的生命周期
Filter的生命周期是指Filter从创建到销毁整个过程执行方法的顺序。包含以下方法:
1.构造器方法;
2.init初始化方法;
3.doFilter过滤方法;
4.destory销毁方法;
在Web工程启动的时候构造器方法和初始化方法会被执行(Filter对象已经创建),每次拦截到请求时会执行doFilter方法,停止Web工程的时候就会执行destory方法。
FilterConfig类
FilterConfig类是Filter过滤器的配置文件类,Tomcat每次创建Filter的时候也会同时创建一个FilterConfig类,这里面包含了Filter配置文件的配置信息。
FilterConfig类的作用是获取Filter过滤器的配置内容
1.获取Filter的名称filter-name的内容
2.获取web.xml配置的init-param初始化参数
3.获取ServletContext对象
package com.pero.servlet;
import jakarta.servlet.*;
import java.io.IOException;
public class TestFilter implements Filter {
public TestFilter() {
System.out.println("构造方法");
}
public void init(FilterConfig config) throws ServletException {
System.out.println("init初始化方法");
//获取Filter的名称filter-name的内容
String filterName = config.getFilterName();
//获取web.xml配置的init-param初始化参数
System.out.println("filter-name为:" + filterName);
String username = config.getInitParameter("username");
String url = config.getInitParameter("url");
System.out.println("username:" + username + "url:" + url);
//获取ServletContext对象
ServletContext servletContext = config.getServletContext();
System.out.println("servletContext:" + servletContext);
}
public void destroy() {
System.out.println("destory销毁方法");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
System.out.println("doFilter方法");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<!-- Filter标签用于配置一个Filter过滤器 -->
<filter>
<!-- 配置Filter别名 -->
<filter-name>AdminFilter</filter-name>
<!-- 配置Filter全类名 -->
<filter-class>com.pero.servlet.AdminFilter</filter-class>
</filter>
<filter>
<filter-name>TestFilter</filter-name>
<filter-class>com.pero.servlet.TestFilter</filter-class>
<init-param>
<param-name>username</param-name>
<param-value>root</param-value>
</init-param>
<init-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/test</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>TestFilter</filter-name>
<url-pattern>/testFilter</url-pattern>
</filter-mapping>
<!-- 配置Filter过滤器的拦截路径 -->
<filter-mapping>
<!-- 表示当前拦截路径给哪一个Filter -->
<filter-name>AdminFilter</filter-name>
<!-- 配置拦截路径
/admin/* 表示http://ip:port/工程路径/ admin目录下的所有文件
-->
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.pero.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/loginServlet</url-pattern>
</servlet-mapping>
</web-app>
FilterChain过滤器链
客户端(浏览器) -> 服务器(Filter①:执行doFilter()方法:前置代码1 -> chain.doFilter(request, response); -> Filter②:执行doFilter()方法 :前置代码1 -> chain.doFilter(request, response); -> 查询目标资源,找到并获取 -> 后置代码2 -> Filter①:执行doFilter()方法:后置代码2)
FilterChain.doFilter()方法的作用:①如果有其他的Filter过滤器,执行下一个Filter过滤器;②如果没有其他需要执行的过滤器,执行目标资源。
多个Filter过滤器执行的时候他们执行的优先顺序是由在web.xml中filter-mapping从上到下的配置顺序决定的。
多个Filter过滤器执行的特点:
①所有Filter和目标资源默认都执行在同一个线程中
②多个Filter共同执行的时候,他们都使用同一个Request对象。
package com.pero.servlet;
import jakarta.servlet.*;
import java.io.IOException;
import java.lang.Thread;
public class Filter1 implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
System.out.println("Filter1前置代码");
System.out.println("Filter1线程" + Thread.currentThread().getName());
System.out.println("Filter1" + request.getParameter("username"));
chain.doFilter(request, response);
System.out.println("Filter1线程" + Thread.currentThread().getName());
System.out.println("Filter1后置代码");
}
}
package com.pero.servlet;
import jakarta.servlet.*;
import java.io.IOException;
public class Filter2 implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
System.out.println("Filter2前置代码");
System.out.println("Filter2线程"+Thread.currentThread().getName());
System.out.println("Filter2" + request.getParameter("username"));
chain.doFilter(request, response);
System.out.println("Filter2线程"+Thread.currentThread().getName());
System.out.println("Filter2后置代码");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
...
<filter>
<filter-name>Filter1</filter-name>
<filter-class>com.pero.servlet.Filter1</filter-class>
</filter>
<filter>
<filter-name>Filter2</filter-name>
<filter-class>com.pero.servlet.Filter2</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter1</filter-name>
<url-pattern>/target.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Filter2</filter-name>
<url-pattern>/target.jsp</url-pattern>
</filter-mapping>
...
</web-app>
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2023/3/17
Time: 10:30
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
System.out.println("target页面执行");
System.out.println("目标资源"+Thread.currentThread().getName());
System.out.println("目标资源" + request.getParameter("username"));
%>
</body>
</html>
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
Filter过滤器只关心请求的值是否匹配,不关心资源是否存在