Chef.Yeon
Code Cook
Chef.Yeon
전체 방문자
오늘
어제
  • 분류 전체보기 (230)
    • 게임 개발 (1)
      • Unity (1)
    • Android (27)
      • Kotlin (19)
      • 우아한테크코스 5기 (4)
    • Language (11)
      • 파이썬 (3)
      • Java (7)
    • DB (2)
      • SQL (16)
    • Spring (25)
    • 코딩테스트 (56)
    • Git (1)
    • TIL (85)
    • DevOps (6)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • rsocket
  • 코틀린 인 액션
  • 코딩테스트
  • 레포지토리
  • MariaDB
  • spring
  • grafana
  • 파이썬
  • Wil
  • enum
  • 프로그래머스
  • 내림차순
  • 코틀린
  • webflux
  • 문자열
  • 에라토스테네스의 체
  • elasticsearch
  • java
  • 백준
  • Docker
  • 다이나믹 프로그래밍
  • til
  • ec2
  • kibana
  • Android
  • kotlin
  • 프리코스
  • SQL
  • 우아한테크코스
  • 안드로이드

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Chef.Yeon

Code Cook

[TIL - 20230506] 회원/비회원 전체 게시글 조회 처리
TIL

[TIL - 20230506] 회원/비회원 전체 게시글 조회 처리

2023. 5. 6. 10:24

 

💻문제점

현재 프로젝트에서는 비회원/회원 모두 전체 게시글을 조회할 수 있도록 되어있다. 게시글 조회 API 응답으로 회원이 해당 게시글을 좋아요 했는지 여부를 함께 넘겨주는데, 비회원이면 무조건 false이므로 좋아요 여부를 확인할 필요가 없었고, 회원이면 각 게시글 마다 좋아요를 했는지 여부에 따라 true/false를 넘겨주어야 했다.


📃시도

API의 요청 URL이 /anonymous 시작하는 비회원 조회 API를 만들어서 비회원이면 해당 API로 요청을 보내고, 좋아요 여부는 무조건 false를 넘겨주도록 했다.

 

AnonymousController

@RestController
@RequestMapping("anonymous")
@RequiredArgsConstructor
public class AnonymousController {

    private final AnonymousService anonymousService;

    @GetMapping("/post")
    public ResponseDto<List<PostResponseDto>> getPosts(Pageable pageable) {
        return anonymousService.getPosts(pageable); //@RequestParam: ?page=1&size=10&sort=id,DESC
    }

    @GetMapping("/post/{id}")
    public ResponseDto<PostResponseDto> getPost(@PathVariable Long id){
        return anonymousService.getPost(id);
    }
}

 

AnonymousService

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class AnonymousService {

    private final PostRepository postRepository;

    public ResponseDto<List<PostResponseDto>> getPosts(Pageable pageable) {
        List<PostResponseDto> postResponseDtos = postRepository.findAll(pageable).getContent().stream().map(PostResponseDto::new).collect(Collectors.toList());

        return ResponseDto.setSuccess("find all Post success", postResponseDtos);
    }

    public ResponseDto<PostResponseDto> getPost(Long id) {
        Post post = ValidateExistPost(id);
        PostResponseDto postResponseDto = new PostResponseDto(post);

        return ResponseDto.setSuccess("post create success", postResponseDto);
    }

    // ==== 유효성 검증 ====
    private Post ValidateExistPost(Long id) {
        return postRepository.findById(id).orElseThrow(
                () -> new IllegalArgumentException("게시글이 존재하지 않습니다.")
        );
    }
}

 

PostService

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class PostService {

    private final PostRepository postRepository;
    private final LikeRepository likeRepository;

    public ResponseDto<List<PostResponseDto>> getPosts(Pageable pageable, Member member) {
        List<Post> responseList = postRepository.findAll(pageable).getContent();
        List<PostResponseDto> postResponseDtoList = new ArrayList<>();

        for (Post post : responseList) {
            likeRepository.findByMemberIdAndPostId(member.getId(), post.getId()).ifPresent(like -> {
                PostResponseDto responseDto = new PostResponseDto(post);
                responseDto.setLikeStatus(true);
                postResponseDtoList.add(responseDto);
            });
        }

        return ResponseDto.setSuccess("find all Post success", postResponseDtoList);
    }

    public ResponseDto<PostResponseDto> getPost(Long id, Member member) {
        Post post = ValidateExistPost(id);
        PostResponseDto responseDto = new PostResponseDto(post);
        //게시글을 좋아요 했는가/안했는가 판단
        likeRepository.findByMemberIdAndPostId(member.getId(), post.getId()).ifPresent(like -> {
            responseDto.setLikeStatus(true);
        });

        return ResponseDto.setSuccess("post create success", responseDto);
    }
}

🔍해결

스프링 시큐리티를 사용할 수 있지 않을까 하며 찾아보았는데, 비회원인지 회원인지 판단할 수 있는 방법이 있다.

