Skip to content

Commit

Permalink
Merge pull request #18 from jisung-in/feature/14-talkrooms-get-api
Browse files Browse the repository at this point in the history
[Feature] TalkRoom 페이징 조회 API 구현
  • Loading branch information
AHNYUNKI authored Mar 22, 2024
2 parents 81e1c33 + e524027 commit 7ade783
Show file tree
Hide file tree
Showing 15 changed files with 750 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
import com.jisungin.api.ApiResponse;
import com.jisungin.api.talkroom.request.TalkRoomCreateRequest;
import com.jisungin.api.talkroom.request.TalkRoomEditRequest;
import com.jisungin.api.talkroom.request.TalkRoomSearchRequest;
import com.jisungin.application.response.PageResponse;
import com.jisungin.application.talkroom.TalkRoomService;
import com.jisungin.application.talkroom.response.TalkRoomResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
Expand All @@ -26,6 +30,11 @@ public ApiResponse<TalkRoomResponse> createTalkRoom(@Valid @RequestBody TalkRoom
return ApiResponse.ok(talkRoomService.createTalkRoom(request.toServiceRequest(), "[email protected]"));
}

@GetMapping("/talk-rooms")
public ApiResponse<PageResponse> getTalkRooms(@ModelAttribute TalkRoomSearchRequest search) {
return ApiResponse.ok(talkRoomService.getTalkRooms(search.toService()));
}

