💻문제점
현재 프로젝트에서는 비회원/회원 모두 전체 게시글을 조회할 수 있도록 되어있다. 게시글 조회 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);
}
'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 |