java - 实现 Spring 拦截器

标签 java spring spring-boot spring-data

我想实现 Spring 拦截器以便打印每个接收和发送的 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());
        }
    };
} 
}

记录组件:

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

}

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

最佳答案

根据您的代码,您在 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;
}

更多信息是 here .

该拦截器将服务于传出 请求。

对于income 请求,您必须从HandlerInterceptorAdapter 继承您的拦截器:

public class MyIncomeRequestInterceptor extends HandlerInterceptorAdapter {
    //...
}

然后用WebMvcConfigurer注册,例如:

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

更多信息是 here .

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

更新

一个工作示例:

@Slf4j
@RestController
@ControllerAdvice
@SpringBootApplication
public class Application implements WebMvcConfigurer, ResponseBodyAdvice<Object> {

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

    @GetMapping("/hello")
    public ResponseEntity<?> hello() {
        return ResponseEntity.ok(Map.of("message", "hello"));
    }

    @EventListener
    public void onReady(final ApplicationReadyEvent e) {
        Map result = restTemplate().getForObject("http://localhost:8080/hello", Map.class);
        if (result != null) {
            log.info("[i] Request result: '{}'", result.get("message"));
        }
    }

    @Bean
    public RestTemplate restTemplate() {

        ClientHttpRequestFactory factory = new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory());
        RestTemplate restTemplate = new RestTemplate(factory);

        var interceptors = restTemplate.getInterceptors();
        if (CollectionUtils.isEmpty(interceptors)) interceptors = new ArrayList<>();

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

    @Override
    public void addInterceptors(final InterceptorRegistry registry) {
        registry.addInterceptor(new IncomingInterceptor());
    }

    @Override
    public boolean supports(final MethodParameter returnType, final Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(final Object body, final MethodParameter returnType, final MediaType selectedContentType, final Class<? extends HttpMessageConverter<?>> selectedConverterType, final ServerHttpRequest request, final ServerHttpResponse response) {
        log.info("[i] ResponseBodyAdvice: response body {}", body);
        return body;
    }

    class OutgoingInterceptor implements ClientHttpRequestInterceptor {
        @Override
        public ClientHttpResponse intercept(final HttpRequest request, final byte[] bytes, final ClientHttpRequestExecution execution) throws IOException {
            log.info("[i] Outgoing interceptor: requested URL is '{}'", request.getURI());
            ClientHttpResponse response = execution.execute(request, bytes);
            String body = StreamUtils.copyToString(response.getBody(), Charset.defaultCharset());
            log.info("[i] Outgoing interceptor: response body is '{}'", body);
            return response;
        }
    }

    class IncomingInterceptor implements HandlerInterceptor {
        @Override
        public void postHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler, final ModelAndView mw) throws Exception {
            log.info("[i] Incoming interceptor: requested URL is '{}'", request.getRequestURL().toString());
        }
    }
}

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

结果:

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'

repo :sb-web-interceptors-demo

关于java - 实现 Spring 拦截器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53469186/

相关文章:

java - 当 in 包含括号和 OR 时,HQL 查询出错

java - Hibernate session 问题,新线程从 Grails Controller 启动

mysql - Spring Boot应用程序MySQL SocketTimeoutException

java - JUnit 5 - 使用 JUnit Jupiter 引擎时 IntelliJ IDEA 中的空测试套件

java - 安装hadoop并编写map reduce程序

java - 带有 EX、EEX、EXP 或 EE 科学记数法的字符串要加倍

spring - 如何为特定的@Test指定SpringClassRule/SpringMethodRule的行为?

java - SolrCrud存储库: use inheritance

spring-boot - @EnableSwagger - 无法在 Spring boot 中解析

Java 反直觉代码