首頁 > 軟體

spring boot使用攔截器修改請求URL域名 換 IP 存取的方法

2022-09-18 22:01:59

Interceptor 介紹

攔截器(Interceptor)同 Filter 過濾器一樣,它倆都是面向切面程式設計——AOP 的具體實現(AOP切面程式設計只是一種程式設計思想而已)。

你可以使用 Interceptor 來執行某些任務,例如在 Controller 處理請求之前編寫紀錄檔,新增或更新設定…

在 Spring中,當請求傳送到 Controller 時,在被Controller處理之前,它必須經過 Interceptors(0或多個)。

Spring Interceptor是一個非常類似於Servlet Filter 的概念 。

Interceptor 作用

紀錄檔記錄:記錄請求資訊的紀錄檔,以便進行資訊監控、資訊統計、計算 PV(Page View)等;
許可權檢查:如登入檢測,進入處理器檢測是否登入;
效能監控:通過攔截器在進入處理器之前記錄開始時間,在處理完後記錄結束時間,從而得到該請求的處理時間。(反向代理,如 Apache 也可以自動記錄)
通用行為:讀取 Cookie 得到使用者資訊並將使用者物件放入請求,從而方便後續流程使用,還有如提取 Locale、Theme 資訊等,只要是多個處理器都需要的即可使用攔截器實現。

自定義 Interceptor

如果你需要自定義 Interceptor 的話必須實現 org.springframework.web.servlet.HandlerInterceptor介面或繼承 org.springframework.web.servlet.handler.HandlerInterceptorAdapter類,並且需要重寫下面下面 3 個方法:

preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) 方法在請求處理之前被呼叫。該方法在 Interceptor 類中最先執行,用來進行一些前置初始化操作或是對當前請求做預處理,也可以進行一些判斷來決定請求是否要繼續進行下去。該方法的返回至是 Boolean 型別,當它返回 false 時,表示請求結束,後續的 Interceptor 和 Controller 都不會再執行;當它返回為 true 時會繼續呼叫下一個 Interceptor 的 preHandle 方法,如果已經是最後一個 Interceptor 的時候就會呼叫當前請求的 Controller 方法。
postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) 方法在當前請求處理完成之後,也就是 Controller 方法呼叫之後執行,但是它會在 DispatcherServlet 進行檢視返回渲染之前被呼叫,所以我們可以在這個方法中對 Controller 處理之後的 ModelAndView 物件進行操作。
afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法需要在當前對應的 Interceptor 類的 postHandler 方法返回值為 true 時才會執行。顧名思義,該方法將在整個請求結束之後,也就是在 DispatcherServlet 渲染了對應的檢視之後執行。此方法主要用來進行資源清理。

接下來結合實際程式碼進行學習。

案例1 :域名換IP存取

package com.config;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.support.HttpRequestWrapper;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import java.io.IOException;
import java.net.URI;
@Component
public class Interceptor implements ClientHttpRequestInterceptor {
    /**
     * Intercept the given request, and return a response. The given {@link ClientHttpRequestExecution} allows
     * the interceptor to pass on the request and response to the next entity in the chain.
     *
     * <p>A typical implementation of this method would follow the following pattern:
     * <ol>
     * <li>Examine the {@linkplain HttpRequest request} and body</li>
     * <li>Optionally {@linkplain HttpRequestWrapper wrap} the request to filter HTTP attributes.</li>
     * <li>Optionally modify the body of the request.</li>
     * <li><strong>Either</strong>
     * <ul>
     * <li>execute the request using {@link ClientHttpRequestExecution#execute(HttpRequest, byte[])},</li>
     * <strong>or</strong>
     * <li>do not execute the request to block the execution altogether.</li>
     * </ul>
     * <li>Optionally wrap the response to filter HTTP attributes.</li>
     * </ol>
     *
     * @param request   the request, containing method, URI, and headers
     * @param body      the body of the request
     * @param execution the request execution
     * @return the response
     * @throws IOException in case of I/O errors
     */
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        String str = request.getURI().toString();
        String str1 = str.replace("https://baidu.com", "http://39.156.66.10:8080");
        URI newUri = UriComponentsBuilder.fromUri(URI.create(str)).build().toUri();
         return execution.execute(new UriModifyHttpRequestWrapper(request, newUri), body);
    }
    private static class UriModifyHttpRequestWrapper extends HttpRequestWrapper {
        private final URI uri;
        public UriModifyHttpRequestWrapper(HttpRequest request, URI uri) {
            super(request);
            this.uri = uri;
        }
        @Override
        public URI getURI() {
            return uri;
        }
    }
}

