GiYeong

Spring - 3 본문

CS/Spring

Spring - 3

gy2710 2022. 6. 4. 04:16

Filter와 Interceptor의 차이

Spring은 공통적으로 여러 작업을 처리함으로써 중복된 코드를 제거할 수 있도록 많은 기능들을 지원한다.

Filter

Filter는 J2EE 표준 스펙 기능으로 Dispatcher Servlet에 요청이 전달되기 전/후에 URL 패턴에 맞는 모든 요청에 대해 부가작업을 처리할 수 있는 기능을 제공한다.

Dispatcher Servlet은 프론트 컨트롤러이므로 Spring 컨테이너가 아닌 웹 컨테이너에 의해 관리된다. 즉, Filter는 Spring의 범위 밖에서 처리된다. 

Filter를 추가하기 위해서는 javax.servlet의 Filter 인터페이스를 구현해야 한다.

public interface Filter {

    public default void init(FilterConfig filterConfig) throws ServletException {}

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;

    public default void destroy() {}
}
  1. init : Filter 객체를 초기화하고 서비스에 추가하는 메서드(웹 컨테이너가 init 메서드를 호출하여 Filter 객체를 초기화한 이후, 요청들은 doFilter 메서드를 통해 처리된다.)
  2. doFilter : url-pattern에 맞는 모든 http 요청이 Dispatcher Servlet으로 전달되기 전에 웹 컨테이너에 의해 실행되는 메서드
  3. destroy : Filter 객체를 서비스에서 제거하고 사용하던 자원을 반환하는 메서드

Interceptor

Interceptor는 Filter와 다르게 Spring에서 제공하는 기술이다.

Dispatcher Servlet이 컨트롤러를 호출하기 전/후에 요청과 응답을 참조하거나 가공할 수 있는 기능을 제공한다.

Interceptor는 Spring 컨테이너 내에서 동작하므로, Filter를 커쳐 Dispatcher Servlet이 요청을 받은 이후에 동작한다.

Dispatcher Servlet은 Handler Mapping을 통해 적절한 컨트롤러를 찾도록 요청하는데, 그 결과로 실행 체인(HandlerExcutionChain)을 돌려준다. 이 실행 체인은 1개 이상의 Interceptor가 등록되어 있다면 순차적으로 Interceptor들을 거친 뒤, 컨트롤러가 실행되도록 한다.

Interceptor를 추가하기 위해서는 org.springframework.web.servlet의 HandlerInterceptor 인터페이스를 구현해야 한다.

public interface HandlerInterceptor {

    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
        
        return true;
    }

    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 {
    }
}
  1. preHandle : 컨트롤러가 호출되기 전에 실행되는 메서드(컨트롤러 이전에 처리해야 하는 전처리 작업이나 요청 정보 가공 또는 추가 작업에 사용)
  2. postHandle: 컨트롤러를 호출한 후에 실행되는 메서드(컨트롤러 이후에 처리해야하는 후처리 작업에 사용)
  3. afterCompletion : 모든 작업이 완료된 후에 실행되는 메서드(요청 처리 중, 사용한 자원을 반환할 때 사용)

차이점

  1. Filter는 Request와 Response를 다른 객체로 바꿀 수 있지만, Interceptor는 불가능하다.
  2. Filter는 Spring과 무관하게 전역적으로 처리해야 하는 작업들을 처리하는 용도이고, Interceptor는 클라이언트의 요청과 관련되어 전역적으로 처리해야 하는 작업들을 처리하는 용도이다.

 

CORS (Cross-Origin Resource Sharing Policy)

CORS는 한 출처에서 실행 중인 웹 어플리케이션이 다른 출처의 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다.

출처(Origin)이란, URL의 구성요소 중, Protocol과 Host, 포트 번호까지 모두 합친 것을 의미한다. 즉, 서버의 위치를 찾아가기 위해 필요한 가장 기본적인 부분이다.

Spring CORS 에러 해결 방법

1. CrossOrigin 어노테이션

컨트롤러에서 특정 메서드나 컨트롤러 상단부에 @CrossOrigin 어노테이션을 추가하는 방법이다.

쉽고 간단하지만 컨트롤러가 많아질수록 설정해야하는 어노테이션이 많아진다는 단점이 있다.

2. WebMvcConfigurer에서 설정

Spring Initializer를 이용하여 프로젝트를 생성하여 생긴 main 메서드에 Bean으로 Configurer를 추가하는 방법이다.

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

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**").allowedOrigins("http://front-server.com");
            }
        };
    }
}

3. CorsFilter 생성

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods","*");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers",
                "Origin, X-Requested-With, Content-Type, Accept, Authorization");

        if("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        }
        else {
            chain.doFilter(req, res);
        }
    }

    @Override
    public void destroy() {
    }
}

Bean/Conponent 어노테이션

@Bean 어노테이션과 @Component 어노테이션 모두 Spring IoC 컨테이너에 Bean을 등록하는 어노테이션이지만 두 어노테이션의 용도는 다르다.

@Bean : 개발자가  제어할 수 없는 외부 라이브러리를 Bean으로 등록하기 위해 해당 라이브러리의 객체를 반환하는 메서드를 만들고, 이를 통해 반환되는 객체를 Bean으로 등록.

@Bean
public ObjectMapper objectMapper() {
	return new ObjectMapper();
}

@Bean
public RestTemplate restTemplate() {
	return new RestTemplate();
}

@Component : 개발자가 제어가 가능한 클래스(직접 작성한 클래스)를 Bean으로 등록

@Component
public class Account{
	public Account(){
    	System.out.println("my account");
    }
}

'CS > Spring' 카테고리의 다른 글

@Controller / @RestController  (0) 2022.09.04
Spring의 장점  (0) 2022.06.16
Spring - 2  (0) 2022.06.03
Spring - 1  (0) 2022.06.02
Comments