フィルターとインターセプターは、日常のビジネス開発ではあまり使用されません. 最近のプロジェクトで時々遭遇する. フィルターとインターセプターの体系的な研究が行われました.
1. フィルター
1.1 フィルターとは
Filter は、Filter インターフェイスを実装する Java クラスである Servlet の高度な機能の 1 つです。その基本的な機能は、サーブレットの呼び出しに介入し、サーブレットの要求と応答のプロセスにいくつかの特定の機能を追加することです。フィルターを使用して実装できる機能には、統一されたエンコード、URL レベルのアクセス許可のアクセス制御、機密性の高い単語のフィルター処理、および要求情報の圧縮が含まれます。
1.2 フィルターの実行
1.3 フィルターインターフェース
Filter インターフェイス コードを見ると、次の 3 つの方法があります。
public interface Filter {
default void init(FilterConfig filterConfig) throws ServletException {
}
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
default void destroy() {
}
}
init(FilterConfig conf) メソッド: フィルターを初期化するために使用され、Web プロジェクトの開始時に Web コンテナーがこのメソッドを自動的に呼び出します。
doFilter(ServletRequest request, SerlvetResponse response, FilterChain chain) メソッド: リクエストとレスポンスがフィルタによってインターセプトされると、処理のために doFilter に渡されます: 2 つのパラメータは、インターセプトされたリクエスト オブジェクトとレスポンス オブジェクトであり、手放す連鎖のdoFliterメソッド。
destroy() メソッド: Filter オブジェクトを閉じることによって開かれたリソースを解放するために使用されます. Web プロジェクトが閉じられると、このメソッドは Web コンテナーによって自動的に呼び出されます.
1.4 フィルターの開発方法
フィルタの開発は比較的簡単です. 最初のステップは Filter インターフェースを実装することであり, 2番目のステップはフィルタを構成することです.
次のように簡単なフィルタ コードを作成します。
package com.lsl.mylsl.filter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
@Component
@WebFilter(filterName = "myFilter",urlPatterns = {"/*"})
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//获取filter名字
String filterName = filterConfig.getFilterName();
//获取filter里配置的init-param配置指定参数的值,如果参数不存在,则返回 null
String email = filterConfig.getInitParameter("email");
//获取filter里配置的init-param配置所有参数值,如果过滤器没有初始化参数,则返回一个空的 Enumeration
Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();
//返回对调用者在其中执行操作的 ServletContext 的引用。
ServletContext servletContext = filterConfig.getServletContext();
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
//统一编码处理
httpRequest.setCharacterEncoding("UTF-8");
httpResponse.setContentType("text/html;charset=UTF-8");
//添加name属性
httpRequest.setAttribute("name", "tom");
//获取请求中的所有cookie
Cookie[] cookies = httpRequest.getCookies();
if (cookies != null) {
StringBuilder sb = new StringBuilder();
for (Cookie cookie : cookies) {
String cookieName = cookie.getName();
String cookieValue = cookie.getValue();
//设置cookie的相关属性
ResponseCookie lastCookie = ResponseCookie.from(cookieName, cookieValue).httpOnly(true).sameSite("Lax").build();
httpResponse.addHeader(HttpHeaders.SET_COOKIE, lastCookie.toString());
}
filterChain.doFilter(httpRequest, httpResponse);
}
}
@Override
public void destroy() {
}
}
2 番目のステップは、フィルターを構成することです。
filter を構成するには 3 つの方法があり 、上記のコードはその 1 つです (注釈構成)。
最初のタイプ: web.xml で構成する
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.lsl.mylsl.filter.MyFilter</filter-class>
<init-param>
<param-name>email</param-name>
<param-value>15***[email protected]</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<フィルター> 構成
Fliter-name: フィルターの名前を参照します
filter-class: フィルターの完全なクラス名
init-param: フィルターの初期化パラメーターを指定するために使用され、そのサブ要素はパラメーターの名前を指定します
<フィルター マッピング> 構成
filter-name: <filter> で宣言したフィルター名
url-patten: フィルターによってインターセプトされる要求パスを設定します (フィルターに関連付けられた URL パターン)
2 番目のタイプ: 注釈構成。これは比較的単純で、フィルターに注釈を定義します。
@WebFilter(filterName = "myFilter",urlPatterns = {"/*"})
3 番目の方法: 構成クラスを使用すると、関連するコードは次のようになります。
package com.lsl.mylsl.filter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyFilterConfig {
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean fb = new FilterRegistrationBean();
//设置filter启动顺序
fb.setOrder(1);
fb.setFilter(new MyFilter());
fb.addInitParameter("email","15***[email protected]");
//设置拦截请求规则,这里拦截所有请求
fb.addUrlPatterns("/*");
return fb;
}
}
これら 3 つのフィルター構成の長所と短所を次に示します。
最初のタイプの xml 構成は xml で記述する必要がありますが、現在ではほとんどがアノテーションと軽い構成に焦点を当てた springboot プロジェクトによって開発されており、現在はあまり使用されていません。複数のフィルターが xml で構成されている場合、それらは上から下に順番に機能します。
2 番目のアノテーション構成は比較的簡単に記述できますが、複数のフィルターでシーケンスを制御できないという欠点があります。このアノテーションを使用したいが、フィルターの順序を制御したい場合、フィルター名の最初の文字の順序を使用して順序を決定するというインターネット上の言い伝えがあります。名前が AdminFilter および UserFilter である複数のフィルターの場合、前者が最初に有効になり、後者が後で有効になります。
構成構成の 3 番目のタイプ、私は個人的にこれを好みます (もちろん、単純なフィルターの場合は、注釈を使用するのが最も簡単で便利です)、xml 構成のすべての機能を備えています。起動シーケンス、初期化パラメータなどを定義できます。
2.インターセプターインターセプター
2.1 インターセプターとは
Spring MVC
Interceptor
のインターセプター ( ) は ServLetのフィルター ( ) に似ておりFilter
、主にユーザーの要求をインターセプトし、対応する処理を行うために使用されます。たとえば、インターセプターは、権限の検証を実行したり、要求情報のログを記録したり、ユーザーがログインしているかどうかを判断したりできます。
2.2 インターセプターの動作原理
インターセプター。preHandle メソッドが true を返す場合のみ、postHandle および afterCompletion を実行できます。preHandle メソッドが false を返す場合、インターセプターの postHandle および afterCompletion は実行されません。インターセプターはフィルターではありませんが、フィルターの機能を実現します。原理は次のとおりです。
すべてのインターセプター (Interceptor) とプロセッサー (Handler) は HandlerMapping に登録されます。
Spring MVC のすべてのリクエストは、DispatcherServlet によってディスパッチされます。
リクエストが DispatcherServlet.doDispatch() に入ると、リクエストを処理するハンドラ (つまり、コントローラ内の対応するメソッド) と、リクエストをインターセプトするすべてのインターセプタが最初に取得されます。ここでインターセプターが呼び出され、作業が開始されます。
2.3 インターセプターの使用シナリオ
インターセプターは本質的にアスペクト指向プログラミング (AOP) です. 分野横断的な懸念を満たす機能をインターセプターに実装できます. 主なアプリケーション シナリオは次のとおりです:
- ログイン認証。ユーザーがログインしているかどうかを判断します。
- トークンの検証など、ユーザーがリソースにアクセスする権限を持っているかどうかを判断するための権限
検証
- Cookie、ローカリゼーション、国際化、テーマ設定などを処理します。
・性能監視、リクエスト処理時間の監視など
2.4、インターセプターインターフェース HandlerInterceptor
package org.springframework.web.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
コードからわかるように、インターセプター インターフェイスには 3 つのメソッドがあり、それぞれの関数は次のとおりです。
preHandle メソッド:前処理メソッドと呼ばれ、このメソッドはコントローラー メソッド (MyController メソッド) の前に実行され、ユーザーの要求はこのメソッドに最初に到着します。このメソッドでは、要求された情報を取得し、要求が要件を満たしているかどうかを検証できます。ユーザーがログインしているかどうかを確認するには、ユーザーが特定のリンク アドレス (url) にアクセスする権限を持っているかどうかを確認します。true を返すと解放され、false を返すと傍受されます。
postHandle メソッド: 後処理メソッドと呼ばれます。コントローラーのメソッドの後に実行されます。processor メソッドの戻り値 mv を取得し、mv 内のデータとビューを変更できます。最終的な実行結果に影響を与える可能性があります。主に元の実行結果に対する二次修正を行うため
afterCompletion メソッド: 最後に実行されたメソッドで、ページがレンダリングされた後に実行されます。これは、リクエスト処理が完了した後に実行されます. フレームワークは、ビュー処理が完了すると、ビューが転送されることを規定しています. タスク要求の処理が完了しました。一般に、リソースの回復作業を行う場合、プログラム要求プロセス中にいくつかのオブジェクトが作成されます。ここで削除できます、占有されているメモリを解放しましょう
2.5 インターセプターの開発
インターセプターの開発にも 2 つのステップが必要です. 最初のステップは HandlerInterceptor インターフェースを実装してインターセプターを定義することです. 2 番目のステップはインターセプターを構成することです.
最初のステップは、インターセプターを定義することです
package com.lsl.mylsl.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
//在拦截的请求了添加属性,在对应请求的controller中的request中就可以获取该参数了
//比如String userName = (String)request.getAttribute("userName");
request.setAttribute("userName","lsl");
//获取cookie
Cookie[] cookies = request.getCookies();
//设置header属性
response.addHeader("SameSite","Lax");
//添加cookie
Cookie cookie = new Cookie("name","lsl");
response.addCookie(cookie);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
ステップ 2: インターセプターを構成する
package com.lsl.mylsl.interceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 拦截器配置类
*/
@Configuration
public class MyInterceptorConfig implements WebMvcConfigurer {
/**
* 配置拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(myInterceptor())
.addPathPatterns("/api/lsl/**")//需要拦截的请求
.addPathPatterns("/api/mjx/**")//需要拦截的请求
.excludePathPatterns("/api/debug/**")//不拦截的请求
.excludePathPatterns("api/lsl/getName");//不拦截的请求
}
/**
* 注入拦截器到spring容器
* @return
*/
@Bean
public MyInterceptor myInterceptor(){
return new MyInterceptor();
}
}
3. フィルターとインターセプターの違い
1. インターセプターは Java リフレクション メカニズムに基づいており、フィルターは関数コールバック (責任チェーン) に基づいています。
2. フィルターはサーブレット コンテナーに依存しますが、インターセプターはサーブレット コンテナーに依存しません。
3. インターセプターはアクション リクエストに対してのみ機能しますが、フィルターはほぼすべてのリクエストに対して機能します。
4.インターセプターはアクションコンテキストと値スタックのオブジェクトにアクセスできますが、フィルターはアクセスできません
5. アクションのライフサイクルでは、インターセプターは複数回呼び出すことができますが、フィルターはコンテナーの初期化時に 1 回しか呼び出すことができません。
6. インターセプターは IOC コンテナー内の各 Bean を取得できますが、フィルターは取得できません.これは非常に重要です.サービスをインターセプターに注入して、ビジネス ロジックを呼び出すことができます.
7.フィルターはサーブレットに属し、インターセプターはspringmvcに属します
8. フィルターは、静的リソースへのアクセス要求を含むすべての要求を傍受できます. インターセプターは、アクション要求、つまりコントローラーへのアクセス要求のみを傍受できます.
一般的な理解:
(1) フィルター (フィルター): たくさんのものがある場合、要件を満たす特定のものだけを選択したいとします。これらの要件を定義するためのツールがフィルターです。(理解: 文字の束から B を取ってください)
(2) インターセプター (Interceptor): プロセスが進行中の場合、そのプロセスに介入したり、プロセスを終了したりしたい. これがインターセプターの機能です。(理解: それは手紙の束であり、それに介入し、検証をあまり通過せず、途中で別のことを行います
フィルターとインターセプターの図