Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,17 @@
import org.websoso.WSSServer.domain.AvatarProfile;
import org.websoso.WSSServer.domain.Genre;
import org.websoso.WSSServer.domain.GenrePreference;
import org.websoso.WSSServer.dto.novel.FilteredNovelsResponse;
import org.websoso.WSSServer.dto.novel.NovelSummaryResponse;
import org.websoso.WSSServer.dto.novel.SearchedNovelsResponse;
import org.websoso.WSSServer.library.service.AttractivePointService;
import org.websoso.WSSServer.library.service.KeywordService;
import org.websoso.WSSServer.repository.AvatarProfileRepository;
import org.websoso.WSSServer.user.domain.User;
import org.websoso.WSSServer.domain.common.GenreName;
import org.websoso.WSSServer.dto.novel.FilteredNovelsGetResponse;
import org.websoso.WSSServer.dto.novel.NovelGetResponseBasic;
import org.websoso.WSSServer.dto.novel.NovelGetResponseInfoTab;
import org.websoso.WSSServer.dto.novel.NovelGetResponsePreview;
import org.websoso.WSSServer.dto.novel.SearchedNovelsGetResponse;
import org.websoso.WSSServer.dto.popularNovel.PopularNovelsGetResponse;
import org.websoso.WSSServer.dto.userNovel.TasteNovelGetResponse;
import org.websoso.WSSServer.dto.userNovel.TasteNovelsGetResponse;
Expand Down Expand Up @@ -71,37 +72,38 @@ public class SearchNovelApplication {
* @return SearchedNovelsGetResponse
*/
@Transactional(readOnly = true)
public SearchedNovelsGetResponse searchNovels(String query, int page, int size) {
public SearchedNovelsResponse searchNovels(String query, int page, int size) {
PageRequest pageRequest = PageRequest.of(page, size);
String searchQuery = query.replaceAll("\\s+", "").replaceAll("[^a-zA-Z0-9가-힣]", "");
String searchQuery = sanitizeQuery(query);

if (searchQuery.isBlank()) {
return SearchedNovelsGetResponse.of(0L, false, Collections.emptyList());
return SearchedNovelsResponse.empty();
}

Page<Novel> novels = novelService.searchNovels(pageRequest, searchQuery);

List<NovelGetResponsePreview> novelGetResponsePreviews = novels.stream()
.map(this::convertToDTO)
List<NovelSummaryResponse> novelGetResponsePreviews = novels.stream()
.map(this::convertToDTO2)
.toList();

return SearchedNovelsGetResponse.of(novels.getTotalElements(), novels.hasNext(), novelGetResponsePreviews);
return SearchedNovelsResponse.of(novelGetResponsePreviews, novels.getTotalElements(), novels.hasNext());
}

@Transactional(readOnly = true)
public FilteredNovelsGetResponse getFilteredNovels(List<String> genreNames, Boolean isCompleted, Float novelRating,
List<Integer> keywordIds, int page, int size) {
public FilteredNovelsResponse getFilteredNovels(List<String> genreNames, List<Integer> keywordIds, Boolean isCompleted, Float novelRating, int page, int size) {
PageRequest pageRequest = PageRequest.of(page, size);
List<Genre> genres = getGenres(genreNames);
List<Keyword> keywords = getKeywords(keywordIds);

List<Genre> genres = genreService.getGenresOrException(genreNames);

List<Keyword> keywords = keywordService.getKeywordsOrException(keywordIds);

Page<Novel> novels = novelService.findFilteredNovels(pageRequest, genres, keywords, isCompleted, novelRating);

List<NovelGetResponsePreview> novelGetResponsePreviews = novels.stream()
.map(this::convertToDTO)
List<NovelSummaryResponse> novelGetResponsePreviews = novels.stream()
.map(this::convertToDTO2)
.toList();

return FilteredNovelsGetResponse.of(novels.getTotalElements(), novels.hasNext(), novelGetResponsePreviews);
return FilteredNovelsResponse.of(novelGetResponsePreviews, novels.getTotalElements(), novels.hasNext());
}

@Transactional(readOnly = true)
Expand Down Expand Up @@ -164,17 +166,32 @@ public PopularNovelsGetResponse getTodayPopularNovels() {
List<Long> novelIdsFromPopularNovel = popularNovelService.getNovelIdsFromPopularNovel();
List<Long> selectedNovelIdsFromPopularNovel = getSelectedNovelIdsFromPopularNovel(novelIdsFromPopularNovel);
List<Novel> popularNovels = novelService.getSelectedPopularNovels(selectedNovelIdsFromPopularNovel);
List<Feed> popularFeedsFromPopularNovels = feedRepository.findPopularFeedsByNovelIds(selectedNovelIdsFromPopularNovel);
List<Feed> popularFeedsFromPopularNovels = feedRepository.findPopularFeedsByNovelIds(
selectedNovelIdsFromPopularNovel);

Map<Long, Feed> feedMap = createFeedMap(popularFeedsFromPopularNovels);
Map<Long, AvatarProfile> avatarMap = createAvatarMap(feedMap);

return PopularNovelsGetResponse.create(popularNovels, feedMap, avatarMap);
}

// TODO: DTO로 이전할 명분이 충분한 메서드
private NovelGetResponsePreview convertToDTO(Novel novel) {
// TODO: UserNovel 리스트 개수를 세는것이 아닌, 개수를 세는 쿼리가 필요
/**
* 검색어 정제 메서 공백 제거 및 특수문자 필터링
*
* @param query 검색어
* @return 필터링된 검색어
*/
private String sanitizeQuery(String query) {
if (query == null) {
return "";
}

return query.replaceAll("\\s+", "")
.replaceAll("[^a-zA-Z0-9가-힣]", "");
}

private NovelSummaryResponse convertToDTO2(Novel novel) {
// TODO: Repository에서 NovelSummaryResponse에 맞게 데이터를 불러오는게 좋을듯
List<UserNovel> userNovels = novel.getUserNovels();

long interestCount = userNovels.stream()
Expand All @@ -188,50 +205,18 @@ private NovelGetResponsePreview convertToDTO(Novel novel) {
.mapToDouble(UserNovel::getUserNovelRating)
.sum();

Float novelRatingAverage = novelRatingCount == 0
float novelRatingAverage = novelRatingCount == 0
? 0.0f
: Math.round((float) (novelRatingSum / novelRatingCount) * 10.0f) / 10.0f;

return NovelGetResponsePreview.of(
return NovelSummaryResponse.of(
novel,
interestCount,
novelRatingAverage,
novelRatingCount
);
}

// TODO: for 문으로 장르를 데이터베이스에서 읽어오는 부분 개선해야함
private List<Genre> getGenres(List<String> genreNames) {
genreNames = genreNames == null
? Collections.emptyList()
: genreNames;

List<Genre> genres = new ArrayList<>();
if (!genreNames.isEmpty()) {
for (String genreName : genreNames) {
genres.add(genreService.getGenreOrException(genreName));
}
}

return genres;
}

// TODO: for 문으로 키워드를 데이터베이스에서 읽어오는 부분 개선해야함
private List<Keyword> getKeywords(List<Integer> keywordIds) {
keywordIds = keywordIds == null
? Collections.emptyList()
: keywordIds;

List<Keyword> keywords = new ArrayList<>();
if (!keywordIds.isEmpty()) {
for (Integer keywordId : keywordIds) {
keywords.add(keywordService.getKeywordOrException(keywordId));
}
}

return keywords;
}

private String getNovelGenreNames(List<NovelGenre> novelGenres) {
return novelGenres.stream()
.map(novelGenre -> getKoreanGenreName(novelGenre.getGenre().getGenreName()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.websoso.WSSServer.application.SearchNovelApplication;
import org.websoso.WSSServer.dto.novel.FilteredNovelsResponse;
import org.websoso.WSSServer.dto.novel.SearchedNovelsResponse;
import org.websoso.WSSServer.user.domain.User;
import org.websoso.WSSServer.dto.novel.FilteredNovelsGetResponse;
import org.websoso.WSSServer.dto.novel.NovelGetResponseBasic;
import org.websoso.WSSServer.dto.novel.NovelGetResponseFeedTab;
import org.websoso.WSSServer.dto.novel.NovelGetResponseInfoTab;
import org.websoso.WSSServer.dto.novel.SearchedNovelsGetResponse;
import org.websoso.WSSServer.dto.popularNovel.PopularNovelsGetResponse;
import org.websoso.WSSServer.dto.userNovel.TasteNovelsGetResponse;
import org.websoso.WSSServer.feed.service.FeedService;
Expand All @@ -37,12 +37,12 @@ public class NovelController {
* @param query 검색할 작품명 or 작가명
* @param page 페이지 네이션 페이지
* @param size 페이지 네이션 사이즈
* @return SearchedNovelsGetResponse
* @return SearchedNovelsResponse
*/
@GetMapping
public ResponseEntity<SearchedNovelsGetResponse> searchNovels(@RequestParam(required = false) String query,
@RequestParam int page,
@RequestParam int size) {
public ResponseEntity<SearchedNovelsResponse> searchNovels(@RequestParam(required = false) String query,
@RequestParam int page,
@RequestParam int size) {
return ResponseEntity
.status(OK)
.body(searchNovelApplication.searchNovels(query, page, size));
Expand All @@ -61,7 +61,7 @@ public ResponseEntity<SearchedNovelsGetResponse> searchNovels(@RequestParam(requ
*/
@GetMapping("/filtered")
@PreAuthorize("isAuthenticated()")
public ResponseEntity<FilteredNovelsGetResponse> getFilteredNovels(
public ResponseEntity<FilteredNovelsResponse> getFilteredNovels(
@RequestParam(required = false) List<String> genres,
@RequestParam(required = false) Boolean isCompleted,
@RequestParam(required = false) Float novelRating,
Expand All @@ -70,8 +70,7 @@ public ResponseEntity<FilteredNovelsGetResponse> getFilteredNovels(
@RequestParam int size) {
return ResponseEntity
.status(OK)
.body(searchNovelApplication.getFilteredNovels(genres, isCompleted, novelRating, keywordIds, page,
size));
.body(searchNovelApplication.getFilteredNovels(genres, keywordIds, isCompleted, novelRating, page, size));
}

/**
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.websoso.WSSServer.dto.novel;

import java.util.List;

public record FilteredNovelsResponse(
long resultCount,
boolean isLoadable,
List<NovelSummaryResponse> novels
) {
public static FilteredNovelsResponse of(List<NovelSummaryResponse> novels, long resultCount, boolean isLoadable) {
return new FilteredNovelsResponse(
resultCount,
isLoadable,
novels
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.websoso.WSSServer.dto.novel;

import org.websoso.WSSServer.novel.domain.Novel;

public record NovelSummaryResponse(
long novelId,
String novelImage,
String title,
String author,
long interestCount,
float novelRating,
long novelRatingCount
) {
public static NovelSummaryResponse of(Novel novel, long interestCount, float novelRating,
long novelRatingCount) {
return new NovelSummaryResponse(
novel.getNovelId(),
novel.getNovelImage(),
novel.getTitle(),
novel.getAuthor(),
interestCount,
novelRating,
novelRatingCount
);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.websoso.WSSServer.dto.novel;

import java.util.Collections;
import java.util.List;

public record SearchedNovelsResponse(
long resultCount,
boolean isLoadable,
List<NovelSummaryResponse> novels
) {
public static SearchedNovelsResponse of(List<NovelSummaryResponse> novels, long resultCount, boolean isLoadable) {
return new SearchedNovelsResponse(
resultCount,
isLoadable,
novels
);
}

public static SearchedNovelsResponse empty() {
return new SearchedNovelsResponse(
0L,
false,
Collections.emptyList()
);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package org.websoso.WSSServer.library.repository;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.websoso.WSSServer.library.domain.Keyword;

@Repository
public interface KeywordRepository extends JpaRepository<Keyword, Integer> {

List<Keyword> findByKeywordIdIn(List<Integer> keywordIds);

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

public interface NovelCustomRepository {

Page<Novel> findFilteredNovels(Pageable pageable, List<Genre> genres, Boolean isCompleted, Float novelRating,
List<Keyword> keywords);

Page<Novel> findSearchedNovels(Pageable pageable, String query);

Page<Novel> findFilteredNovels(Pageable pageable, List<Genre> genres, Boolean isCompleted, Float novelRating, List<Keyword> keywords);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import static org.websoso.WSSServer.exception.error.CustomGenreError.GENRE_NOT_FOUND;

import java.util.Collections;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -21,4 +23,22 @@ public Genre getGenreOrException(String genreName) {
.orElseThrow(() -> new CustomGenreException(GENRE_NOT_FOUND,
"genre with the given name is not found"));
}

@Transactional(readOnly = true)
public List<Genre> getGenresOrException(List<String> names) {
if (names == null || names.isEmpty()) {
return Collections.emptyList();
}

List<String> uniqueNames = names.stream().distinct().toList();

List<Genre> genres = genreRepository.findByNameIn(uniqueNames);

if (genres.size() != uniqueNames.size()) {
throw new CustomGenreException(GENRE_NOT_FOUND,
"genre with the given name is not found");
}

return genres;
}
}
Loading