亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBoot之攔截器與過濾器解讀

 更新時間:2023年07月11日 10:36:41   作者:LZHH_2008  
這篇文章主要介紹了SpringBoot之攔截器與過濾器解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

SpringBoot 攔截器 過濾器

1、過濾器和攔截器觸發(fā)時機不一樣,過濾器是在請求進入容器后,但請求進入servlet之前進行預(yù)處理的。請求結(jié)束返回也是,是在servlet處理完后,返回給前端之前。

2、攔截器可以獲取IOC容器中的各個bean,而過濾器就不行,因為攔截器是spring提供并管理的,spring的功能可以被攔截器使用,在攔截器里注入一個service,可以調(diào)用業(yè)務(wù)邏輯。而過濾器是JavaEE標準,只需依賴servlet api ,不需要依賴spring。

3、過濾器的實現(xiàn)基于回調(diào)函數(shù)。而攔截器(代理模式)的實現(xiàn)基于反射

4、Filter是依賴于Servlet容器,屬于Servlet規(guī)范的一部分,而攔截器則是獨立存在的,可以在任何情況下使用。

5、Filter的執(zhí)行由Servlet容器回調(diào)完成,而攔截器通常通過動態(tài)代理(反射)的方式來執(zhí)行。

6、Filter的生命周期由Servlet容器管理,而攔截器則可以通過IoC容器來管理,因此可以通過注入等方式來獲取其他Bean的實例,因此使用會更方便。

過濾器和攔截器非常相似,但是它們有很大的區(qū)別最簡單明了的區(qū)別就是**過濾器可以修改request,而攔截器不能過濾器需要在servlet容器中實現(xiàn),攔截器可以適用于javaEE,javaSE等各種環(huán)境攔截器可以調(diào)用IOC容器中的各種依賴,而過濾器不能過濾器只能在請求的前后使用,而攔截器可以詳細到每個方法**區(qū)別很多,大家可以去查下

總的來說過濾器就是篩選出你要的東西,比如requeset中你要的那部分攔截器在做安全方面用的比較多,比如 權(quán)限驗證

下面是攔截器的例子:

攔截器定義:

實現(xiàn)HandleInterceptor接口

自定義攔截器類實現(xiàn)HandleInterceptor接口,并使用@Component注解標注為一個組件。

@Component注解 是為了 注入spring其他組件方便, 如果沒有這個注解,自動注入為空

@Autowired   

UserService userService;

public class MySelfInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("在業(yè)務(wù)處理器處理請求之前被調(diào)用");
       //可以進行權(quán)限校驗,安全控制
        MyRequestWrapper requestWrapper = new MyRequestWrapper (request);
        // 讀取請求內(nèi)容
        BufferedReader br = requestWrapper.getReader();
        String line = null;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        // 將json字符串轉(zhuǎn)換為json對象
        JSONObject body = JSONObject.parseObject(sb.toString());
        //業(yè)務(wù)處理
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("在業(yè)務(wù)處理器處理請求執(zhí)行完成后,生成視圖之前執(zhí)行");
        //可以對返回來的ModelAndView進行處理,這個時候還未渲染視圖
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("在DispatcherServlet完全處理完請求后被調(diào)用");
        //請求已經(jīng)完成,頁面已經(jīng)渲染,數(shù)據(jù)已經(jīng)返回。這個時候可以做一些資源清理,或者記錄請求調(diào)用時間,做性能監(jiān)控
    }
}

繼承HandleInterceptorAdapter類

自定義攔截器類繼承HandleInterceptor接口的實現(xiàn)類HandleInterceptorAdapter來定義,并使用@Component注解標注為一個組件。

可以根據(jù)需要覆蓋一些方法

@Component
public class MyInterceptor extends HandlerInterceptorAdapter {
    public SingleLoginInterceptor() {
        super();
    }
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return super.preHandle(request, response, handler);
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        super.postHandle(request, response, handler, modelAndView);
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        super.afterCompletion(request, response, handler, ex);
    }
    @Override
    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        super.afterConcurrentHandlingStarted(request, response, handler);
    }
}

可以看到HandlerInterceptorAdapter類底層是實現(xiàn)了HandlerInterceptor接口,多了兩個方法,要比實現(xiàn)HandlerInterceptor接口的方式功能強大。

這兩個方法都是HandlerInterceptorAdapter類實現(xiàn)的org.springframework.web.servlet.AsyncHandlerInterceptor接口提供的,而AsyncHandlerInterceptor接口又繼承了HandlerInterceptor接口,所以HandlerInterceptorAdapter底層是實現(xiàn)類HandlerInterceptor接口。

