사용자 정의 어노테이션을 활용한 Profile 별 호출 가능 API 설정 - @LocalDevOnly
2024. 3. 14. 23:16ㆍSpring Boot
728x90
반응형
#1. 개요
- 각 API 에 대해 prod / dev / local 어디에서 호출할 수 있는 지에 대한 설정 추가를 위해 어노테이션 생성
- 기존 어노테이션으로는 각 API 가 아닌 Bean 단위로 Controller 속 API 전체에 대해 어느 서버에서 호출 할 수 있는 지 나타낼 수 있음
- @Profile({"local"})
- string[] 값 속에 어느 서버에서 해당 controller 속 API 들을 허용할 지 정하면 됨
- @ConditionalOnExpression("'${spring.profiles.active}'.equals('dev')")
- 위 같은 방법도 가능
- @Profile({"local"})
- 그러나 이 방법으로는 controller 내부 특정 API에 대해서 접근 제어를 할 수 없음.
- 그래서 @**LocalDevOnly** 어노테이션을 만들어서, 특정 API에 대한 접근 제어를 가능케 함
#2. 사용방법
1. 사용 설명
@PutMapping(value = "/item")
@Operation(summary = "메뉴 수정")
@LocalDevOnly
public ResponseEntity<JsonResponse> putMenu(
HttpServletRequest request,
// ... 중략 ...
@RequestBody @Valid MenuDto menuDto) {
// ... 중략 ...
return ResponseEntity.ok(response);
}
- controller 내부 API 선언 위쪽에 어노테이션 달아주면 끝
2. 결과
- 해당 API 가 호출되지 않는 서버에서 호출 되었을 경우 리턴 값.
#3. 구현
- 어노테이션 정의
- @Target
- 이 어노테이션이 적용될 수 있는 대상을 method 등을 지정할 수 있음\
- @Retention
- 이 어노테이션이 유지되는 기간 설정
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface LocalDevOnly { }
- @Target
- 핸들러 인터셉터 정의
- 정의된 어노테이션을 활용하여 어떤 기능을 실행할 지를 정하는 인터셉터 정의
- 인터셉터: http 요청이 들어올 때마다 먼저 실행 됨
- ${spring.profiles.active}
- spring 의 profile 값 프로퍼티 를 가져옴. 위 변수에는 현재 어플리케이션의 활성 profile 이 저장되어있음
- HandlerInterceptor
- 스프링 MVC 에서 컨트롤러의 요청처리 전후에 추가적인 처리를 수행할 수 있도록 해줌
- preHandle()
- 우선 LocalDevOnly 어노테이션을 사용했는 지 확인
- 어노테이션이 존재하면, Http 요청이 컨트롤러에 도달하기 전 실행되어서, profile 변수값이 조건에 맞지 않으면 NoHandlerFoundException을 던져 404 예외처리 핸들러 handle404에서 처리 될 수 있도록 한다.
@Component public class LocalDevOnlyInterceptor implements HandlerInterceptor { @Value("${spring.profiles.active}") private String profilesActive; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod)handler; Method method = handlerMethod.getMethod(); LocalDevOnly localDevOnly = method.getAnnotation(LocalDevOnly.class); if (localDevOnly != null) { if (!profilesActive.equals("local") && !profilesActive.contains("dev")) { HttpHeaders headers = new HttpHeaders(); headers.add("Content-Type", "application/json"); throw new NoHandlerFoundException(request.getMethod(), request.getRequestURL().toString(), headers); } } } return true; } }
- 정의된 어노테이션을 활용하여 어떤 기능을 실행할 지를 정하는 인터셉터 정의
- 인터셉터 등록
- WebMvcConfig 에서 정의한 인터셉터를 등록
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(localDevOnlyInterceptor); }
728x90
반응형
'Spring Boot' 카테고리의 다른 글
Java Spring - Cache 도입기 (2 / 2): Redis 적용기 (1) | 2024.03.14 |
---|---|
Java Spring - Cache 도입기 (1 / 2): 어떤 캐시를 쓸까? (0) | 2024.03.14 |
Java Spring 으로 백엔드 개발 시 지양해야할 코딩 패턴: (1) | 2024.03.14 |
네이버 코딩컨벤션 적용하기 - formatter / rules / suppressions .xml (2) | 2024.03.14 |
Node 에서 Java spring 로의 리팩토링 기록 ( NoSql 에서 Sql로) (0) | 2024.03.14 |