12월 25일 월 TIL

장숭혁·2023년 12월 26일
0

TIL작성

목록 보기
38/60
@RestControllerAdvice
public class ExceptionController {

  @ExceptionHandler({SendFailedException.class})
  @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
  public MessageDto sendFail() {
    return new MessageDto("이메일 전송에 실패했습니다.");
  }

  @ExceptionHandler(NotFoundEntityException.class)
  @ResponseStatus(HttpStatus.NOT_FOUND)
  public MessageDto notFound(NotFoundEntityException ex) {
    String message = ex.getMessage();
    if (message == null) {
      message = "존재하지 않습니다.";
    }
    return new MessageDto(message);
  }

  @ExceptionHandler({AccessDeniedException.class})
  @ResponseStatus(HttpStatus.FORBIDDEN)
  public MessageDto notAllowed(AccessDeniedException ex) {
    return new MessageDto(ex.getMessage());
  }
}
  • @RestControllerAdvice 어노테이션
  1. 컨트롤러에서 발생하는 예외를 한 곳에서 관리하고 처리한다.
  2. sendFail(): SendFailedException이 발생하면 이 메서드가 호출된다. 메서드는 HTTP 상태 코드 500(Internal Server Error)와 함께 "이메일 전송에 실패했습니다."라는 메시지를 반환한다.
  3. notFound(): NotFoundEntityException이 발생하면 이 메서드가 호출된다. 메서드는 HTTP 상태 코드 404(Not Found)와 함께 "존재하지 않습니다."라는 메시지를 반환한다. 만약 예외에 메시지가 있으면 그 메시지를 반환한다.
  4. notAllowed(): AccessDeniedException이 발생하면 이 메서드가 호출된다. 이 메서드는 HTTP 상태 코드 403(Forbidden)와 함께 예외의 메시지를 반환한다.
  5. handleNotFoundException(): NotFoundException이 발생하면 이 메서드가 호출된다. 이 메서드는 HTTP 상태 코드 404(Not Found)와 함께 예외의 메시지를 반환한다.
  • 사용 방법
  1. 클래스가 선언된 패키지 혹은 그 하위 패키지에서 발생하는 예외들은 이 클래스에서 자동으로 잡히고 처리된다.

  2. 따라서 각각의 컨트롤러에서 별도로 예외 처리를 하지 않아도 된다. 이렇게 하면 예외 처리 로직이 중복되는 것을 방지하고, 코드의 가독성을 높일 수 있다.





    AOP

  • AOP는 흩어진 관심사를 한 곳에서 관리하도록 하는 프로그래밍 패러다임이다.

  • 로깅, 트랜잭션 관리, 보안 등과 같이 여러 곳에서 공통적으로 사용되는 코드를 분리하여 관리하는데 유용하게 사용된다.

    @Slf4j(topic = "UseTimeAop")
    @Aspect
    @Component
    @RequiredArgsConstructor
    public class UseTimeAop {
    
       private final ApiUseTimeRepository apiUseTimeRepository;
    
       @Pointcut("execution(* com.sparta.myselectshop.controller.ProductController.*(..))")
       private void product() {}
       @Pointcut("execution(* com.sparta.myselectshop.controller.FolderController.*(..))")
       private void folder() {}
       @Pointcut("execution(* com.sparta.myselectshop.naver.controller.NaverApiController.*(..))")
       private void naver() {}
    
       @Around("product() || folder() || naver()")
       public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
           // 측정 시작 시간
           long startTime = System.currentTimeMillis();
    
           try {
               // 핵심기능 수행
               Object output = joinPoint.proceed();
               return output;
           } finally {
               // 측정 종료 시간
               long endTime = System.currentTimeMillis();
               // 수행시간 = 종료 시간 - 시작 시간
               long runTime = endTime - startTime;
    
               // 로그인 회원이 없는 경우, 수행시간 기록하지 않음
               Authentication auth = SecurityContextHolder.getContext().getAuthentication();
               if (auth != null && auth.getPrincipal().getClass() == UserDetailsImpl.class) {
                   // 로그인 회원 정보
                   UserDetailsImpl userDetails = (UserDetailsImpl) auth.getPrincipal();
                   User loginUser = userDetails.getUser();
    
                   // API 사용시간 및 DB 에 기록
                   ApiUseTime apiUseTime = apiUseTimeRepository.findByUser(loginUser).orElse(null);
                   if (apiUseTime == null) {
                       // 로그인 회원의 기록이 없으면
                       apiUseTime = new ApiUseTime(loginUser, runTime);
                   } else {
                       // 로그인 회원의 기록이 이미 있으면
                       apiUseTime.addUseTime(runTime);
                   }
    
                   log.info("[API Use Time] Username: " + loginUser.getUsername() + ", Total Time: " + apiUseTime.getTotalTime() + " ms");
                   apiUseTimeRepository.save(apiUseTime);
               }
           }
       }
    }```
    
  • AOP(Aspect-Oriented Programming)를 사용하여 API의 실행 시간을 측정하고, 이를 데이터베이스에 저장하는 기능을 수행하는 것이다.

  • @Aspect: 해당 클래스가 AOP를 구현하는 클래스임을 명시하는 어노테이션이다.

  • @Component: 스프링이 관리하는 빈 클래스임을 명시하는 어노테이션이다.

  • @Pointcut: AOP의 대상이 되는 메소드를 지정하는 어노테이션이다. "execution( com.sparta.myselectshop.controller.ProductController.(..))"는 ProductController의 모든 메소드를 대상으로 한다.

  • @Around: @Pointcut으로 지정된 메소드를 실행하기 전후로 로직을 실행하도록 하는 어노테이션이다.

  • execute(ProceedingJoinPoint joinPoint): @Around 어노테이션에 의해 실행되는 메소드이다. joinPoint.proceed()를 호출하여 대상 메소드를 실행하고, 그 전후로 원하는 로직(여기서는 시간 측정 및 데이터베이스 저장)을 추가한다.

  • Authentication auth = SecurityContextHolder.getContext().getAuthentication();: 현재 접근하려는 사용자의 인증 정보를 가져온다.

  • if (auth != null && auth.getPrincipal().getClass() == UserDetailsImpl.class): 인증 정보가 존재하고, 인증된 사용자가 UserDetailsImpl 클래스의 인스턴스인 경우에만 로직을 수행한다.

  • ApiUseTime apiUseTime = apiUseTimeRepository.findByUser(loginUser).orElse(null);: 인증된 사용자의 API 사용 시간을 데이터베이스에서 찾습니다. 없다면 null을 반환한다.

profile
코딩 기록

0개의 댓글

관련 채용 정보