案例2: erverWebExchange通過攔截器修改請求url

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
{
    ServerHttpRequest str = exchange.getRequest();
    //新url
    String newPath ="/system/loanOrg/list";
    ServerHttpRequest newRequest = str.mutate().path(newPath).build();
    exchange.getAttributes().put("path", newRequest.getURI());
    return chain.filter(exchange.mutate() .request(newRequest).build());
}

案例3: 將請求路徑中/idea都去掉

1.定義攔截器

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
@Component
public class GlobalInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpServletResponseWrapper httpResponse = new HttpServletResponseWrapper((HttpServletResponse) response);
        System.out.println(request.getRequestURI());
        String path=request.getRequestURI();
        if(path.indexOf("/idea")>-1){
            path = path.replaceAll("/idea","");
            request.getRequestDispatcher(path).forward(request,response);
        }
 
        return true;
    }
}

2.定義WebMvcConfig

import com.GlobalInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
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 WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    GlobalInterceptor globalInterceptor;
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(globalInterceptor).addPathPatterns("/idea/**");
    }
} 

案例4: SpringBoot 利用過濾器Filter修改請求url地址

要求:

程式碼中設定的url路徑為http://127.0.0.1/api/asso

現在要求http://127.0.0.1/asso 也可以同樣存取同一個conroller下面的method,並且要求引數全部跟隨

程式碼:

package com.framework.filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

/**
 * 修改請求路由,當進入url為/a/b時,將其url修改為/api/a/b
 *  
 **/
public class UrlFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest)request;
        HttpServletResponseWrapper httpResponse = new HttpServletResponseWrapper((HttpServletResponse) response);
        System.out.println(httpRequest.getRequestURI());
        String path=httpRequest.getRequestURI();
        if(path.indexOf("/api/")<0){
            path="/api"+path;
            System.out.println(path);
            httpRequest.getRequestDispatcher(path).forward(request,response);
        }
       else {
            chain.doFilter(request,response);

        }
        return;
    }
}


這個類必須繼承Filter類,這個是Servlet的規範。有了過濾器類以後,以前的web專案可以在web.xml中進行設定,但是spring boot專案並沒有web.xml這個檔案,那怎麼設定?在Spring boot中,我們需要FilterRegistrationBean來完成設定。

其實現過程如下:

package com.shitou.huishi.framework.filter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * Created by qhong on 2018/5/16 15:28
 **/
@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean registFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new UrlFilter());
        registration.addUrlPatterns("/*");
        registration.setName("UrlFilter");
        registration.setOrder(1);
        return registration;
    }
}

案例5.攔截器: WebMvcConfigurerAdapter攔截器

攔截所有請求

	@Configuration
	public class CustMvcConfigurerAdapter extends WebMvcConfigurerAdapter {
    @Autowired
    private CustInterceptor custInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(custInterceptor).addPathPatterns("/**");
    }
}
排除指定路徑

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(custInterceptor).addPathPatterns("/**").excludePathPatterns("/select/**");
    }

攔截指定路徑

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(custInterceptor).addPathPatterns("/user/**");
}

CustInterceptor具體攔截類

@Component
public class CustInterceptor extends HandlerInterceptorAdapter {
	   @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        boolean needLogin = needLogin(request);
        if (!needLogin) {
            return true;
        }
        boolean isLogin = checkLogin(request, response);
        return isLogin;
    }
}

結語

到此這篇關於spring boot使用攔截器修改請求URL域名 換 IP 存取的文章就介紹到這了,更多相關spring boot攔截器修改請求URL域名內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com