最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot之攔截器與過濾器解讀

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

SpringBoot 攔截器 過濾器

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

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

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

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

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

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

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

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

下面是攔截器的例子:

攔截器定義:

實現(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è)務處理器處理請求之前被調用");
       //可以進行權限校驗,安全控制
        MyRequestWrapper requestWrapper = new MyRequestWrapper (request);
        // 讀取請求內容
        BufferedReader br = requestWrapper.getReader();
        String line = null;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        // 將json字符串轉換為json對象
        JSONObject body = JSONObject.parseObject(sb.toString());
        //業(yè)務處理
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("在業(yè)務處理器處理請求執(zhí)行完成后,生成視圖之前執(zhí)行");
        //可以對返回來的ModelAndView進行處理,這個時候還未渲染視圖
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("在DispatcherServlet完全處理完請求后被調用");
        //請求已經完成,頁面已經渲染,數(shù)據(jù)已經返回。這個時候可以做一些資源清理,或者記錄請求調用時間,做性能監(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中的信息,或者預設一些參數(shù)供后續(xù)流程使用。
  • 3.HandlerInterceptor的功能更強大也更基礎,可以在preHandle方法中就直接拒絕請求進入controller方法。

實現(xiàn)RequestInterceptor接口

此方式為微服務Feign調用的自定義攔截器,實現(xiàn)各個微服務之間的參數(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以后已經廢除,但仍可使用。

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

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);
}

此方式:一個容器內只能有一個WebMvcConfigurationSupport的實現(xiàn)類,也就是說不能有多個繼承類,否則只有一個生效,會造成未知的錯誤,如果想在已有實現(xiàn)類的基礎上(基礎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 {
        //這個方法將在請求處理之前進行調用。注意:如果該方法的返回值為false ,將視為當前請求結束,不僅自身的攔截器會失效,還會導致其他的攔截器也不再執(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è)務操作...");
            return true;
        }
    }

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

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

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

InputStream的read()方法內部有一個position,標志當前流被讀取到的位置,每讀取一次,該標志就會移動一次,如果讀到最后,read()返回-1,表示已經讀取完了,如果想要重新讀取,則需要調用reset()方法,position就會移動到上次調用mark的位置,mark默認是0,所有就能重頭再讀了。調用reset()方法的前提是已經重寫了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 {
	}
}

總結

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

相關文章

  • 詳解JAVA 原型模式

    詳解JAVA 原型模式

    這篇文章主要介紹了JAVA 原型模式的的相關資料,文中講解非常細致,實例幫助大家更好的理解和學習,感興趣的朋友可以了解下
    2020-06-06
  • JDK生成WebService客戶端代碼以及調用方式

    JDK生成WebService客戶端代碼以及調用方式

    WebService 是一種跨編程語言和跨操作系統(tǒng)平臺的遠程調用技術,下面這篇文章主要給大家介紹了關于JDK生成WebService客戶端代碼以及調用方式的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-08-08
  • java跳出for循環(huán)的三種常見方法

    java跳出for循環(huán)的三種常見方法

    這篇文章主要給大家介紹了關于java跳出for循環(huán)的三種常見方法,需要的朋友可以參考下
    2023-07-07
  • Java使用JDBC向MySQL數(shù)據(jù)庫批次插入10W條數(shù)據(jù)(測試效率)

    Java使用JDBC向MySQL數(shù)據(jù)庫批次插入10W條數(shù)據(jù)(測試效率)

    使用JDBC連接MySQL數(shù)據(jù)庫進行數(shù)據(jù)插入的時候,特別是大批量數(shù)據(jù)連續(xù)插入(100000),如何提高效率呢?今天小編通過本教程給大家介紹下
    2016-12-12
  • java背包問題動態(tài)規(guī)劃算法分析

    java背包問題動態(tài)規(guī)劃算法分析

    這篇文章主要介紹了java背包問題動態(tài)規(guī)劃算法分析,想了解算法的同學一定要看一下
    2021-04-04
  • Java中如何使用Redis GEO測算經緯度距離

    Java中如何使用Redis GEO測算經緯度距離

    GEO也是Redis中提供的一種數(shù)據(jù)類型,可以將其理解成ZSet有序集合類型,本文給大家介紹Java-使用Redis GEO測算經緯度距離,感興趣的朋友一起看看吧
    2023-11-11
  • logback-spring.xml配置詳解

    logback-spring.xml配置詳解

    這篇文章主要介紹了logback-spring.xml詳解,本文介紹了logback-spring.xml相關的知識與概念,結合實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • Spring Boot 如何將 Word 轉換為 PDF

    Spring Boot 如何將 Word 轉換為 PDF

    這篇文章主要介紹了Spring Boot將Word轉換為 PDF,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • 基于springboot實現(xiàn)文件上傳

    基于springboot實現(xiàn)文件上傳

    這篇文章主要為大家詳細介紹了基于springboot實現(xiàn)文件上傳,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • SpringBoot+MyBatis簡單數(shù)據(jù)訪問應用的實例代碼

    SpringBoot+MyBatis簡單數(shù)據(jù)訪問應用的實例代碼

    這篇文章主要介紹了SpringBoot+MyBatis簡單數(shù)據(jù)訪問應用的實例代碼,需要的朋友可以參考下
    2017-05-05

最新評論

兰考县| 林甸县| 扎鲁特旗| 淅川县| 房山区| 林口县| 灵山县| 项城市| 图们市| 永登县| 明光市| 荆州市| 科技| 霍林郭勒市| 台州市| 万年县| 元氏县| 连州市| 留坝县| 宁海县| 酉阳| 吉水县| 英山县| 渭南市| 灵山县| 锡林浩特市| 天全县| 双桥区| 德保县| 灵川县| 吴川市| 禹州市| 海林市| 丽江市| 遂平县| 望江县| 永吉县| 中阳县| 福州市| 玛多县| 龙南县|