我想实现Spring Interceptor以便打印每个接收到的并发送API XML请求。我尝试了以下测试代码:
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;
}
}
记录组件:
import React, { Component, Fragment } from "react";
import Form from "../components/Form";
import product from "./product.json";
class App extends Component {
constructor() {
super();
this.state = {
data: {}
};
}
onSubmit = (model) => {
console.log("Outer", model);
this.setState({
data: model
});
console.log("Form: ", this.state);
}
render() {
const fields = product.fields;
return (
<Fragment>
<div>Header</div>
<Form
model={fields}
onSubmit={(model) => {this.onSubmit(model);}}
/>
<div>Footer</div>
</Fragment>
);
}
}
export default App;
但是在调试模式下,没有任何内容打印到控制台中。知道我错了吗?可能该组件未注册,或者我缺少一些重要的配置?
答案 0 :(得分: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;
}
更多信息为here。
该拦截器将满足去向的请求。
对于收入请求,您必须从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());
}
}
}
要记录控制器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'
答案 1 :(得分:2)
将AOP面向方面的编程应用于日志记录,您可以执行以下操作:
记录方面:
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Enumeration;
@Aspect
@Component
public class LoggingAspect {
private static final String CONTROLLER_EXPRESION = "within(@org.springframework.stereotype.Controller *) && execution(* *.*(..))";
private static final Logger log = LoggerFactory.getLogger(LoggingAspect.class);
/**
* Before -> Any resource annotated with @Controller annotation and all method
* and function taking HttpServletRequest as first parameter.
*
* @param joinPoint
* @param request
*/
@Before(CONTROLLER_EXPRESION)
public void logBefore(JoinPoint joinPoint, HttpServletRequest request) {
log.debug("Entering in Method : {}", joinPoint.getSignature().getName());
log.debug("Class Name : {}", joinPoint.getSignature().getDeclaringTypeName());
log.debug("Arguments : {}", Arrays.toString(joinPoint.getArgs()));
log.debug("Target class : {}", joinPoint.getTarget().getClass().getName());
if (null != request) {
log.debug("Start Header Section of request ");
log.debug("Method Type : {}", request.getMethod());
Enumeration headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement().toString();
String headerValue = request.getHeader(headerName);
log.debug("Header Name: {} Header Value : {}", headerName, headerValue);
}
log.debug("Request Path info : {}", request.getServletPath());
log.debug("End Header Section of request ");
}
}
/**
* After -> All method within resource annotated with @Controller annotation.
*
* @param joinPoint
* @param result
*/
@AfterReturning(pointcut = CONTROLLER_EXPRESION, returning = "result")
public void logAfter(JoinPoint joinPoint, Object result) {
String returnValue = this.getValue(result);
log.debug("Method Return value : {}", returnValue);
}
/**
* After -> Any method within resource annotated with @Controller annotation and throws an exception ...Log it
* @param joinPoint
* @param exception
*/
@AfterThrowing(pointcut = CONTROLLER_EXPRESION, throwing = "exception")
public void logAfterThrowing(JoinPoint joinPoint, Throwable exception) {
log.error("An exception has been thrown in {} {}", joinPoint.getSignature().getName(), " ()");
log.error("Cause : {}", exception.getCause());
}
/**
* Around -> Any method within resource annotated with @Controller annotation.
* @param joinPoint
* @return
* @throws Throwable
*/
@Around(CONTROLLER_EXPRESION)
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
try {
String className = joinPoint.getSignature().getDeclaringTypeName();
String methodName = joinPoint.getSignature().getName();
Object result = joinPoint.proceed();
long elapsedTime = System.currentTimeMillis() - start;
log.debug("Method {}.{} () execution time : {} ms", className, methodName, elapsedTime);
return result;
} catch (IllegalArgumentException e) {
log.error("Illegal argument {} in {}()", Arrays.toString(joinPoint.getArgs()), joinPoint.getSignature().getName());
throw e;
}
}
private String getValue(Object result) {
String returnValue = null;
if (null != result) {
if (result.toString().endsWith("@" + Integer.toHexString(result.hashCode()))) {
returnValue = ReflectionToStringBuilder.toString(result);
} else {
returnValue = result.toString();
}
}
return returnValue;
}
}