TIL&WIL

2023-07-28 TIL (Spring AOP)

blues_jun 2023. 7. 28. 20:58

오늘 공부한 내용

  • 내배캠 강의
  • 내배캠 플러스 주차 개인과제 (Spring AOP적용)
  • 프로그래머스 알고리즘 문풀

AOP적용

Spring AOP는 관점 지향 프로그래밍을 의미하는데 개념만 들었을 때에는 실제로 많이 와닿지가 않았다.

 

오늘 실습을 해보면서 조금 감을 잡은 것 같다.

AOP는 게시글, 댓글 수정/삭제시에 본인이 작성하지 않았으면은 예외를 던지는 곳에 적용했다.

작성한 코드는 다음과 같다.

 

@Aspect
@Component
@RequiredArgsConstructor
public class RoleCheckAop {
    private final BlogRepository blogRepository;
    private final CommentRepository commentRepository;

    @Pointcut("execution(* com.sparta.blog.service.BlogService.updateBlog(..))")
    private void updateBlog() {}

    @Pointcut("execution(* com.sparta.blog.service.BlogService.deleteBlog(..))")
    private void deleteBlog() {}

    @Pointcut("execution(* com.sparta.blog.service.CommentService.updateComment(..))")
    private void updateComment() {}

    @Pointcut("execution(* com.sparta.blog.service.CommentService.deleteComment(..))")
    private void deleteComment() {}

    @Around("updateBlog() || deleteBlog()")
    public Object blogRoleCheck(ProceedingJoinPoint joinPoint) throws Throwable {
        // 게시글 정보 받아오기
        Long blogId = (Long) joinPoint.getArgs()[0];
        Blog blog = blogRepository.findById(blogId).orElseThrow(() -> new NoExistBlogException("해당 게시글이 존재하지 않습니다."));

        // 로그인된 유저 정보 받아오기
        UserDetailsImpl userDetails = (UserDetailsImpl) joinPoint.getArgs()[1];
        User user = userDetails.getUser();

        if (!user.getRole().equals(UserRoleEnum.ADMIN) || blog.getAuthor().equals(user.getUsername())) {
            throw new NoPermissionException("본인이 작성한 게시글만 수정/삭제할 수 있습니다.");
        }

        return joinPoint.proceed();
    }

    @Around("updateComment() || deleteComment()")
    public Object commentRoleCheck(ProceedingJoinPoint joinPoint) throws Throwable {
        // 댓글 정보 받아오기
        Long blogId = (Long) joinPoint.getArgs()[0];
        Long commentId = (Long) joinPoint.getArgs()[1];
        Comment comment = commentRepository.findByIdAndBlogId(commentId, blogId);

        // 로그인된 유저 정보 받아오기
        UserDetailsImpl userDetails = (UserDetailsImpl) joinPoint.getArgs()[2];
        User user = userDetails.getUser();

        if(comment == null) throw new NoExistCommentException("해당 댓글이 존재하지 않습니다.");

        if (!(user.getRole().equals(UserRoleEnum.ADMIN) || comment.getUsername().equals(user.getUsername()))) {
            throw new NoPermissionException("자신이 등록한 댓글만 수정/삭제할 수 있습니다.");
        }

        return joinPoint.proceed();
    }
}

@Pointcut 으로 aop의 적용 위치를 정해주고, @Around를 이용하여 해당 메서드가 실행될 때 aop가 수행될 수 있도록 했다.

 

내부 코드는 ProceedingJoinPoint를 활용하여 해당 인자값(게시글, 댓글, 유저 정보 등)을 받아와서 활용했다.  

 

 

이렇게 적용하니 Service부분은 비즈니스 로직에 더욱 집중할 수 있고, 반복되는 코드들이 많이 사라져서 코드의 가독성이 더 좋아졌다고 느껴졌다.