Skip to content

Commit

Permalink
♻️ refactor: 차단 기능 리팩토링 (#50)
Browse files Browse the repository at this point in the history
♻️ refactor: 차단 기능 리팩토링 (#50)
  • Loading branch information
yslle authored Aug 8, 2024
2 parents 8ac9ffd + d0db993 commit 49c316e
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.example.template.domain.block.dto.response.BlockResponseDTO;
import com.example.template.domain.block.service.BlockCommandService;
import com.example.template.domain.block.service.BlockQueryService;
import com.example.template.domain.member.entity.Member;
import com.example.template.global.annotation.AuthenticatedMember;
import com.example.template.global.apiPayload.ApiResponse;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
Expand All @@ -20,22 +22,24 @@ public class BlockController {

@PostMapping("/blocks/members/{targetMemberId}")
@Operation(summary = "차단하기 API", description = "차단할 멤버의 아이디를 전달해주세요.")
public ApiResponse<BlockResponseDTO.BlockDTO> createBlock(@PathVariable("targetMemberId") Long targetMemberId) {
BlockResponseDTO.BlockDTO blockDTO = blockCommandService.createBlock(targetMemberId);
public ApiResponse<BlockResponseDTO.BlockDTO> createBlock(@PathVariable("targetMemberId") Long targetMemberId, @AuthenticatedMember Member member) {
BlockResponseDTO.BlockDTO blockDTO = blockCommandService.createBlock(targetMemberId, member);
return ApiResponse.onSuccess(blockDTO);
}

@GetMapping("/blocks/members")
@Operation(summary = "차단 목록 조회 API", description = "멤버가 차단한 목록을 조회합니다. 차단 목록이 없으면 빈 배열을 반환합니다.")
public ApiResponse<List<BlockResponseDTO.BlockListDTO>> getBlockList() {
List<BlockResponseDTO.BlockListDTO> blockListDTO = blockQueryService.getBlockList();
public ApiResponse<BlockResponseDTO.BlockListDTO> getBlockList(@RequestParam(defaultValue = "0") Long cursor,
@RequestParam(defaultValue = "10") Integer limit,
@AuthenticatedMember Member member) {
BlockResponseDTO.BlockListDTO blockListDTO = blockQueryService.getBlockList(cursor, limit, member);
return ApiResponse.onSuccess(blockListDTO);
}

@DeleteMapping("/blocks/{blockId}")
@Operation(summary = "차단 해제 API")
public ApiResponse<Void> deleteBlock(@PathVariable("blockId") Long blockId) {
blockCommandService.deleteBlock(blockId);
public ApiResponse<Void> deleteBlock(@PathVariable("blockId") Long blockId, @AuthenticatedMember Member member) {
blockCommandService.deleteBlock(blockId, member);
return ApiResponse.onSuccess(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

public class BlockResponseDTO {

@Builder
Expand All @@ -16,12 +18,18 @@ public static class BlockDTO {
Long blockId;
Long memberId; // 멤버 아이디
Long targetMemberId; // 차단 대상 멤버 아이디
String name; // 차단 대상 멤버 이름
String email; // 차단 대상 멤버 이메일
String profileImg; // 차단 대상 멤버 프로필 이미지

public static BlockDTO from(Block block) {
return BlockDTO.builder()
.blockId(block.getId())
.memberId(block.getMember().getId())
.targetMemberId(block.getTargetMember().getId())
.name(block.getTargetMember().getName())
.email(block.getTargetMember().getEmail())
.profileImg(block.getTargetMember().getProfileImg())
.build();
}
}
Expand All @@ -31,17 +39,19 @@ public static BlockDTO from(Block block) {
@NoArgsConstructor
@AllArgsConstructor
public static class BlockListDTO {
Long blockId;
String name; // 차단 대상 멤버 이름
String email; // 차단 대상 멤버 이메일
String profileImg; // 차단 대상 멤버 프로필 이미지
private List<BlockDTO> blocks;
private Long nextCursor;
private boolean hasNext;

public static BlockListDTO of(List<Block> blocks, Long nextCursor, boolean hasNext) {
List<BlockDTO> blockDTOS = blocks.stream()
.map(BlockDTO::from)
.toList();

public static BlockListDTO from(Block block) {
return BlockListDTO.builder()
.blockId(block.getId())
.name(block.getTargetMember().getName())
.email(block.getTargetMember().getEmail())
.profileImg(block.getTargetMember().getProfileImg())
.blocks(blockDTOS)
.nextCursor(nextCursor)
.hasNext(hasNext)
.build();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ public enum BlockErrorCode implements BaseErrorCode {

// Block ERROR 응답
BLOCK_NOT_FOUND(HttpStatus.NOT_FOUND,
"BLOCK400", "차단 내역을 찾을 수 없습니다."),
"BLOCK404", "차단 내역을 찾을 수 없습니다."),
ACCESS_DENIED(HttpStatus.FORBIDDEN,
"BLOCK401", "권한이 없습니다."),
BLOCK_SELF_BLOCK(HttpStatus.FORBIDDEN,
"BLOCK402", "자기 자신은 차단할 수 없습니다."),
"BLOCK403_1", "권한이 없습니다."),
SELF_BLOCK_NOT_ALLOWED(HttpStatus.FORBIDDEN,
"BLOCK403_2", "자기 자신은 차단할 수 없습니다."),
BLOCK_ALREADY_EXISTS(HttpStatus.BAD_REQUEST,
"BLOCK403", "이미 차단된 사용자입니다.");
"BLOCK400", "이미 차단된 사용자입니다.");

private final HttpStatus httpStatus;
private final String code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,21 @@

import com.example.template.domain.block.entity.Block;
import com.example.template.domain.member.entity.Member;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface BlockRepository extends JpaRepository<Block, Long> {
List<Block> findByMember(Member member);

boolean existsByMemberAndTargetMember(Member member, Member targetMember);

@Query("SELECT b FROM Block b WHERE b.id < :cursor AND b.member = :member ORDER BY b.id DESC")
List<Block> findByMemberWithCursor(@Param("cursor") Long cursor, @Param("member") Member member, Pageable pageable);

default List<Block> findByMemberWithCursor(Long cursor, Integer limit, Member member) {
return findByMemberWithCursor(cursor, member, PageRequest.of(0, limit));
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package com.example.template.domain.block.service;

import com.example.template.domain.block.dto.response.BlockResponseDTO;
import com.example.template.domain.member.entity.Member;

public interface BlockCommandService {
BlockResponseDTO.BlockDTO createBlock(Long targetMemberId);
BlockResponseDTO.BlockDTO createBlock(Long targetMemberId, Member member);

void deleteBlock(Long blockId);
void deleteBlock(Long blockId, Member member);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import com.example.template.domain.block.exception.BlockException;
import com.example.template.domain.block.repository.BlockRepository;
import com.example.template.domain.member.entity.Member;
import com.example.template.domain.member.exception.MemberErrorCode;
import com.example.template.domain.member.exception.MemberException;
import com.example.template.domain.member.repository.MemberRepository;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
Expand All @@ -22,16 +24,13 @@ public class BlockCommandServiceImpl implements BlockCommandService {
private final BlockRepository blockRepository;

@Override
public BlockResponseDTO.BlockDTO createBlock(Long targetMemberId) {
// TODO 현재 로그인한 멤버 정보 받아오기, 멤버 예외 처리로 변경
Member member = memberRepository.findById(1L)
.orElseThrow(() -> new EntityNotFoundException("Sender not found"));
public BlockResponseDTO.BlockDTO createBlock(Long targetMemberId, Member member) {
Member targetMember = memberRepository.findById(targetMemberId)
.orElseThrow(() -> new EntityNotFoundException("Sender not found"));
.orElseThrow(() -> new MemberException(MemberErrorCode.MEMBER_NOT_FOUND));

// 자기 자신을 차단하는지 확인
if (member.equals(targetMember)) {
throw new BlockException(BlockErrorCode.BLOCK_SELF_BLOCK);
throw new BlockException(BlockErrorCode.SELF_BLOCK_NOT_ALLOWED);
}

// 이미 차단된 사용자인지 확인
Expand All @@ -47,11 +46,7 @@ public BlockResponseDTO.BlockDTO createBlock(Long targetMemberId) {
}

@Override
public void deleteBlock(Long blockId) {
// TODO 현재 로그인한 멤버 정보 받아오기, 멤버 예외 처리로 변경
Member member = memberRepository.findById(1L)
.orElseThrow(() -> new EntityNotFoundException("Sender not found"));

public void deleteBlock(Long blockId, Member member) {
Block block = blockRepository.findById(blockId)
.orElseThrow(() -> new BlockException(BlockErrorCode.BLOCK_NOT_FOUND));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.example.template.domain.block.service;

import com.example.template.domain.block.dto.response.BlockResponseDTO;
import com.example.template.domain.member.entity.Member;

import java.util.List;

public interface BlockQueryService {
List<BlockResponseDTO.BlockListDTO> getBlockList();
BlockResponseDTO.BlockListDTO getBlockList(Long cursor, Integer limit, Member member);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,33 @@
import com.example.template.domain.block.entity.Block;
import com.example.template.domain.block.repository.BlockRepository;
import com.example.template.domain.member.entity.Member;
import com.example.template.domain.member.repository.MemberRepository;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class BlockQueryServiceImpl implements BlockQueryService{

private final MemberRepository memberRepository;
private final BlockRepository blockRepository;

@Override
public List<BlockResponseDTO.BlockListDTO> getBlockList() {
// TODO 현재 로그인한 멤버 정보 받아오기, 멤버 예외 처리로 변경
Member member = memberRepository.findById(1L)
.orElseThrow(() -> new EntityNotFoundException("Sender not found"));

List<Block> blockList = blockRepository.findByMember(member);
return blockList.stream()
.map(BlockResponseDTO.BlockListDTO::from)
.collect(Collectors.toList());
public BlockResponseDTO.BlockListDTO getBlockList(Long cursor, Integer limit, Member member) {
// 첫 페이지 로딩 시 매우 큰 ID 값 사용
if (cursor == 0) {
cursor = Long.MAX_VALUE;
}

List<Block> blocks = blockRepository.findByMemberWithCursor(cursor, limit, member);

Long nextCursor = blocks.isEmpty() ? null : blocks.get(blocks.size() - 1).getId();
boolean hasNext = blocks.size() == limit;


return BlockResponseDTO.BlockListDTO.of(blocks, nextCursor, hasNext);

}
}

0 comments on commit 49c316e

Please sign in to comment.