Spring MVC Configuration

ppparkta·2일 전
0

Spring

목록 보기
7/7

Spring MVC Configuration

WebMvcConfigurer을 통해 개발자가 쉽게 Mvc 설정을 커스텀할 수 있다

  • 뷰 컨트롤러 매핑
  • 인터셉터 추가
  • ArgumentResolver 추가에 대해 다룬다

View Controllers

호출 시 컨트롤러를 거치지 않고 즉시 view를 전달하는 ParameterizableViewController를 정의할 수 있다.

Java에서 처리하는 로직이 없는 단순 뷰 이름 매핑에만 사용 가능하다. 모델이나 로직이 없는 정적페이지/간단한 라우팅 용도로만 사용해야 한다.

  • ex) 정적 페이지, 홈화면 리다이렉트, 로그인 페이지 등 간단한 뷰 출력

addViewControllers 메서드를 사용하면 컨트롤러를 작성하지 않고도 뷰를 응답할 수 있다.

@Configuration
public class WebMvcConfiguration implements **WebMvcConfigurer** {

		// addViewControllers를 통해 로직 없는 단순 뷰 이름 매핑을 할 수 있다.
    @Override
   **** public void **addViewControllers(**ViewControllerRegistry registry) {
    
		    // 다음과 같이 addViewController를 통해 경로를 지정할 수 있다.
        registry.addViewController("/").setViewName("hello");
****    }
    ...
}

WebMvcConfigurer를 사용하는 방식과 직접 Controller 를 작성하는 방식 중 어떤 방식이 더 좋을까?


→ 당연히 모든 코드 상황마다 다르겠지만, 일반적으로 직접 Controller를 작성하는 방식이 더 좋을 것이다.

WebMvcConfigurer를 커스텀한다는 것은 스프링을 알고 있지만 해당 커스텀 옵션을 모르는 개발자에게 혼란을 줄 수 있다. (프로젝트에 신규 투입되는 사람이라면 놓칠 가능성이 높다고 봄)

따라서 한시적으로 사용하고, 일반적인 경우 @Controller 방식으로 구현하는 것을 지향하자.

View Controllers :: Spring Framework

Interceptor

Spring의 Interceptor는 HTTP 요청의 사전/사후 처리에 사용된다. 컨트롤러로 요청을 전달하기 전과 후에 특정 로직을 실행시킬 수 있다.

WebMvcConfigurer 가 제공하는 addInterceptor 메서드를 통해 특정 패턴에 대해 인터셉터가 동작하도록 설정할 수 있다.

다음의 인터페이스를 구현한 구현체를 인터셉터로 등록할 수 있다.

public interface HandlerInterceptor {

		// Handler 작업 전에 호출된다.
		// 반환값 true면 Handler 정상 실행, false면 Handler 미실행
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

		// Handler 작업 이후에 호출된다. (콜백)
		// ResponseBody/Entity 사용 시 응답은 이미 HandlerAdaptor에 작성되고 커밋되므로 여기서 응답을 수정할 수 없다.
    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

		// 전체 요청이 완료된 이후에 호출된다. (콜백)
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

아무튼 Interceptor는 아래와 같이 사용 가능하다. 마찬가지로 WebMvcConfigurer 내부에서 addInterceptors() 메서드에 인터셉터를 추가할 수 있다.

addPathPatterns() 이용해서 특정 요청으로 매핑할 수도 있다. (매핑하지 않으면 전체 요청에 대해 Interceptor가 동작하는 것 같다. 잘 되던 이전 테스트가 먹혔다)

excludePathPatterns() 사용하면 제외할 패턴도 지정 가능하다

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
    ..
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CheckLoginInterceptor())
                .addPathPatterns("/admin/**");
    }
}
public class CheckLoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String accessToken = request.getHeader("Authorization");
        if (accessToken == null) {
            throw new AuthorizationException();
        }

        return true;
    }
}

패턴 문법 정리 (Spring의 Ant-style path pattern)

패턴설명
/admin/*/admin/ 하위의 한 단계 경로에만 매칭. 예: /admin/user, X: /admin/user/edit
/admin/**/admin/ 하위의 모든 경로에 매칭. 예: /admin, /admin/user, /admin/user/edit
/**모든 요청 경로에 매칭
/static/**.css/static/ 하위의 .css 파일들
/*.html루트 경로의 .html 파일들. 예: /index.html, X: /pages/index.html

Filter와의 차이

항목FilterHandlerInterceptor
위치ServletContainer 수준Spring MVC DispatcherServlet 내부
대상모든 요청 (정적 리소스 포함)Spring MVC에서 처리되는 요청만
사용 목적보안, 로깅 등 아주 전역적인 기능컨트롤러 전/후 공통 처리 로직
API 수준Servlet 표준Spring 전용

스프링이라는 프레임워크가 HandlerInterceptor 라는 인터페이스를 제공하고, 이런 행위를 지원하는 이유는 무엇일까?
→ 관심사 분리, 확장성

*공식 문서에서 공통적으로 말하는 것은, Interceptor는 보안 수단이 아니므로 보안 목적으로 사용하는 경우 Spring Security를 사용하는 것이 좋다.

  • Spring Framework - Interception 모든 HandlerMapping 구현체는 요청 전반에 공통 기능을 적용할 수 있도록 핸들러 인터셉터(handler interceptor) 를 지원합니다. HandlerInterceptor는 다음과 같은 콜백 메서드를 구현할 수 있습니다:
    • preHandle(..) – 실제 핸들러가 실행되기 직전에 호출되는 콜백으로, boolean을 반환합니다. true를 반환하면 실행이 계속되고, false를 반환하면 실행 체인이 중단되며 핸들러는 호출되지 않습니다.
    • postHandle(..) – 핸들러 실행 이후에 호출되는 콜백입니다.
    • afterCompletion(..) – 요청 전체가 완료된 후에 호출되는 콜백입니다.

참고
@ResponseBodyResponseEntity를 사용하는 컨트롤러 메서드의 경우, 응답은 HandlerAdapter 내부에서 이미 작성되고 커밋되므로, postHandle이 호출될 시점에는 응답을 수정할 수 없습니다 (예: 헤더 추가 등).
이 경우에는 ResponseBodyAdvice를 구현하여 @ControllerAdvice로 등록하거나, RequestMappingHandlerAdapter에 직접 설정해야 합니다.

경고
인터셉터는 보안 계층으로는 이상적인 수단이 아닙니다.
그 이유는 애노테이션 기반 컨트롤러의 경로 매핑 방식과 인터셉터 매핑이 불일치할 수 있기 때문입니다.
보안을 위해서는 Spring Security를 사용하거나, Servlet 필터 체인에 통합된 보안 처리 방식을 사용하는 것이 바람직하며, 가능한 한 이른 시점에 적용해야 합니다.

EnableWebMvc와 WebMvcConfigurer 사용 시 주의
@EnableWebMvc 애노테이션이 붙은 @Configuration클래스를 사용할 수는 있지만, 이 경우 Spring MVC의 모든 설정을 직접 제어해야 하며, 모든 구성을 수동으로 커스터마이징해야 합니다.
또한 이 방식은 Spring Boot의 자동 설정(auto-configuration)충돌이 발생할 수 있어, 애플리케이션을 올바르게 설정하는 것이 더 어려워질 수 있습니다.

추가 자료

Be careful when using @Configuration classes with @EnableWebMvc in Spring Boot

(Spring)Filter와 Interceptor의 차이 : NHN Cloud Meetup

profile
겉촉속촉

0개의 댓글