实现Spring Interceptor

Pet*_*zov 5 java spring spring-data spring-boot

我想实现Spring Interceptor以打印每个接收和发送的API XML请求.我试过这个测试代码:

@SpringBootApplication
@EntityScan(".....")
public class Application extends SpringBootServletInitializer implements WebMvcConfigurer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();

    List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();

    // check if restTeamplate doesn't already have other interceptors
    if (CollectionUtils.isEmpty(interceptors)) { 
        interceptors = new ArrayList<>();
    }

    interceptors.add(new RestTemplateHeaderModifierInterceptor());
    restTemplate.setInterceptors(interceptors);
    return restTemplate;
}

@Bean
public WebMvcConfigurer webMvcConfigurer() {
    return new WebMvcConfigurer() {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new RestTemplateHeaderModifierInterceptor());
        }
    };
} 
}
Run Code Online (Sandbox Code Playgroud)

记录组件:

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.stereotype.Component;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.WebRequestInterceptor;
import org.springframework.web.servlet.HandlerInterceptor;

import io.micrometer.core.instrument.util.IOUtils;

@Component
public class RestTemplateHeaderModifierInterceptor implements ClientHttpRequestInterceptor, HandlerInterceptor {

    private static final Logger LOGGER = LoggerFactory.getLogger(HomeController.class);

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
            throws IOException {

        StringBuilder sb = new StringBuilder();
        sb.append("[ ");
        for (byte b : body) {
            sb.append(String.format("0x%02X ", b));
        }
        sb.append("]");

        LOGGER.debug("!!!!!!!!!!!!!!! Input " + sb.toString());

        System.out.println("!!!!!!!!!!!!!!!");

        ClientHttpResponse response = execution.execute(request, body);    
        InputStream inputStream = response.getBody();    
        String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8);

        LOGGER.debug("!!!!!!!!!!!!!!! result " + result);

        System.out.println("!!!!!!!!!!!!!!!");

        return response;
    }

}
Run Code Online (Sandbox Code Playgroud)

但是在DEBUG模式下没有任何内容打印到控制台中.知道我错了吗?可能这个组件没有注册,或者我错过了一些重要的配置?

Cep*_*pr0 3

根据您的代码,您在 RestTemplate 中注册了一个空的拦截器列表。尝试按如下方式更改您的代码:

@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();

    List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();

    // check if restTeamplate doesn't already have other interceptors
    if (CollectionUtils.isEmpty(interceptors)) { 
        interceptors = new ArrayList<>();
    }

    interceptors.add(new RestTemplateHeaderModifierInterceptor());
    restTemplate.setInterceptors(interceptors);
    return restTemplate;
}
Run Code Online (Sandbox Code Playgroud)

更多信息在这里

该拦截器将为传出服务请求提供服务。

对于收入请求,您必须从以下位置继承您的拦截器HandlerInterceptorAdapter

public class MyIncomeRequestInterceptor extends HandlerInterceptorAdapter {
    //...
}
Run Code Online (Sandbox Code Playgroud)

然后WebMvcConfigurer通过以下方式注册它,例如:

@Bean
public WebMvcConfigurer webMvcConfigurer() {
    return new WebMvcConfigurer() {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new MyIncomeRequestInterceptor());
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

更多信息请参见此处

在这两种情况下,都没有必要从拦截器中创建bean(您可以删除注释@Component)。

更新

一个工作示例:

@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();

    List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();

    // check if restTeamplate doesn't already have other interceptors
    if (CollectionUtils.isEmpty(interceptors)) { 
        interceptors = new ArrayList<>();
    }

    interceptors.add(new RestTemplateHeaderModifierInterceptor());
    restTemplate.setInterceptors(interceptors);
    return restTemplate;
}
Run Code Online (Sandbox Code Playgroud)

要记录控制器每种方法的响应主体(IMO),最好使用ResponseBodyAdvice带有注释的实现@ControllerAdvice(请参见上面的代码)。

结果:

2019-01-16 14:05:07.260  : [i] Outgoing interceptor: requested URL is 'http://localhost:8080/hello'
2019-01-16 14:05:07.366  : [i] ResponseBodyAdvice: response body {message=hello}
2019-01-16 14:05:07.383  : [i] Incoming interceptor: requested URL is 'http://localhost:8080/hello'
2019-01-16 14:05:07.387  : [i] Outgoing interceptor: response body is '{"message":"hello"}'
2019-01-16 14:05:07.402  : [i] Request result: 'hello'
Run Code Online (Sandbox Code Playgroud)

回购:sb-web-interceptors-demo