天天看點

spring boot使用攔截器修改請求URL域名 換 IP 通路

文章目錄

  • ​​Interceptor 介紹​​
  • ​​Interceptor 作用​​
  • ​​自定義 Interceptor​​
  • ​​案例1 :域名換IP通路​​
  • ​​案例2: erverWebExchange通過攔截器修改請求url​​
  • ​​案例3: 将請求路徑中/idea都去掉​​
  • ​​案例4: SpringBoot 利用過濾器Filter修改請求url位址​​
  • ​​案例5.攔截器: WebMvcConfigurerAdapter攔截器​​
  • ​​結語​​

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/**");
}      
@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;
    }
}      

結語