SecurityContextHolder는 security context에 접근할 수 있도록 도와준다. security context의 사용자 정보를 가져옴으로써 회원인지, 비회원인지 알 수 있다. getAuthentication() 을 사용하면 인증되지 않은 사용자일 경우 Authentication 인터페이스의 구현체가 AnonymousAuthenticationToken 클래스이고, 사용자일 경우에는 UsernamePasswordAuthenticationToken 클래스이다.

 

구현체가 null이거나 AnonymousAuthenticationToken.class 이면 false를 반환하도록 하여 그에 맞는 PostService의 메서드를 수행하도록 하였다.

 

PostController

@RestController
@RequiredArgsConstructor
public class PostController {

    private final PostService postService;

    @GetMapping("/board")
    public ResponseDto<List<PostResponseDto>> getPosts(Pageable pageable) {
        if (!isAuthenticated()) {
            return postService.getAllPostByAnonymous(pageable);
        }
        return postService.getAllPostByMember(pageable);
    }

    @GetMapping("/board/{id}")
    public ResponseDto<PostResponseDto> getPost(@PathVariable Long id){
        if (!isAuthenticated()) {
            return postService.getPostByAnonmous(id);
        }
        return postService.getPostByMember(id);
    }

    //로그인 여부 확인
    private boolean isAuthenticated() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || AnonymousAuthenticationToken.class.
                isAssignableFrom(authentication.getClass())) {
            return false;
        }
        return authentication.isAuthenticated();
    }
}

 

PostService


    public ResponseDto<List<PostResponseDto>> getAllPostByMember(Pageable pageable) {
        Member member = getMember();

        List<Post> responseList = postRepository.findAll(pageable).getContent();
        List<PostResponseDto> postResponseDtoList = new ArrayList<>();

        for (Post post: responseList) {
            PostResponseDto postResponseDto = new PostResponseDto(post);
            if (likeRepository.findByMemberIdAndPostId(member.getId(), post.getId()).isEmpty()) {
                postResponseDto.setLikeStatus(true);
            }
            postResponseDtoList.add(postResponseDto);
        }

        return ResponseDto.setSuccess("member: find all Post success", postResponseDtoList);
    }

	//비회원
    public ResponseDto<List<PostResponseDto>> getAllPostByAnonymous(Pageable pageable) {
        List<PostResponseDto> postResponseDtos = postRepository.findAll(pageable).getContent().stream().map(PostResponseDto::new).collect(Collectors.toList());

        return ResponseDto.setSuccess("anonymous: find all Post success", postResponseDtos);
    }

    public ResponseDto<PostResponseDto> getPostByMember(Long id) {
        Member member = getMember();
        Post post = ValidateExistPost(id);
        PostResponseDto responseDto = new PostResponseDto(post);

        //좋아요 여부 판단
        likeRepository.findByMemberIdAndPostId(member.getId(), post.getId()).ifPresent(like -> {
            responseDto.setLikeStatus(true);
        });

        return ResponseDto.setSuccess("member: post create success", responseDto);
    }


	//비회원
    public ResponseDto<PostResponseDto> getPostByAnonmous(Long id) {
        Post post = ValidateExistPost(id);
        PostResponseDto postResponseDto = new PostResponseDto(post);

        return ResponseDto.setSuccess("anonymous: post create success", postResponseDto);
    }

 

728x90

'TIL' 카테고리의 다른 글

[TIL - 20230513] 게시글 수정(썸네일 변경 포함)을 위한 MutipartFile과 Dto 함께 받기  (0) 2023.05.14
[TIL - 20230510] Service 유효성 검사 메서드 분리  (0) 2023.05.11
[TIL - 202030504] WebSocket+Stomp 채팅방에 직접 참여하지 않은 사용자 구독시키기2 + 자잘한 문제점 해결  (0) 2023.05.04
[TIL - 20230503] WebSocket+Stomp 채팅방에 직접 참여하지 않은 사용자 구독시키기1  (0) 2023.05.04
[TIL - 20230501] 채팅 시스템 프론트와 연결  (0) 2023.05.02
    'TIL' 카테고리의 다른 글
    • [TIL - 20230513] 게시글 수정(썸네일 변경 포함)을 위한 MutipartFile과 Dto 함께 받기
    • [TIL - 20230510] Service 유효성 검사 메서드 분리
    • [TIL - 202030504] WebSocket+Stomp 채팅방에 직접 참여하지 않은 사용자 구독시키기2 + 자잘한 문제점 해결
    • [TIL - 20230503] WebSocket+Stomp 채팅방에 직접 참여하지 않은 사용자 구독시키기1
    Chef.Yeon
    Chef.Yeon
    보기 좋고 깔끔한 코드를 요리하기 위해 노력하고 있습니다.

    티스토리툴바