自定義攔截器類實現(xiàn)WebRequestInterceptor接口,并使用@Component注解標注為一個組件。

@Component
public class MyInterceptor implements WebRequestInterceptor {
    @Override
    public void preHandle(WebRequest webRequest) throws Exception {
    }
    @Override
    public void postHandle(WebRequest webRequest, ModelMap modelMap) throws Exception {
    }
    @Override
    public void afterCompletion(WebRequest webRequest, Exception e) throws Exception {
    }
}

兩個實現(xiàn)接口方式的異同點 相同點 都可以實現(xiàn)controller層的攔截請求 不同點

  • 1.WebRequestInterceptor的入?yún)ebRequest是包裝了HttpServletRequest 和HttpServletResponse的,通過WebRequest獲取Request中的信息更簡便。
  • 2.WebRequestInterceptor的preHandle是沒有返回值的,說明該方法中的邏輯并不影響后續(xù)的方法執(zhí)行,所以這個接口實現(xiàn)就是為了獲取Request中的信息,或者預(yù)設(shè)一些參數(shù)供后續(xù)流程使用。
  • 3.HandlerInterceptor的功能更強大也更基礎(chǔ),可以在preHandle方法中就直接拒絕請求進入controller方法。

實現(xiàn)RequestInterceptor接口

此方式為微服務(wù)Feign調(diào)用的自定義攔截器,實現(xiàn)各個微服務(wù)之間的參數(shù)傳遞。

@Configuration
public class CenterinsRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
    }
}

攔截器的注冊

創(chuàng)建一個自定義類,繼承WebMvcConfigurerAdapter類重寫addInterceptors方法。

@Configuration
public class WebCofiguration extends WebMvcConfigurerAdapter {
     @Bean
	MyInterceptor getMyInterceptor (){
		return new MyInterceptor ();
	}
    public void addInterceptors(InterceptorRegistry registry) {
            // 將自己定義的攔截器注入進來進行攔截操作
        //registry.addInterceptor(new MySelfInterceptor ()) // 如果是new 出來的對象 會導致 攔截器中自動裝配為空
       registry.addInterceptor(getMyInterceptor ())
                .addPathPatterns("/**")
                .excludePathPatterns("/logout");
                //過濾器可以添加多個,這里的addPathPatterns的/**是對所有的請求都做攔截。
                //excludePathPatterns代表排除url的攔截路徑,即不攔截
    }
}

此類在SpringBoot2.0以后已經(jīng)廢除,但仍可使用。

推薦使用以下兩種方式來代替此方式。

1. 創(chuàng)建一個自定義類繼承WebMvcConfigurationSupport類,實現(xiàn)addInterceptors。

@Configuration
public class MyInterceptorConfig extends WebMvcConfigurationSupport {
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
        super.addInterceptors(registry);
    }
}

此方式會導致默認的靜態(tài)資源被攔截,這就需要我們手動將靜態(tài)資源放開。

除了重寫方法外還需要重寫addResourceHandlers方法來釋放靜態(tài)資源

@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
    super.addResourceHandlers(registry);
}

此方式:一個容器內(nèi)只能有一個WebMvcConfigurationSupport的實現(xiàn)類,也就是說不能有多個繼承類,否則只有一個生效,會造成未知的錯誤,如果想在已有實現(xiàn)類的基礎(chǔ)上(基礎(chǔ)jar包中存在webConfig)還想繼續(xù)添加攔截器,可以選擇繼承WebConfig,但是要super.addInterceptors,避免丟失注冊

原因:在WebMvcAutoConfiguration 中 WebMvcConfigurationSupport 是  @ConditionalOnMissingBean 原來SpringBoot做了這個限制,只有當WebMvcConfigurationSupport類不存在的時候才會生效WebMvc自動化配置

2. 實現(xiàn)WebMvcConfigurer接口

@Configuration
public class MyInterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 實現(xiàn)WebMvcConfigurer不會導致靜態(tài)資源被攔截
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
    }
}

另外可以寫個配置注解,根據(jù)注解攔截需要的方法

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogData {
}

在controller中需要攔截的方法上加上 @LogData

@LogData
public ResponseMessage getUserList(@RequestParam Long id) {
        return ResponseMessage.ok();
    }

可以在攔截器中

