Programming/Web-Spring

[Spring] Annotation 커스텀 생성하기

아이바 2024. 7. 26. 11:17
@Aspect
@Component
@Slf4j
public class LogAspect {
    private final AccountRepo accountRepo;
    private final OperatorLogHistoryRepository operatorLogHistoryRepository;

    public LogAspect(AccountRepo accountRepo, OperatorLogHistoryRepository operatorLogHistoryRepository) {
        this.accountRepo = accountRepo;
        this.operatorLogHistoryRepository = operatorLogHistoryRepository;
    }

    @Pointcut("execution(* kr.co.concepters.operation.controller.*.*(..))" +
            "&& !@annotation(kr.co.concepters.operation.annotation.NoLogging)")
    private void pointCut() {
    }

    @Around("pointCut()")
    public Object onAfterHandler(ProceedingJoinPoint joinPoint) throws Throwable {
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        Object result = joinPoint.proceed();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) return result;

        Object tempUserDetail = authentication.getPrincipal();

        if (!(tempUserDetail instanceof UserDetails)) return result;

        UserDetails userDetails = (UserDetails) tempUserDetail;

        LocalDateTime connectionDate = LocalDateTime.now();
        String connectionDateTime = connectionDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"));

        Account account = accountRepo.findById(userDetails.getAccountIdx()).orElse(null);
        String ip = getClientIP(request);

        // 사설 아이피 체크.
        if (isPrivateNetwork(ip)) return result;

        String path = request.getServletPath();
        String method = request.getMethod();
        boolean isDownload = path.contains("download"); // download check.

        if (account != null) {
            log.info("{} [{}] {} ({}) [{} : {}]", connectionDateTime, ip, account.getIdentifier(), account.getName(), method, path);

            // 비밀번호 로그 제외 로직 추가.
            args = args.stream()
                    .filter(arg -> !(arg instanceof HttpServletResponse) && !(arg instanceof HttpServletRequest))
                    .map(arg -> {
                        if (arg instanceof Map) {
                            Map<Object, Object> temp = (Map) arg;

                            if (temp.containsKey("pw")) {
                                temp.remove("pw");
                            } else if (temp.containsKey("password")) {
                                temp.remove("password");
                            }

                            return temp;
                        } else {
                            try {
                                if (arg != null && arg.getClass().getMethod("toString").getDeclaringClass() == Object.class) {
                                    return "[Object] " + arg.getClass().getSimpleName();
                                } else {
                                    return arg;
                                }
                            } catch (NoSuchMethodException e) {
                                return arg;
                            }
                        }
                    }).collect(Collectors.toList());

            log.info("args {}", args);

            operatorLogHistoryRepository.save(OperatorLogHistory.builder()
                    .accountIdx(account.getIdx())
                    .ipAddress(ip)
                    .identifier(account.getIdentifier())
                    .name(account.getName())
                    .email(account.getEmail())
                    .phone(account.getPhone())
                    .isMaster(account.getIsMaster())
                    .isDownload(isDownload)
                    .method(method)
                    .path(path)
                    .arguments(args.toString())
                    .connectionDate(connectionDate)
                    .build());
        }

        return result;
    }

    private boolean isPrivateNetwork(String ip) throws UnknownHostException {
        InetAddress inetAddress = InetAddress.getByName(ip);
        return inetAddress.isSiteLocalAddress();
    }
}

 

해당부분에서 pointcut 메소드에서 !@annotation(kr.co.concepters.operation.annotation.NoLogging)" 부분이 있다. 

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NoLogging {
}

인터페이스 앞에 @를 붙여서 어노테이션을 커스텀 합니다.

 

@Target, @Retention은 어노테이션을 정의할 때 사용하는 메타 어노테이션입니다.

  • @Target은 어노테이션이 적용될 수 있는 대상을 지정합니다. 위의 예시에서는 메소드에만 적용할 수 있도록 ElementType.METHOD로 설정되어 있습니다.
  • @Retention은 어노테이션이 유지되는 기간을 지정합니다. 위의 예시에서는 런타임까지 유지되도록 RetentionPolicy.RUNTIME으로 설정되어 있습니다.

@NoLogging은 사용자가 직접 만든 어노테이션으로, 메소드에 적용되면 해당 메소드의 로그를 출력하지 않도록 하는 기능을 할 수 있습니다.

@NoLogging
@GetMapping({"/", ""})
public ResponseEntity<?> root(@RequestHeader(value = "X-Path", required = false) String xPath) {

 

해당 부분에 @NoLogging 을 선언함으로써, 로그 출력을 하지않도록 설정 가능

728x90