안녕하세요 dev-길길IT입니다.
spring 개발을 하면서 수많은 controller를 만들고, request들에 대한 mapping을 하게 됩니다. 그럴 때 연계 관계가 복잡해진다면 debugging을 하기가 쉽지 않습니다. 그래서 편하게 사용하기 위해서 적절한 위치에 로그를 출력해주어야 하는데요. 그렇다고 모든 Controller에 일일이 다 logger.info나 logger.debug를 출력하기는 쉽지 않습니다.
그럴 때에는 spring interceptor를 이용해서 모든 요청을 일괄적으로 처리할 수 있는데요. 오늘은 이 기능을 소개해드리겠습니다.
interceptor를 이용한 mapping 요청 로그 출력
※ 목차
1. Spring Interceptor란? 동작 원리
2. Interceptor를 이용한 mapping 요청 로그 출력 설정
3. 결과
1. Spring Interceptor란? 동작 원리
Spring Interceptor란 "intercept, 낚아채다"라는 뜻에서 파생되었습니다. 보통 Spring MVC 구조에서는 사용자의 요청을 1차적으로 Dispatcher Servlet이 받게 되고, 이에 대한 적절한 request를 mapping하여 controller에게 전달해주고, controller에서 return된 페이지를 ViewResolver가 주게 됩니다.
이 때 Dispatcher Servlet과 Controller 사이에 자리하게 되는 것이 바로 Interceptor입니다. 그래서 Controller의 동작 전후, View페이지를 보여주고 난 후 그 사이에서 무언가 동작을 할 수 있게 되는 것입니다. 모든 Spring은 dispatcher serlvet을 다 거치게 되기에 이곳에 로직을 걸면 일괄적으로 로그 출력을 할 수 있습니다.
spring interceptor는 총 3가지의 메소드를 재정의해서 사용할 수 있습니다.
1) preHandle()
- Controller 호출되기 전 실행됩니다.
- 주로 요청 정보를 가공하는데 사용하고, 실행되어야 할 이후 handler들에 대한 정보를 인자값으로 받기 때문에 세부적으로 로그 출력 및 로직 구성이 가능합니다.
2) postHandle()
- Controller 호출 이후 View가 생성되기 전에 실행됩니다.
- 주로 보여주어야 할 페이지인 ModelAndView 타입의 정보를 받게 됩니다.
3) afterCompletion()
- View에서 최종 결과를 생성하는 작업 이후에 실행됩니다.
2. interceptor를 이용한 mapping 요청 로그 출력 설정
그럼 이제 spring interceptor를 이용해서 mapping 요청 로그 출력 설정을 진행해보겠습니다.
# RequestInterceptor.java
public class RequestInterceptor extends HandlerInterceptorAdapter {
private final Log logger = LogFactory.getLog(RequestInterceptor.class);
public static final String LOG_ID = "logId";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
String requestURI = request.getRequestURI();
String uuid = UUID.randomUUID().toString();
request.setAttribute(LOG_ID, uuid);
if (handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;//호출할 컨트롤러 메서드의 모든 정보가 포함되어 있다.
}
logger.debug("REQUEST uuid : [" + uuid + "] HTTP : ["+requestURI+"] Handler : ["+handler+"]");
return true;
}
}
먼저 interceptor의 preHandle을 이용하여 logger를 출력하는 클래스를 만들어주겠습니다. 이 때 HandlerInterceptorAdapter를 상속받아서 preHandle만 오버라이딩하여 재정의하고 사용하게 됩니다. 이 때 입력받는 값은 request와 handler이고, logger에 이 정보들을 출력하게끔 설정해주면 됩니다. 다른 메소드들은 사용하지 않겠습니다.
# root-servlet.xml
<bean id="requestInterceptor" class="com.demo.example.common.RequestInterceptor" />
<mvc:interceptor>
<mvc:mapping path="/*"/>
<ref bean="requestInterceptor"/>
</mvc:interceptor>
그 다음 servlet 설정에 가서 위에서 만든 interceptor를 bean으로 등록하고, mvc:interceptor 설정을 통해 등록해줍니다. 이 때 mvc:mapping path에 경로를 지정하면 특정한 부분에서만 해당 interceptor가 동작하도록 할 수 있는데요. 저는 "/"라고 등록해서 모든 경로에 이 interceptor가 동작되도록 설정해주었습니다.
# log4j.xml
<Logger name="com.demo.example.common.RequestInterceptorr" level="debug" additivity="false">
<AppenderRef ref="console" />
</Logger>
마지막으로 log4j 설정을 해줍니다. 위에서 구성한 requestInterceptor안에 logger를 구성했는데요. 이 logger를 log4j 설정에서 appender를 추가하여 콘솔에 출력해주도록 합니다. 이제 설정은 완료되었습니다.
3. 결과
테스트를 해보면 이런식으로 정상 동작되는 것을 확인하실 수 있습니다. spring interceptor가 request 요청을 가로채서 mapping url과 이후 호출해야 될 handler들을 보여줍니다.
마무리
오늘은 interceptor를 이용한 mapping 요청 로그 출력을 해보았습니다. spring 버전이나 환경 구성 방식에 따라 설정이 차이가 있을 수는 있지만 큰 동작은 비슷합니다. 그래서 이렇게 일괄적으로 처리를 함으로써 더 효율적으로 로깅을 하고 디버깅을 하실 수 있기를 바랍니다.
도움이 되시기를 바라며, 오늘도 읽어주셔서 감사합니다.
'Dev > Java' 카테고리의 다른 글
[Spring] log4j 적용 쿼리 및 로그 출력, 정렬하는 방법 (0) | 2024.07.31 |
---|---|
[Spring Boot] Thymeleaf 뷰 레이아웃 설정 및 사용하는 방법 (0) | 2024.07.26 |
[Spring] Tiles 적용하는 법과 사용하는 방법 (10) | 2024.07.24 |
IntelliJ, Maven, createprocess error=206 파일 이름이나 확장명이 너무 깁니다. 오류 해결 방법 (0) | 2023.03.23 |
[Spring Project 셋팅] 2. Spring Project의 구조와 흐름 (1) | 2022.09.01 |
댓글