@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //這個方法將在請求處理之前進行調(diào)用。注意:如果該方法的返回值為false ,將視為當前請求結(jié)束,不僅自身的攔截器會失效,還會導致其他的攔截器也不再執(zhí)行。
        log.info("進入到攔截器中:preHandle() 方法");
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        LogData loginVerify = handlerMethod.getMethodAnnotation(LogData .class);
        if (loginVerify == null) {
            log.info("不需要對該路徑 進行攔截");
            return true;
        }else {
            log.info("對該路徑 進行攔截");
            log.info("業(yè)務(wù)操作...");
            return true;
        }
    }

攔截器中request請求被讀取一次后,controller獲取為空

繼承HandleInterceptorAdapter類  和 實現(xiàn)HandleInterceptor接口  實現(xiàn)WebRequestInterceptor接口  自定義類實現(xiàn)RequestInterceptor接口

HttpServletRequest的輸入流只能讀取一次的原因當我們調(diào)用getInputStream()方法獲取輸入流時得到的是一個InputStream對象,而實際類型是ServletInputStream,它繼承與InputStream。

InputStream的read()方法內(nèi)部有一個position,標志當前流被讀取到的位置,每讀取一次,該標志就會移動一次,如果讀到最后,read()返回-1,表示已經(jīng)讀取完了,如果想要重新讀取,則需要調(diào)用reset()方法,position就會移動到上次調(diào)用mark的位置,mark默認是0,所有就能重頭再讀了。調(diào)用reset()方法的前提是已經(jīng)重寫了reset()方法,當然能否reset也是有條件的,它取決于markSupported()方法是否返回true。

InputStream默認不實現(xiàn)reset(),并且markSupported()默認也是返回false

我們可以把流讀取出來后用容器存起來,后面就可以多次利用了。JavaEE提供了一個HttpServletRequestWrapper類,它是一個http請求包裝器,基于裝飾者模式實現(xiàn)類HttpServletRequest界面。

繼承HttpServletRequestWrapper,將請求體中的流copy一份,可以重寫getinputStream()和getReader()方法,或自定義方法供外部使用

 
import dm.jdbc.e.e;
import dm.jdbc.util.StreamUtil;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;
/**
  * 重寫 HttpServletRequestWrapper 
  * 
  */
@Slf4j
public class MyRequestWrapper extends HttpServletRequestWrapper {
	private byte[]  body; //用于保存讀取body中數(shù)據(jù)
    public MyRequestWrapper (HttpServletRequest request) throws IOException {    
        super(request);
        //讀取請求的數(shù)據(jù)保存到本類當中
        //body = StreamUtil.readBytes(request.getReader(), "UTF-8");
		StringBuilder stringBuilder = new StringBuilder();
		BufferedReader bufferedReader = null;
		InputStream inputStream = null;
		try{
			inputStream = request.getInputStream();
			if(inputStream != null){
				bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
				char[] charBuffer = new char[128];
				int bytesRead =-1;
				while((bytesRead = bufferedReader.read(charBuffer)) >0){
					stringBuilder.append(charBuffer,0, bytesRead);
				}
			}else{
				stringBuilder.append("");
			}
		}catch (Exception e){
		}finally {
			if(inputStream != null){
				inputStream.close();
			}
			if(bufferedReader != null){
				bufferedReader.close();
			}
		}
		body = stringBuilder.toString().getBytes();
    }
    //覆蓋(重寫)父類的方法
    @SuppressFBWarnings("DM_DEFAULT_ENCODING")
	@Override
    public BufferedReader getReader() throws IOException {    
        return new BufferedReader(new InputStreamReader(getInputStream()));    
    }    
    //覆蓋(重寫)父類的方法
    @Override    
    public ServletInputStream getInputStream() throws IOException {    
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
        return new ServletInputStream() {    
            @Override    
            public int read() throws IOException {    
                return bais.read();    
            }
			@Override
			public boolean isFinished() {
				// TODO Auto-generated method stub
				return false;
			}
			@Override
			public boolean isReady() {
				// TODO Auto-generated method stub
				return false;
			}
			@Override
			public void setReadListener(ReadListener arg0) {
				// TODO Auto-generated method stub
			} 
        };    
    }
    /**
     * 獲取body中的數(shù)據(jù)
     * @return
     */
	public byte[] getBody() {
		return body;
	}
	/**
	 * 把處理后的參數(shù)放到body里面
	 * @param body
	 */
	public void setBody(byte[] body) {
		this.body = body;
	}
}

定義過濾器

import lombok.extern.slf4j.Slf4j;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
 * 過濾器
 * 
 */
