@Aspect로 공통header 처리

2024. 2. 19. 15:38·개발/java

http request body 에 다시 업무공통header와 payload가 있고,

업무공통 header 에서 txId나 응답시간, 메뉴 ID, 권한, 사용자 ID등등의 정보를 관리한다고 하자.

 

표준 메시지 포멧을 header 와 payload와 같이 고정한 경우, request의 업무공통header의 대부분의 정보는 응답 공통header에도 동일하게 세팅되고 응답시간 등 일부의 데이터만 바뀔 것이다.

 

RestController -> Service -> DAO 를 거쳐 다시 응답으로 나가기 까지 업무처리에 필요한 대부분의 정보는 payload에 있다고 하면

굳이 Service와 DAO에 header 정보까지 넘길 필요가 없을 것이다.

 

물론 권한 체크 등의 로직 수행이 필요한 경우 업무공통 header의 사용자ID나 기타 정보가 필요할 수도 있겠지만, 

그러한 정보는 threadLocal에 저장하고 불러오는 방식으로 처리하면 응답하는 방법으로 우회 가능하다.

 

그렇다고 RestController에서 다시 Response 에 header를 매번 다시 set 해주는것또한 비효율 적이다.

 

이러한 경우 @Aspect를 이용해 header handling을 해보자. 

 

request VO는 sampleVO, response VO 는 ResponseVO 이며 구조는 다음과 같다.

//HeaderVO.java
@Getter
@Setter
public class HeaderVO {
    @Schema(example = "abcdefg1234567")
    private String txId;

    private long txTime;
}

//PayloadVO.java
@Getter
@Setter
public class PayloadVO {
    @Schema(example = "Ligue1")
    private String league;
    @Schema(example = "PSG")
    private String team;
    @Schema(example = "Lee Gang-in")
    private String name;
    private int number;
    private int wage;

}

//BaseVO.java
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
public class BaseVO {
    private HeaderVO header;
}

//SampleVO.java
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
public class SampleVO extends BaseVO{

    private PayloadVO payload;
}

//ResponseVO
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
public class ResponseVO extends BaseVO{
    private PayloadVO payload;
}

 

SampleVO 와 ResponseVO는 private HeaderVO header를 선언한 BaseVO를 상속받았고,

각자 private PayloadVO payload 를 인자로 가지고 있다.

 

  • 목표: request 의 업무 공통 header를 response업무공통 header에 복제하는데, txTime을 세팅해 보자.

 

먼저 HeaderAspect component를 구성한다. 

(PostMapping에 대한 처리를 진행할 것이다.)

@Slf4j
@Aspect
@Component
public class HeaderAspect {

    @Around("@annotation(org.springframework.web.bind.annotation.PostMapping)")
    public Object aroundController(final ProceedingJoinPoint joinPoint) throws Throwable {
        final Object[] args = joinPoint.getArgs(); //request body
        Object returnValue = joinPoint.proceed();  //response 

        if (returnValue != null) {
            ResponseEntity<?> resEntity = (ResponseEntity<?>) returnValue;
            Object body = resEntity.getBody();

            BaseVO ansVO = null;

            // response header 설정
            if (!ObjectUtils.isEmpty(body) && body instanceof BaseVO) { 
                ansVO = (BaseVO)body;

                if(ansVO.getHeader() == null && !ObjectUtils.isEmpty(args)) { //응답 header가 null인 경우
                    for(Object arg : args) {
                        if(arg instanceof BaseVO) {
                            BaseVO ivo = (BaseVO)arg;

                            HeaderVO ivoHeader = ivo.getHeader(); //request body 의 header 
                            ansVO.setHeader(ivoHeader); // response body의 header에 set

                            break;
                        }
                    }
                }
            } else {
                log.warn("body is not instance of BaseVO");
            }

        }

        return returnValue;
    }
}

 

22 ~ 27라인에서 request의 header가 response로 복제된다.

 

테스트해보자. 

@RestController
@RequestMapping("/api/aspects")
public class AspectTestController {
    
    @PostMapping("/test-header-aspect")
    public ResponseEntity<ResponseVO> testHeaderAspect(@RequestBody SampleVO vo) {
        
        vo.getHeader().setTxTime(System.currentTimeMillis()); //request에 값을 세팅했다.

        return ResponseEntity.ok(new ResponseVO()); // new ResponseVO()를 했으므로, header정보는 null 이어야 한다.
    }
    

}

 

header aspect 설정이 없는 상태라면 응답 업무공통 header에는 null 이 들어가야한다.

그리고 new 로 헤더를 세팅 하더라도 txTime의 값은 null 이 나와야 한다. 

 

 

request에 넘긴 txId xxxx123123 뿐만 아니라, Controller에서 세팅한 txTime 값까지 함께 리턴되었다.

 

Git: https://github.com/FullMooney/tistory/tree/dev/aspect

 

728x90

'개발 > java' 카테고리의 다른 글

spring cloud task  (1) 2024.11.14
jasypt  (1) 2024.11.13
springboot threadLocal 테스트  (1) 2024.01.22
springboot resttemplate config 와 restClient 생성  (1) 2024.01.19
springboot rabbitmq config와 DLQ 예제  (0) 2024.01.18
'개발/java' 카테고리의 다른 글
  • spring cloud task
  • jasypt
  • springboot threadLocal 테스트
  • springboot resttemplate config 와 restClient 생성
yunapapa
yunapapa
working on the cloud
    250x250
  • yunapapa
    supermoon
    yunapapa
  • 전체
    오늘
    어제
    • 분류 전체보기 (94)
      • 개발 (20)
        • java (17)
        • web (2)
        • MSX (1)
        • Go (0)
      • CloudNative (50)
        • App Definition & Developeme.. (17)
        • Orchestration & Management (4)
        • Runtime (3)
        • Provisioning (7)
        • Observability & Analysis (14)
        • event review (5)
      • AWS (7)
      • 환경관련 (17)
      • 취미생활 (0)
        • 맛집 (0)
        • 게임 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • CNCF Past Events
    • Kubernetes Korea Group
  • 공지사항

  • 인기 글

  • 태그

    AWS
    k8s
    gitlab
    APM
    Java
    istio
    kubernetes
    티스토리챌린지
    springboot
    devops
    Pinpoint
    helm
    오블완
    dop-c02
    OpenShift
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
yunapapa
@Aspect로 공통header 처리
상단으로

티스토리툴바