@PatchMapping("/talk-rooms")
public ApiResponse<TalkRoomResponse> editTalkRoom(@Valid @RequestBody TalkRoomEditRequest request) {
return ApiResponse.ok(talkRoomService.editTalkRoom(request.toServiceRequest(), "[email protected]"));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.jisungin.api.talkroom.request;

import com.jisungin.application.talkroom.request.TalkRoomSearchServiceRequest;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
public class TalkRoomSearchRequest {

private Integer page = 1;

private Integer size = 10;

private String order;

@Builder
private TalkRoomSearchRequest(Integer page, Integer size, String order) {
this.page = page != null ? page : 1;
this.size = size != null ? size : 1;
this.order = order != null ? order : "recent";
}

public TalkRoomSearchServiceRequest toService() {
return TalkRoomSearchServiceRequest.builder()
.page(page)
.size(size)
.order(order)
.build();
}

}
26 changes: 26 additions & 0 deletions src/main/java/com/jisungin/application/response/PageResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.jisungin.application.response;

import java.util.ArrayList;
import java.util.List;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class PageResponse<T> {

private List<T> queryResponse = new ArrayList<>();

private long totalCount;

private int size;

@Builder
private PageResponse(List<T> queryResponse, long totalCount, int size) {
this.queryResponse = queryResponse;
this.totalCount = totalCount;
this.size = size;
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.jisungin.application.talkroom;

import com.jisungin.application.response.PageResponse;
import com.jisungin.application.talkroom.request.TalkRoomCreateServiceRequest;
import com.jisungin.application.talkroom.request.TalkRoomEditServiceRequest;
import com.jisungin.application.talkroom.request.TalkRoomSearchServiceRequest;
import com.jisungin.application.talkroom.response.TalkRoomResponse;
import com.jisungin.domain.ReadingStatus;
import com.jisungin.domain.book.Book;
Expand Down Expand Up @@ -46,7 +48,11 @@ public TalkRoomResponse createTalkRoom(TalkRoomCreateServiceRequest request, Str
readingStatus.stream().map(status -> TalkRoomRole.roleCreate(talkRoom, status))
.forEach(talkRoomRoleRepository::save);

return TalkRoomResponse.of(talkRoom, readingStatus);
return TalkRoomResponse.of(user.getName(), talkRoom, readingStatus, book.getUrl());
}

public PageResponse getTalkRooms(TalkRoomSearchServiceRequest search) {
return talkRoomRepository.getTalkRooms(search);
}

@Transactional
Expand All @@ -69,7 +75,7 @@ public TalkRoomResponse editTalkRoom(TalkRoomEditServiceRequest request, String
readingStatus.stream().map(status -> TalkRoomRole.roleCreate(talkRoom, status))
.forEach(talkRoomRoleRepository::save);

return TalkRoomResponse.of(talkRoom, readingStatus);
return TalkRoomResponse.of(user.getName(), talkRoom, readingStatus, talkRoom.getBook().getUrl());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.jisungin.application.talkroom.request;

import static java.lang.Math.max;
import static java.lang.Math.min;

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class TalkRoomSearchServiceRequest {

private static final int MAX_SIZE = 2000;

private Integer page;

private Integer size;

private String order;

@Builder
private TalkRoomSearchServiceRequest(Integer page, Integer size, String order) {
this.page = page;
this.size = size;
this.order = order;
}

public long getOffset() {
return (long) (max(1, page) - 1) * min(size, MAX_SIZE);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.jisungin.application.talkroom.response;

import com.jisungin.domain.ReadingStatus;
import com.querydsl.core.annotations.QueryProjection;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class TalkRoomQueryReadingStatus {

private Long talkRoomId;

private ReadingStatus readingStatus;

@Builder
@QueryProjection
public TalkRoomQueryReadingStatus(Long talkRoomId, ReadingStatus readingStatus) {
this.talkRoomId = talkRoomId;
this.readingStatus = readingStatus;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.jisungin.application.talkroom.response;

import com.querydsl.core.annotations.QueryProjection;
import java.util.ArrayList;
import java.util.List;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class TalkRoomQueryResponse {

private Long talkRoomId;
private String userName;
private String content;
private String bookImage;
private List<TalkRoomQueryReadingStatus> readingStatuses = new ArrayList<>();

@Builder
@QueryProjection
public TalkRoomQueryResponse(Long talkRoomId, String userName, String content, String bookImage) {
this.talkRoomId = talkRoomId;
this.userName = userName;
this.content = content;
this.bookImage = bookImage;
}

public void addTalkRoomStatus(List<TalkRoomQueryReadingStatus> readingStatuses) {
this.readingStatuses = readingStatuses;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,37 @@

import com.jisungin.domain.ReadingStatus;
import com.jisungin.domain.talkroom.TalkRoom;
import com.querydsl.core.annotations.QueryProjection;
import java.util.List;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class TalkRoomResponse {

private Long id;
private String userName;
private String content;
private List<ReadingStatus> readingStatuses;
private String bookImage;

@Builder
private TalkRoomResponse(Long id, String content, List<ReadingStatus> readingStatuses) {
this.id = id;
@QueryProjection
public TalkRoomResponse(String userName, String content, List<ReadingStatus> readingStatuses, String bookImage) {
this.userName = userName;
this.content = content;
this.readingStatuses = readingStatuses;
this.bookImage = bookImage;
}

public static TalkRoomResponse of(TalkRoom talkRoom, List<ReadingStatus> readingStatuses) {
public static TalkRoomResponse of(String userName, TalkRoom talkRoom, List<ReadingStatus> readingStatuses,
String bookImage) {
return TalkRoomResponse.builder()
.id(talkRoom.getId())
.userName(userName)
.content(talkRoom.getContent())
.readingStatuses(readingStatuses)
.bookImage(bookImage)
.build();
}

Expand Down
20 changes: 20 additions & 0 deletions src/main/java/com/jisungin/config/QueryDslConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.jisungin.config;

import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class QueryDslConfig {

@PersistenceContext
public EntityManager em;

@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(em);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import org.springframework.stereotype.Repository;

@Repository
public interface TalkRoomRepository extends JpaRepository<TalkRoom, Long> {
public interface TalkRoomRepository extends JpaRepository<TalkRoom, Long>, TalkRoomRepositoryCustom {

@Query(
"select t from TalkRoom t join t.user u where t.id = :talkRoomId"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.jisungin.domain.talkroom.repository;

import com.jisungin.application.response.PageResponse;
import com.jisungin.application.talkroom.request.TalkRoomSearchServiceRequest;

public interface TalkRoomRepositoryCustom {

PageResponse getTalkRooms(TalkRoomSearchServiceRequest search);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package com.jisungin.domain.talkroom.repository;

import static com.jisungin.domain.book.QBook.book;
import static com.jisungin.domain.talkroom.QTalkRoom.talkRoom;
import static com.jisungin.domain.talkroom.QTalkRoomRole.talkRoomRole;
import static com.jisungin.domain.user.QUser.user;

import com.jisungin.application.response.PageResponse;
import com.jisungin.application.talkroom.request.TalkRoomSearchServiceRequest;
import com.jisungin.application.talkroom.response.QTalkRoomQueryReadingStatus;
import com.jisungin.application.talkroom.response.QTalkRoomQueryResponse;
import com.jisungin.application.talkroom.response.TalkRoomQueryReadingStatus;
import com.jisungin.application.talkroom.response.TalkRoomQueryResponse;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class TalkRoomRepositoryImpl implements TalkRoomRepositoryCustom {

private final JPAQueryFactory queryFactory;

@Override
public PageResponse<TalkRoomQueryResponse> getTalkRooms(TalkRoomSearchServiceRequest search) {

//루트 조회(toOne 코드를 모두 한번에 조회)
List<TalkRoomQueryResponse> findTalkRoom = findTalkRoom(search);

//TalkRoomRole 컬렉션을 MAP 한방에 조회
Map<Long, List<TalkRoomQueryReadingStatus>> talkRoomRoleMap = findTalkRoomRoleMap(toTalkRoomIds(findTalkRoom));

//루프를 돌면서 컬렉션 추가(추가 쿼리 실행X)
findTalkRoom.forEach(t -> t.addTalkRoomStatus(talkRoomRoleMap.get(t.getTalkRoomId())));

long totalCount = getTotalTalkRoomCount();

return PageResponse.<TalkRoomQueryResponse>builder()
.queryResponse(findTalkRoom)
.totalCount(totalCount)
.size(search.getSize())
.build();
}

private List<Long> toTalkRoomIds(List<TalkRoomQueryResponse> findTalkRoom) {
return findTalkRoom.stream()
.map(t -> t.getTalkRoomId())
.collect(Collectors.toList());
}

private Map<Long, List<TalkRoomQueryReadingStatus>> findTalkRoomRoleMap(List<Long> talkRoomIds) {
List<TalkRoomQueryReadingStatus> talkRoomRoles = queryFactory.select(new QTalkRoomQueryReadingStatus(
talkRoom.id,
talkRoomRole.readingStatus
))
.from(talkRoomRole)
.join(talkRoomRole.talkRoom, talkRoom)
.where(talkRoomRole.talkRoom.id.in(talkRoomIds))
.fetch();

return talkRoomRoles.stream()
.collect(Collectors.groupingBy(TalkRoomQueryReadingStatus::getTalkRoomId));
}

private long getTotalTalkRoomCount() {
return queryFactory
.select(talkRoom.count())
.from(talkRoom)
.join(talkRoom.user, user)
.join(talkRoom.book, book)
.fetchOne();
}

private List<TalkRoomQueryResponse> findTalkRoom(TalkRoomSearchServiceRequest search) {
return queryFactory.select(new QTalkRoomQueryResponse(
talkRoom.id.as("talkRoomId"),
user.name.as("userName"),
talkRoom.content,
book.url.as("bookImage")
))
.from(talkRoom)
.join(talkRoom.user, user)
.join(talkRoom.book, book)
.offset(search.getOffset())
.limit(search.getSize())
.orderBy(condition(search.getOrder()))
.fetch();
}

/**
* 아직 좋아요 기능이 구현 되지 않아 최신순으로만 정렬
*/
private OrderSpecifier<?> condition(String order) {
// if (order.equals("recent"))
return talkRoom.id.desc();
}

}
Loading

0 comments on commit 7ade783

Please sign in to comment.