@Slf4j
@WebFilter(urlPatterns = "/*", filterName = "logSignDataFilter")
public class LogSignDataFilter implements Filter {
	@Override
	public void destroy() {
	}
	@Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
		ServletRequest requestWrapper = null;
		if(request instanceof HttpServletRequest){
			requestWrapper = new MyRequestWrapper ((HttpServletRequest) request);
		}
		if(requestWrapper == null){
			filterChain.doFilter(request, response);
		}else{
			filterChain.doFilter(requestWrapper, response);
		}
    }
	@Override
	public void init(FilterConfig config) throws ServletException {
	}
}

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot后端數(shù)據(jù)校驗實戰(zhàn)操作指南

    SpringBoot后端數(shù)據(jù)校驗實戰(zhàn)操作指南

    在項?開發(fā)中,對于前端提交的表單,后臺接?接收到表單數(shù)據(jù)后,為了保證程序的嚴謹性,通常后端會加?業(yè)務(wù)參數(shù)的合法校驗操作來避免程序的?技術(shù)性?bug,這篇文章主要給大家介紹了關(guān)于SpringBoot后端數(shù)據(jù)校驗的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • Java在web頁面上的編碼解碼處理及中文URL亂碼解決

    Java在web頁面上的編碼解碼處理及中文URL亂碼解決

    這篇文章主要介紹了Java在web頁面上的編碼解碼處理及中文URL亂碼解決,文中所介紹的兩種使用過濾器解決中文鏈接亂碼的方法非常有效,需要的朋友可以參考下
    2016-02-02
  • java實現(xiàn)短地址服務(wù)的方法(附代碼)

    java實現(xiàn)短地址服務(wù)的方法(附代碼)

    大多數(shù)情況下URL太長,字符多,不便于發(fā)布復制和存儲,本文就介紹了通過java實現(xiàn)短地址服務(wù),減少了許多使用太長URL帶來的不便,需要的朋友可以參考下
    2015-07-07
  • SpringCloud OpenFeign概述與使用

    SpringCloud OpenFeign概述與使用

    OpenFeign源于Netflix的Feign,是http通信的客戶端。屏蔽了網(wǎng)絡(luò)通信的細節(jié),直接面向接口的方式開發(fā),讓開發(fā)者感知不到網(wǎng)絡(luò)通信細節(jié)。所有遠程調(diào)用,都像調(diào)用本地方法一樣完成
    2023-01-01
  • 使用Java實現(xiàn)一個解析CURL腳本小工具

    使用Java實現(xiàn)一個解析CURL腳本小工具

    文章介紹了如何使用Java實現(xiàn)一個解析CURL腳本的工具,該工具可以將CURL腳本中的Header解析為KV Map結(jié)構(gòu),獲取URL路徑、請求類型,解析URL參數(shù)列表和Body請求體,感興趣的小伙伴跟著小編一起來看看吧
    2025-02-02
  • 關(guān)于java后端的詳解

    關(guān)于java后端的詳解

    在本篇文章里小編給各位分享的是關(guān)于java后端的知識點詳解,學習java的朋友們可以參考下。
    2019-08-08
  • spring boot如何添加攔截器

    spring boot如何添加攔截器

    本篇文章主要介紹了spring boot如何添加攔截器,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • Java后端服務(wù)間歇性響應(yīng)慢的問題排查與解決

    Java后端服務(wù)間歇性響應(yīng)慢的問題排查與解決

    之前在公司內(nèi)其它團隊找到幫忙排查的一個后端服務(wù)連接超時問題,問題的表現(xiàn)是服務(wù)部署到線上后出現(xiàn)間歇性請求響應(yīng)非常慢(大于10s),但是后端業(yè)務(wù)分析業(yè)務(wù)日志時卻沒有發(fā)現(xiàn)慢請求,所以本文給大家介紹了Java后端服務(wù)間歇性響應(yīng)慢的問題排查與解決,需要的朋友可以參考下
    2025-03-03
  • Java 實戰(zhàn)項目之誠途旅游系統(tǒng)的實現(xiàn)流程

    Java 實戰(zhàn)項目之誠途旅游系統(tǒng)的實現(xiàn)流程

    讀萬卷書不如行萬里路,只學書上的理論是遠遠不夠的,只有在實戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+SpringBoot+Vue+maven+Mysql實現(xiàn)一個精美的物流管理系統(tǒng),大家可以在過程中查缺補漏,提升水平
    2021-11-11
  • MyBatis 如何配置多個別名 typeAliasesPackage

    MyBatis 如何配置多個別名 typeAliasesPackage

    這篇文章主要介紹了MyBatis 如何配置多個別名 typeAliasesPackage,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01

最新評論