[Spring, JAVA] OncePerRequestFilter, ChronoUnit, Query문

Coodori·2023년 4월 12일
0

CherishU

목록 보기
23/29

여행을 다녀온 후

일본을 4박 5일 다녀온 이후 밀렸던 코드 PR을 확인했다.
그 코드 리뷰하면서 몰랐던 것이나 다르게 작성해야하는 코드 몇개를 발견하였다.

그래서 공부를 하면서 정리를 하려고 한다.

OncePerRequestFilter란?

흔히 FilterInterceptor 차이는 스프링을 공부한 사람이라면 알 듯하다.

기본적으로 흐름은

HTTP 요청 -> WAS -> Filter -> Servlet -> Interceptor -> Controller

로 진행이 된다.

여기서 ServletDispatcher Servlet을 포함한 모든 서블릿이다.

Interceptor은 Spring에서 제공하는 기능이기에 당연하게 Spring 시작인 Dispatcher Servlet 뒤에서 시작되는 것이다.

Filter 같은 경우 doFilter() 하나만 제공이 되지만 Interceptor는 호출전, 호출후, 요청완료 이후 까지 세분화 되어있다.(추가로 modelAndView 반환 응답 정보도 알 수 있다.)

하지만 FilterServlet 전에 진행이 되니 Spring 생태계에 포함되지 않는다.

그래서 Filter 를 조금 더 확장하여 스프링에서 제공하는 필터가 있는데 그것이 바로 GenericFilterBean이다.

GenericFilterBean

GenericFilterBean은 기존 Filter에서 얻어올 수 없는 정보였던 Spring의 설정 정보를 가져올 수 있게 확장된 추상 클래스이다.

당연하게 FilterServletContext를 상속받은 추상 클래스이다.

Filter와 GenericFilterBean

둘다 다 매 서블릿 마다 호출이 된다.

하나의 요청에 대해 해당 필터가 여러번 작동 될 수 있다는 것이다.

예를 들면 A(사용자 인증) -> 서블릿 -> B(추가 로그 로직 등) 이라고 했을 때 만약 다른 서블릿에 대한 새로운 요청을 하게 되면 이미 검증된 서블릿이지만 새롭게 생성된 요청이니 이니 다시 A -> 서블릿 -> B 를 수행한다.

OncePerRequestFilter

해당 필터는 이 동작을 제거해준다.
하나의 요청에 대해 정확히 한번 만 실행된다.
그래서 보안 인증으로 작업하는 동안 좋다고 한다.

그래서 해당을 이용한 대표적인 예는 Spring Security이다.
다른 요청 디스패처를 보내도 다시 해당 필터가 사용되지 않는 것이다.

당연하게도 GenericFilterBean 를 상속받는다.
스프링 설정 정보를 쓰면서 한번의 요청을 받고 싶은거니깐..

대충 해당 필터를 사용했는지 여부를 체크하고 request에 체크 값을 넣는 느낌이다.

ChronoUnit

보통 특정 날짜와 차이를 알고 싶은 날짜를 찾을때 쓰는 클래스다.
JAVA 8 에서 새롭게 등장했다.

사용 가능한 메소드로는

  • A.isAfter(B) => A가 B이후이면 True
  • .isBefore() => 이전이면 True
  • ChronoUnit.YEARS.between(temp,target) => 두개의 연도 차이를 구한다.(MONTHS, DAYS, HOURS 등)

Query code review

1번

개인적으로 직관적이며 내가 무엇을 찾고 싶은지 볼 수 있는 BooleanExpression을 좋아한다.

BooleanBuilder도 있지만 코드가 길어지면 내가 무엇을 찾고 싶은지 난해해지고 NULL일 경우를 고려해줄 수 없다.

그것에 관해서는 개인 취향이니 NPE만 안나게 하면되니깐 생략하고

리뷰한 부분을 살펴보겠다.

에서 이해가 되지 않는 코드가 있었다.

바로 categoryExpression = category.name.contains(categoryName).or(category.children.any().name.contains(categoryName));인데

현재 우리의 Category Entity 다.

보면 셀프 참조로 상위 카테고리와 하위 카테고리를 만들어줬다.

그렇다면 계층 관계를 논리적으로 만들어줬을 뿐이지
categoryExpression = category.name.contains(categoryName)
해당 코드에서 이미 Category name에 해당 키워드가 포함되어있는지 없는지 모두 확인되었다.

그래서 자식을 확인하는 것 자체가 의미가 없고 or 연산자도 의미가 없다.

이러한 부분이 몇군데가 더 있어서 리뷰를 했다.

2번 문제

jobChildren과 categoryChildren을 List로 받게 변경하였더니 여기저기를 refactor하고 있는데 ItemFilterRepositoryImpl에서 searchItem 부분 where절 이 두부분이 category.children.any().name.as("categoryChildren"), job.children.any().name.as("jobChildren") 계속 에러가 납니다 ! Expressions.List()로도 받아보고 Expressions.stringTemplate("GROUP_CONCAT({0})", category.children.any().name).as("categoryChildren") 이런식으로도 시도해봤으나 해결이 안되네요

해당 문제도 Job Entity가 자기 자신을 참조하여 부모 Job과 자식 Job이 있는 Entity 구조이다.

해결법


라고 해결법을 드렸다.

셀프 조인 같은 경우 별칭을 따로 지정하여 테이블을 구분해주는 것이 포인트였던 것같다.

물론 QTypestatic으로 구현된 것을 사용해도 되지만 별칭을 지정하여 생성 할 수도 있다.

결론

자기 자신을 참조하는 부분은 생소해서 이 부분에서 많은 난항이 있던 것 같고 새롭게 다시 보는 시간이였다.

REFERENCE

https://www.daleseo.com/java8-duration-period/
https://stackoverflow.com/questions/13152946/what-is-onceperrequestfilter
https://minkukjo.github.io/framework/2020/12/18/Spring-142/

profile
https://coodori.notion.site/0b6587977c104158be520995523b7640

0개의 댓글