Spring Framework/Spring Boot

[Spring Boot] Filter 설정

장쫄깃 2022. 4. 15. 13:55
728x90


Interceptor에 대한 설명은 해당 글을 참고

링크 : https://jangjjolkit.tistory.com/6

 

[Spring Boot] Filter, Interceptor, AOP

들어가며 자바 웹 개발을 하다보면, 공통적으로 처리해야할 업무들이 많다. 예를들어 로그인, 권한, XSS, pc/mobile 등 사용자 agent 체크, 로그, 페이지 인코딩 변환 등이 있다. 공통업무에 관련된 코

jangjjolkit.tistory.com


1. @Component or @ServletComponentScan WebFilter


임베디드 WAS의 경우, 자동 설정에 의해서 Filter를 구현할 클래스에 @Component만 붙여줘도 필터가 등록된다.

@Component
public class SomeFilter implements Filter {
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// ... before filter
		chain.doFilter(request, response);
		// ... after filter
	}
}

 

characterEncodingFilter가 Ordered.HIGHEST_PRECEDENCE로 등록되기 때문에 해당값은 피해서 필터 순서를 지정해야 한다.
다른 필터도 마찬가지다.

chain.doFilter 이전에 작성한 코드들은 Request시에, 이후에 작성한 코드들은 Response시에 실행된다.

 

2개 이상 필터를 등록하는 경우 필터에 순서를 줘야한다면 @Order 또는 Ordered 인터페이스를 구현해야 한다.

@Component
@Order(1)
public class SomeFilter implements Filter {
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// ... before filter
		chain.doFilter(request, response);
		// ... after filter
	}
}

 

그런데 @Component로 필터를 등록하면 url패턴을 지정할 수 없기 때문에 모든 url 패턴에 매핑된다.

@WebFilter 어노테이션을 이용하여 특정 url패턴에 매핑되는 필터를 추가할 수 있다.

@Component
@Order(1)
@WebFilter(urlPatterns="/some/*")
public class SomeFilter implements Filter {
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// ... before filter
		chain.doFilter(request, response);
		// ... after filter
	}
}

이렇게 @Component로 스캔 후 필터로 등록 시 @WebFilter 어노테이션이 적용되지 않는다.

 

@ServletComponentScan 은 Spring Boot 내장 웹서버를 사용할 경우 서블릿 Component(@WebFilter, @WebServlet, @WebListener)를 스캔할 때 사용하는 어노테이션이다.

해당 어노테이션을 @SpringBootApplication이 붙어있는 메인클래스에 추가한다.

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

 

하지만 위 방식대로 진행할 경우 Filter가 두 번 실행되는 문제가 생길 수 있다. 이유는 이미 @Component로 Filter 클래스를 적용했는데 @ServletComponentScan 에서 @WebFilter 를 한번 더 스캔하기 때문이다.

때문에, @WebFilter 를 사용할 경우 @Component를 제거해주면 된다.

@Order(1)
@WebFilter(urlPatterns="/some/*")
public class SomeFilter implements Filter {
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// ... before filter
		chain.doFilter(request, response);
		// ... after filter
	}
}

필자는 api 암복호화 프로젝트를 진행할 때, 특정 url로 api 요청 시 필터 적용을 위해 해당 방법을 사용했다.

참고 : https://github.com/JangDaeHyeok/spring_api_server

 

2. FilterRegistrationBean


만약 조금 더 세밀한 제어나 Filter 클래스를 수정하지 못하는 경우 FilterRegistrationBean을 이용하여 필터를 등록할 수 있다. 위에서 정리한 방식과 다르게 config 클래스를 별도로 생성해야 하지만 @ServletComponentScan 어노테이션이나 필터 클래스에 적용한 어노테이션이 필요없다.

@Configuration
public class SomeFilterConfig {
	@Bean
	public void runSomeFilterRegistration() {
		someFilterRegistration();
	}
	
	private FilterRegistrationBean<SomeFilter> someFilterRegistration() {
		FilterRegistrationBean<SomeFilter> registration = new FilterRegistrationBean<Filter>();
		registration.setFilter(new SomeFilter());
		registration.addUrlPatterns("/some/*"); // url 패턴 설정
		registration.addInitParameter("param1", "param_value1"); // 파라미터 설정
		registration.setName("some-filter"); // 필터명 설정
		registration.setOrder(1); // 순서 설정

		return registration;
	}
}

 

필자는 프로젝트 진행 중 어떠한 라이브러리 클래스를 별도로 제공했기 때문에, 필터로 적용 시 해당 방법을 사용했다.

728x90