[캡스톤디자인] 모임 서비스, 유저 서비스 개선

Dev_Sanizzang·2023년 5월 28일
0

캡스톤디자인

목록 보기
7/15

📕 개요

채팅구현을 끝내고 원래 화상채팅 서비스를 구현하려고 했으나
교수님께서 간담회 일정까지 최대한 완성도를 높일 수 있도록 하라는 지시가 내려와 화상채팅 구현은 나중으로 미루고 지금까지 구현한 코드들을 개선하고 테스팅까지 완벽하게 끝내놓으려고 한다.
이번 포스팅은 기존 모임 서비스를 개선하는 글을 쓰겠다.

1. 코드 개선

  • 현재 코드는 DTO가 됐던 Entity가 됐던 무분별한 @Data, @Setter 사용을 하고 있다.
    -> @Data, @Setter 사용 -> @Getter, @Builder 사용

  • ModelMapper 사용
    -> 자바 매핑 코드로 변경

RequestClub.java

@Getter
@NoArgsConstructor
public class RequestClub {

    @NotNull(message = "host_id cannot be null")
    private Long hostId;

    @NotNull(message ="clubName cannot be null")
    private String clubName;

    @NotNull(message = "category cannot be null")
    private String category;

    private String description;

    private String mainImageUrl;

    @NotNull(message = "approvalMethod cannot be null")
    private ApprovalMethod approvalMethod;

    @NotNull(message = "maximumPeople cannot be null")
    private int maximumPeople;

    private List<String> tagList;

    public Club toEntity() {
        Club clubBuild = Club.builder()
                .hostId(hostId)
                .clubName(clubName)
                .category(category)
                .description(description)
                .mainImageUrl(mainImageUrl)
                .approvalMethod(approvalMethod)
                .maximumPeople(maximumPeople)
                .build();

        this.tagList.stream()
                .map(tag -> Tag.builder().tag(tag).build())
                .forEach(clubBuild::addTag);

        return clubBuild;
    }
}
@Getter
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResponseClubByClubId {
    private Long id;
    private Long hostId;
    private String clubName;
    private String category;
    private String description;
    private String mainImageUrl;
    private ApprovalMethod approvalMethod;
    private int maximumPeople;
    private boolean recruitment;
    private LocalDateTime createdAt;

    @Builder
    public ResponseClubByClubId(Club club) {
        this.id = club.getId();
        this.hostId = club.getHostId();
        this.clubName = club.getClubName();
        this.category = club.getCategory();
        this.description = club.getDescription();
        this.mainImageUrl = club.getMainImageUrl();
        this.approvalMethod = club.getApprovalMethod();
        this.maximumPeople = club.getMaximumPeople();
        this.recruitment = club.isRecruitment();
        this.createdAt = club.getCreatedAt();
    }
}

기존 ModelMapper를 사용해서 DTO <-> Entity간 매핑을 해준 것에서 DTO안에 매핑 메서드를 구현하는 것으로 변경하였다.

이를 통해 위와 같이 Controller와 Service의 코드가 엄청 간결하고 직관적으로 바뀐것을 볼 수 있다.

user-service 같은 경우도 club-service와 동일한 방법으로 코드를 개선했기 때문에 user-service 코드 개선부분은 생략하겠다.

2. 모임 검색 API 추가하기

현재 모임 서비스 API는 위와 같다.
현재 API는 그냥 기본적인 조회기능만 제공할 뿐 검색 조건을 제공하고 있지 않다.
고로 검색 조건을 추가하고 모든 모임을 한번에 조회하는 것보다 페이지네이션 통해 조회하는 것으로 구현해보자!

검색 조건

검색 조건이라 하면 어떤게 필요할까?

  • 말 그대로 검색한 모임 목록 조회가 필요할 것이고
  • 카테고리에 따른 분류

일단 위 2개만 구현해놓고 더 필요하면 추가하도록 하자!

검색 구현

ClubController.java

    // 모임 조회
    @GetMapping("/club")
    public ResponseEntity<Page<ResponseClub>> getClubs(ClubSearchCondition clubSearchCondition, Pageable pageable) {
        Page<ResponseClub> clubPage = clubService.getClubs(clubSearchCondition, pageable);

        return ResponseEntity.status(HttpStatus.OK).body(clubPage);
    }

먼저 기존의 단순히 모임 목록을 조회를 ClubSearchCondition: 검색 조건, Pageable: 페이징 조건을 추가하였다.

ClubSearchCondition.java

: 쿼리 파라미터로 받을 검색 조건들

public class ClubSearchCondition {

    String search;
    String category;
}

search: 검색
category: 카테고리

ClubServiceImpl.java

    // 모임 조회
    @Override
    public Page<ResponseClub> getClubs(ClubSearchCondition clubSearchCondition, Pageable pageable) {
        return clubRepository.getClubs(clubSearchCondition, pageable);
    }

Service는 별거 없다. clubRepository에 쿼리파라미터로 받은 검색 조건과 페이징 조건을 넘긴다.

ClubRepository.java

public interface ClubRepository extends JpaRepository<Club, Long>, ClubCustomRepository {
}

QueryDSL를 통해 필터링과, 페이징을 구현하기 위해서 ClubCustomRepository(커스텀 Repository)를 추가로 상속 받았다.

ClubRepositoryImpl.java

: 커스텀 Repository 구현 클래스

public class ClubRepositoryImpl implements ClubCustomRepository {

    private JPAQueryFactory queryFactory;

    public ClubRepositoryImpl(EntityManager em) {
        this.queryFactory = new JPAQueryFactory(em);
    }

    @Override
    public Page<ResponseClub> getClubs(ClubSearchCondition condition, Pageable pageable) {
        List<ResponseClub> content = queryFactory
                .select(new QResponseClub(
                        club.id,
                        club.hostId,
                        club.clubName,
                        club.category,
                        club.description,
                        club.mainImageUrl,
                        club.approvalMethod,
                        club.maximumPeople,
                        club.recruitment,
                        club.createdAt
                ))
                .from(club)
                .where(
                        search(condition.getSearch()),
                        categoryEq(condition.getCategory())
                )
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetch();

        JPAQuery<Club> countQuery = queryFactory
                .select(club)
                .from(club)
                .where(
                        search(condition.getSearch()),
                        categoryEq(condition.getCategory())
                );

        return PageableExecutionUtils.getPage(content, pageable, () -> countQuery.fetch().size());
    }

    private BooleanExpression search(String search) {
        return StringUtils.hasText(search) ? club.clubName.likeIgnoreCase("%" + search + "%") : null;
    }

    private BooleanExpression categoryEq(String category) {
        return StringUtils.hasText(category) ? club.category.eq(category): null;
    }
}

간단하게 설명하자면

  • select 대상은 DTO에 @QueryProjection를 사용하여 QDTO를 만들어 조회를 하도록 하였다.
  • 동적 쿼리 해결은 Where 다중 파라미터를 사용하여 메소드로 쿼리 조건을 뺐다.

요청 예시

API 요청은 위와 같이 하면된다. 필터링 하고 싶은 부분만 쿼리 파라미터에 추가해서 요청을 하면 쿼리 파라미터를 추가한 부분만 필터링되서 응답한다.

🚪 마무리

이를 통해 유저 서비스와 모임 서비스의 코드개선과 추가를 완료했다.
추후 더 필요한 기능이 있으면 추가하도록 하고 다음에는 MSA 테스팅을 해보도록 하자.

profile
기록을 통해 성장합니다.

0개의 댓글