目次
1. フィルターを使用したクイックスタート
1.基本的な紹介:
Filter は、JavaWeb の 3 つの主要コンポーネント (サーブレット プログラム、 リスナー 、 フィルター ) の 1 つです。リスナーとフィルターは本質的にはサーブレット仕様に属しますが、機能が独立しているため、JavaWeb の 3 つの主要コンポーネントとして個別に見なされます。Filter はインターフェースであり、頻繁に使用されます。従来の検証方法によって引き起こされるコードの冗長性や機能の重複の問題を解決するだけでなく、フィルターはログ操作、権限チェック、トランザクション管理などのシナリオにも適用できます。
2. 基本原則:
(1)ブラウザが HTTP リクエストをサーバーに送信すると、 Tomcat は、web.xml 設定ファイルで設定されたフィルタと、指定されたフィルタの URL パターン ルールに基づいて、現在のリクエストにフィルタが必要かどうかを判断します。PS: フィルタリング ルールはプログラマが手動で指定できます。
(2)フィルタが必要ないと判断した場合は、Web リソース(サーブレット、Web 静的ページなど)に直接アクセスします。
(3) Tomcatは必要と判断した場合、ビジネス要件に応じて検証を行い、正当な検証であればアクセスを続行し、正当な検証でなければ を返します。PS: 返される特定の URL は、プログラマが手動で指定することもできます。
(4) Tomcat がサーブレットやその他の Web リソースを呼び出す前に、最初にフィルターと一致します。つまり、要求された URL (req オブジェクトによってカプセル化されている) に従って、フィルターの URL を管理するコンテナー内で一致します。一致が成功すると、管理されます。Filter コンテナ内で対応する Filter インスタンスを見つけて、その doFilter メソッドを呼び出します。一致するものがない場合は、Web リソースに直接アクセスします。(手書きの Tomcat の最下層でサーブレットを管理するために使用される 2 つの Map コンテナーに連絡します)
3. 開始の例:
ユーザーのログイン操作に使用されるlogin.jspページを定義します。データはLoginCheckServletに送信されます。パスワードが233に等しい場合、管理者ログインとみなされ、リクエストはadministration.jspページに転送されます。 (ユーザー管理ページ)。Administration.jsp ページはターゲット パッケージの下で定義され、フィルタ LoginFilter を定義し、フィルタリング ルールは /target/* です。
login.jsp ページのコードは次のとおりです。
<%--
User : Cyan_RA9
Version : 21.0
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>login</title>
<style>
table, td {
border: cornflowerblue 2px solid;
background-color: lightcyan;
border-collapse: collapse;
padding: 5px;
}
</style>
</head>
<body>
<form action="<%= request.getContextPath() %>/loginCheckServlet" method="post">
<table>
<tr>
<th colspan="2">Manage the login</th>
</tr>
<tr>
<td>Username : </td>
<td><input type="text" name="username"/></td>
</tr>
<tr>
<td>Password : </td>
<td><input type="password" name="password"/></td>
</tr>
<tr>
<td><input type="submit" value="submit"/></td>
<td><input type="reset" value="reset"/></td>
</tr>
</table>
</form>
</body>
</html>
ページ効果は次のとおりです。
LoginCheckServlet クラスのコードは次のとおりです。
package filter;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author : Cyan_RA9
* @version : 21.0
*/
@WebServlet(urlPatterns = {"/loginCheckServlet"})
public class LoginCheckServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
RequestDispatcher requestDispatcher = null;
if ("233".equals(password)) {
//若验证合法,向session中放入用户名
req.getSession().setAttribute("username", username);
requestDispatcher = req.getRequestDispatcher("/target/administration.jsp");
requestDispatcher.forward(req, resp);
} else {
requestDispatcher = req.getRequestDispatcher("/login.jsp");
requestDispatcher.forward(req, resp);
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
Administration.jsp ページのコードは次のとおりです。
<%--
User : Cyan_RA9
Version : 21.0
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>target</title>
<%--<base href="<%= request.getContextPath() %>/img/"/>--%>
<style>
table, td {
border: 2px lightpink solid;
background-color: lightcyan;
border-collapse: collapse;
padding: 10px;
margin-left: auto;
margin-right: auto;
}
</style>
</head>
<body>
<table width="500px">
<tr>
<th>ID</th>
<th>Username</th>
<th>Function</th>
</tr>
<tr>
<td>100011</td>
<td>Cyan</td>
<td><a href="none">删除用户</a></td>
</tr>
<tr>
<td>100023</td>
<td>Rain</td>
<td><a href="none">删除用户</a></td>
</tr>
<tr>
<td>100033</td>
<td>Ice</td>
<td><a href="none">删除用户</a></td>
</tr>
<tr>
<td>100041</td>
<td>Five</td>
<td><a href="none">删除用户</a></td>
</tr>
<tr>
<td>100099</td>
<td>Irving</td>
<td><a href="none">删除用户</a></td>
</tr>
</table>
</body>
</html>
ページ効果は次のとおりです。
LoginFilter フィルターを定義して、ユーザーによる不正なアクセスを遮断し、管理者以外のユーザー管理インターフェイスへの不正なアクセスを防ぎます。LoginFilter クラスのコードは次のとおりです。
package filter;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
public class LoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("LoginFilter is initialized~");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("LoginFilter's doFilter method is invoked~");
/**
* (1) 每次调用该Filter对象时,都会动态绑定调用doFilter方法;
* (2) 若doFilter方法中没有调用继续请求的方法,那么对请求的资源的访问就会卡在这里。
* (3) Tomcat在调用Filter之前,就已经创建好了req和resp对象,并且req中已经封装好了
* HTTP请求的相关信息。因此,可以通过req对象来获取到这些信息,例如URL,session,
* 等等,从而实现日志操作,权限检查,事务管理等业务需求。
* (4) 可以通过filterChain对象的doFilter方法将servletRequest对象和
* servletResponse对象传递下去。
* (5) 特别注意:请求转发不经过过滤器!(在服务器端)
*/
//动态---动态绑定的使用
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpSession session = httpServletRequest.getSession();
//session中的属性可能之后会用到(eg : log),因此可以单独做接收。
String username = (String) session.getAttribute("username");
if (username != null) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
RequestDispatcher requestDispatcher = servletRequest.getRequestDispatcher("/login.jsp");
requestDispatcher.forward(servletRequest, servletResponse);
}
/**
* 关于filterChain.doFilter方法 :
* (1) 该方法执行,会继续访问URL的目标资源;
* (2) 创建好的servletRequest对象和servletResponse对象会传递给目标资源(servlet/jsp,etc)
* (3) 因此,目标资源中获得的这两个对象是相同的对象 (同一次HTTP请求中)
*/
}
@Override
public void destroy() {
System.out.println("LoginFilter is destroyed~");
}
}
web.xml 構成ファイルでフィルターを構成します。コードは次のとおりです。
<?xml version="1.0" encoding="UTF-8"?>
<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">
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/target/*</url-pattern>
</filter-mapping>
<!--
此处的<url-pattern>即指过滤规则,当请求的URL满足该条件时,
都需要走该过滤器。这时Tomcat会调用该Filter的doFilter()方法。
(回顾URL四种匹配模式)
-->
</web-app>
ランニング効果:(下のGIF)
4. ライフサイクル:
(1) Web プロジェクトが開始されると、Tomcat はリフレクション メカニズムに基づいて対応する Filter インスタンスを作成し ( Filter は 1 回だけ作成されます)、Tomcat が管理するコンテナに保存します。
(2) Tomcat は、デフォルトのパラメーターなしのコンストラクターとフィルターに対応する init メソッドを実行します ( init メソッドは HTTP リクエストで 1 回だけ呼び出されます)。フィルター インスタンスはメモリ内に常駐します。
(3) Filter インスタンスを作成するとき、Tomcat は FilterConfig オブジェクトも作成し、それを init メソッドを通じて渡します。プログラマは、FilterConfig オブジェクトを通じてフィルタの関連構成情報を取得できます。
(4)クライアントから HTTP リクエストが送信されると、Tomcat は HTTP リクエストの URL がフィルタの <url-pattern> と一致するかどうかを判定し、一致する場合は対応するフィルタの doFilter メソッドを呼び出します。さらに、 Tomcat は ServletRequest オブジェクト、ServletResponse オブジェクト、および FilterChain オブジェクトを同時に作成し、それらを doFilter メソッドを通じて渡します。
(5) Web プロジェクトが停止したら、Filter インスタンスを破棄し、destroy メソッドを呼び出します。
2. FilterConfig と FilterChain
1.フィルター構成:
1° 基本的な紹介
FilterConfig はFilter フィルターの構成クラスです。FilterConfigオブジェクトの目的は、 Filter フィルターの構成コンテンツを取得することです。
2° 応用例
web.xml でフィルターを再構成します。web.xml コードは次のとおりです。
<?xml version="1.0" encoding="UTF-8"?>
<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">
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/target/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>FilterConfig_Demo</filter-name>
<filter-class>filter.FilterConfig_Demo</filter-class>
<init-param>
<param-name>color</param-name>
<param-value>cyan</param-value>
</init-param>
<init-param>
<param-name>sport</param-name>
<param-value>basketball</param-value>
</init-param>
<init-param>
<param-name>fruit</param-name>
<param-value>grape</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>FilterConfig_Demo</filter-name>
<url-pattern>/filterConfig_Demo</url-pattern>
</filter-mapping>
</web-app>
FilterConfig_Demo クラスのコードは次のとおりです。
package filter;
import jakarta.servlet.*;
import java.io.IOException;
import java.util.Enumeration;
public class FilterConfig_Demo implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//获取当前过滤器的名称
String filterName = filterConfig.getFilterName();
System.out.println("filterName = " + filterName);
//获取当前过滤器中配置的参数(根据name获取指定参数)
String color = filterConfig.getInitParameter("color");
String fruit = filterConfig.getInitParameter("fruit");
String sport = filterConfig.getInitParameter("sport");
System.out.println("color = " + color);
System.out.println("fruit = " + fruit);
System.out.println("sport = " + sport);
//获取当前过滤器中配置的全部参数
Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();
while (initParameterNames.hasMoreElements()) {
System.out.println("parameter's name = " + initParameterNames.nextElement());
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
RequestDispatcher requestDispatcher = servletRequest.getRequestDispatcher("/Listener_Filter/login.jsp");
requestDispatcher.forward(servletRequest, servletResponse);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
ランニング効果:(下のGIF)
2.フィルターチェーン:
1° 基本的な紹介
FilterChain、フィルターチェーン。一部の複雑なサービスを処理する場合、1 つのフィルタでは不十分であり、複数のフィルタを設計してフィルタリング タスクをまとめて完了し、フィルタ チェーンを形成できます。
2° 基本原則
以下に示すように:
3° 応用例
Filter_Demo1 と Filter_Demo2 という 2 つのフィルターを定義し、web.xml 構成ファイルで 1--->2 の順序で構成します。
web.xml 構成ファイルのコードは次のとおりです。
<?xml version="1.0" encoding="UTF-8"?>
<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">
<filter>
<filter-name>Filter_Demo1</filter-name>
<filter-class>filter.Filter_Demo1</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter_Demo1</filter-name>
<url-pattern>/img/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>Filter_Demo2</filter-name>
<filter-class>filter.Filter_Demo2</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter_Demo2</filter-name>
<url-pattern>/img/cornflower.jpg</url-pattern>
</filter-mapping>
</web-app>
Filter_Demo1 クラスのコードは次のとおりです。
package filter;
import jakarta.servlet.*;
import java.io.IOException;
public class Filter_Demo1 implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Filter_Demo1 ———— doFilter's fore code");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("Filter_Demo1 ———— doFilter's end code");
}
}
Filter_Demo2 クラスのコードは次のとおりです。
package filter;
import jakarta.servlet.*;
import java.io.IOException;
public class Filter_Demo2 implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Filter_Demo2 ———— doFilter's fore code");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("Filter_Demo2 ———— doFilter's end code");
}
}
ランニングエフェクト:(GIF)
4° 使用方法の詳細
(1) 同じ HTTP リクエスト内で、同じスレッドが複数のフィルターを渡してターゲット リソースにアクセスする役割を果たします。(複数のフィルターが同じリクエスト オブジェクトを使用します)
(2) HTTP リクエストの URL が設定されたフィルターの URL パターンと一致する場合にのみ、フィルターの doFilter メソッドが実行され、同じ HTTP リクエスト内で複数のフィルターが正常に一致した場合は、それらのフィルターが順番に実行されます。 、フィルター呼び出しチェーンを形成します。(複数のフィルターの実行順序は、web.xml 構成ファイルで構成された順序と一致します)
(3) filterChain.doFilter()メソッドが実行されると、次に一致するフィルタのdoFilterメソッドが実行されます。現在のフィルターの後に他に一致するフィルターがない場合、ターゲット リソースが実行されます。
System.out.println("END------------------------------------------ -------------------------------------------------- ------------------------------------");