Skip to content

Commit

Permalink
[Merge] 2024-06-06 버전 적용 (#213)
Browse files Browse the repository at this point in the history
* [Feat] 관심사 기반 추천 기능 추가 (#211)

* [Refactor] 대분류 id 순서로 응답하도록 수정

* [Refactor] 독서경험 수정시 파이썬 서버로 이벤트 날리도록 수정

* [Feat] 관심사 기반 추천 기능 추가

* [Refactor] 마이 페이지에서 출력할때 oauth로그인 여부 출력 (#209)

* [Refactor] 데이터베이스 인스턴스 연결 주소 변경

---------

Signed-off-by: 이성훈 <[email protected]>
Signed-off-by: simjaeyoun <[email protected]>
Co-authored-by: simjaeyoun <[email protected]>
  • Loading branch information
seonghooni and Simy2 authored Jun 6, 2024
1 parent 1a41a7f commit 4775e0b
Show file tree
Hide file tree
Showing 13 changed files with 156 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class BookSearchController {
@GetMapping(params = {"title", "target=modal"})
public ResponseEntity<List<BookSearchResponseDto>> getBookListByTitleOnModal(@RequestParam(name = "title") String searchWord){

PageRequest pageRequest = PageRequest.of(0, 6, Sort.by("count").descending());
PageRequest pageRequest = PageRequest.of(0, 6, Sort.by("view-count").descending());

List<BookSearchResponseDto> result = bookSearchService.searchBookOnModalByTitleContainingSearchWord(searchWord, pageRequest);

Expand All @@ -39,15 +39,15 @@ public ResponseEntity<List<BookSearchResponseDto>> getBookListByTitleOnModal(@Re
@GetMapping(params = {"author", "target=modal"})
public ResponseEntity<List<BookSearchResponseDto>> getBookListByAuthorOnModal(@RequestParam(name = "author") String searchWord){

PageRequest pageRequest = PageRequest.of(0, 6, Sort.by("count").descending());
PageRequest pageRequest = PageRequest.of(0, 6, Sort.by("view-count").descending());

List<BookSearchResponseDto> result = bookSearchService.searchBookOnModalByAuthorContainingSearchWord(searchWord, pageRequest);

return ResponseEntity.ok(result);
}

@Operation(summary = "[페이지]책제목에 검색어를 포함하는 book 리스트 ?개 요청 <파라미터에서 target을 page로 지정해야함>" +
" 예시) /api/search/book?title=그림&target=page&sort=oneLineCount&page=0&size=20")
" 예시) /api/search/book?title=그림&target=page&sort=oneline-count&page=0&size=20")
@GetMapping(params = {"title", "target=page"})
public ResponseEntity<Page<BookDto>> getBookListByTitleOnPageOrderByCount(@RequestParam(name = "title") String searchWord,
@RequestParam(name = "sort") String sortType,
Expand All @@ -67,7 +67,7 @@ public ResponseEntity<Page<BookDto>> getBookListByTitleOnPageOrderByCount(@Reque
}

@Operation(summary = "[페이지]작가명에 검색어를 포함하는 book 리스트 ?개 요청 <파라미터에서 target을 page로 지정해야함>" +
" 예시) /api/search/book?author=남해운&target=page&sort=oneLineCount&page=0&size=20")
" 예시) /api/search/book?author=남해운&target=page&sort=oneline-count&page=0&size=20")
@GetMapping(params = {"author", "target=page"})
public ResponseEntity<Page<BookDto>> getBookListByAuthorOnPage(@RequestParam(name = "author") String searchWord,
@RequestParam(name = "sort") String sortType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
@ToString(of = {"isbn", "title", "author", "bigCategory", "middleCategory", "imageUrl", "count"})
@Table(indexes = {
@Index(name = "book_isbn_index", columnList = "isbn", unique = true),
@Index(name = "book_count_index", columnList = "count")
@Index(name = "title_index", columnList = "title"),
@Index(name = "view_count_index", columnList = "view_count"),
@Index(name = "one_line_count_index", columnList = "one_line_count", unique = false)
})
public class Book {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package kr.KWGraduate.BookPharmacy.domain.book.domain;

import jakarta.persistence.*;
import kr.KWGraduate.BookPharmacy.domain.category.domain.Categories;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class InterestRecommend {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "interest_recommend_id")
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "category_id")
private Categories middleCategory;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "book_id")
private Book book;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import kr.KWGraduate.BookPharmacy.domain.book.domain.Book;
import kr.KWGraduate.BookPharmacy.domain.book.domain.ClientRecommend;
import kr.KWGraduate.BookPharmacy.domain.book.domain.InterestRecommend;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
Expand All @@ -24,4 +25,13 @@ public ClientBasedRecommendDto(ClientRecommend clientRecommend){
this.title = book.getTitle();
this. author = book.getAuthor();
}

public ClientBasedRecommendDto(InterestRecommend interestRecommend){
Book book = interestRecommend.getBook();
this.id = book.getId();
this.isbn = book.getIsbn();
this.imageUrl = book.getImageUrl();
this.title = book.getTitle();
this. author = book.getAuthor();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package kr.KWGraduate.BookPharmacy.domain.book.repository;

import kr.KWGraduate.BookPharmacy.domain.book.domain.InterestRecommend;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.EntityGraph;
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 InterestRecommendRepository extends JpaRepository<InterestRecommend, Long> {

@EntityGraph(attributePaths = {"book"})
@Query("select ir from InterestRecommend ir join fetch ir.middleCategory mc where mc.id in :categoryIdList")
List<InterestRecommend> findByInterestList(@Param("categoryIdList") List<Long> categoryIdList, Pageable pageable);
}

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

Expand Down Expand Up @@ -60,6 +61,7 @@ public Page<BookDto> getBookPageByMiddleCategory(String categoryName, Pageable p
return dtoList;
}

@Transactional
public BookDto getBookDetails(String isbn){
Book book = bookRepository.findBookWithKeywordByIsbn(isbn);
book.plusViewCount();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,55 +1,110 @@
package kr.KWGraduate.BookPharmacy.domain.book.service;

import kr.KWGraduate.BookPharmacy.domain.book.domain.ClientRecommend;
import kr.KWGraduate.BookPharmacy.domain.book.domain.InterestRecommend;
import kr.KWGraduate.BookPharmacy.domain.book.dto.response.BoardBasedRecommendDto;
import kr.KWGraduate.BookPharmacy.domain.book.dto.response.BookBasedRecommendDto;
import kr.KWGraduate.BookPharmacy.domain.book.dto.response.ClientBasedRecommendDto;
import kr.KWGraduate.BookPharmacy.domain.book.repository.BoardRecommendRepository;
import kr.KWGraduate.BookPharmacy.domain.book.repository.BookRecommendRepository;
import kr.KWGraduate.BookPharmacy.domain.book.repository.ClientRecommendRepository;
import kr.KWGraduate.BookPharmacy.domain.book.repository.InterestRecommendRepository;
import kr.KWGraduate.BookPharmacy.domain.client.domain.Client;
import kr.KWGraduate.BookPharmacy.domain.client.repository.ClientRepository;
import kr.KWGraduate.BookPharmacy.domain.interest.domain.Interest;
import kr.KWGraduate.BookPharmacy.domain.interest.repository.InterestRepository;
import kr.KWGraduate.BookPharmacy.domain.readexperience.domain.ReadExperience;
import kr.KWGraduate.BookPharmacy.domain.readexperience.repository.ReadExperienceRepository;
import kr.KWGraduate.BookPharmacy.global.security.common.dto.AuthenticationAdapter;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@RequiredArgsConstructor
public class RecommendService {
private final BoardRecommendRepository boardRecommendRepository;
private final BookRecommendRepository bookRecommendRepository;
private final ClientRecommendRepository clientRecommendRepository;
private final InterestRepository interestRepository;
private final InterestRecommendRepository interestRecommendRepository;
private final ClientRepository clientRepository;
private final ReadExperienceRepository readExperienceRepository;

public List<ClientBasedRecommendDto> getClientBasedAiPrescription(AuthenticationAdapter authentication){
String username = authentication.getUsername();
Client client = clientRepository.findByLoginId(username).get();

List<ClientRecommend> clientRecommend = clientRecommendRepository.findByClientAiPrescription(client.getId());
Collections.shuffle(clientRecommend);
return clientRecommend.stream()
.limit(3)
.sorted(Comparator.comparingInt(ClientRecommend::getRank))
.map(ClientBasedRecommendDto::new)
.collect(Collectors.toList());
List<ClientBasedRecommendDto> dtoList;

List<ReadExperience> readExperienceList = readExperienceRepository.findByLoginId(username);

PageRequest pageRequest = PageRequest.of(0, 3);

if(readExperienceList.isEmpty()) { // 독서경험이 0개일 경우 처리

List<InterestRecommend> interestRecommend = getInterestRecommend(username, pageRequest);

dtoList = interestRecommend.stream().map(interest -> new ClientBasedRecommendDto(interest)).collect(Collectors.toList());

}else { // 독서경험이 1개 이상 존재할 경우

List<ClientRecommend> clientRecommend = clientRecommendRepository.findByClientBasedRecommend(client.getId());

if(clientRecommend.isEmpty()) { // ClientRecommend가 존재하지 않는다면 관심사 기반 추천리스트를 반환
List<InterestRecommend> interestRecommend = getInterestRecommend(username, pageRequest);

dtoList = interestRecommend.stream().map(interest -> new ClientBasedRecommendDto(interest)).collect(Collectors.toList());
}else { // ClientRecommend가 존재한다면 유저 기반 추천리스트를 반환
Collections.shuffle(clientRecommend);

dtoList = clientRecommend.stream().limit(3).sorted(Comparator.comparingInt(ClientRecommend::getRank))
.map(ClientBasedRecommendDto::new).collect(Collectors.toList());
}
}

return dtoList;
}
public List<ClientBasedRecommendDto> getClientBasedRecommend(AuthenticationAdapter authentication){
String username = authentication.getUsername();
Client client = clientRepository.findByLoginId(username).get();

List<ClientRecommend> clientRecommend = clientRecommendRepository.findByClientBasedRecommend(client.getId());
Collections.shuffle(clientRecommend);
List<ClientBasedRecommendDto> dtoList;

return clientRecommend.stream()
.limit(10)
.sorted(Comparator.comparingInt(ClientRecommend::getRank))
.map(ClientBasedRecommendDto::new)
.collect(Collectors.toList());
List<ReadExperience> readExperienceList = readExperienceRepository.findByLoginId(username);

PageRequest pageRequest = PageRequest.of(0, 10);

if(readExperienceList.isEmpty()) { // 독서경험이 0개일 경우 처리

List<InterestRecommend> interestRecommend = getInterestRecommend(username, pageRequest);

dtoList = interestRecommend.stream().map(interest -> new ClientBasedRecommendDto(interest)).collect(Collectors.toList());

} else { // 독서경험이 1개 이상 존재할 경우

List<ClientRecommend> clientRecommend = clientRecommendRepository.findByClientBasedRecommend(client.getId());

if(clientRecommend.isEmpty()) { // ClientRecommend가 존재하지 않는다면 관심사 기반 추천리스트를 반환
List<InterestRecommend> interestRecommend = getInterestRecommend(username, pageRequest);

dtoList = interestRecommend.stream().map(interest -> new ClientBasedRecommendDto(interest)).collect(Collectors.toList());
}else { // ClientRecommend가 존재한다면 유저 기반 추천리스트를 반환
Collections.shuffle(clientRecommend);

dtoList = clientRecommend.stream().limit(10).sorted(Comparator.comparingInt(ClientRecommend::getRank))
.map(ClientBasedRecommendDto::new).collect(Collectors.toList());
}
}

return dtoList;
}
public BoardBasedRecommendDto getBoardBasedRecommend(Long boardId){
return boardRecommendRepository.findByBoardBasedRecommend(boardId)
Expand All @@ -69,4 +124,21 @@ public List<BookBasedRecommendDto> getBookBasedRecommend(String isbn){
.map(BookBasedRecommendDto::new)
.collect(Collectors.toList());
}

private List<InterestRecommend> getInterestRecommend(String username, Pageable pageable) {
List<Interest> interestList = interestRepository.findByLoginId(username); // 유저의 관심사리스트

List<InterestRecommend> interestRecommend;

if(interestList.isEmpty()) // 유저가 관심사를 하나도 등록하지 않았을 경우
{
interestRecommend = interestRecommendRepository.findAll(pageable).getContent();

}else{
List<Long> interestIdList = interestList.stream().map(interest -> interest.getId()).collect(Collectors.toList());
interestRecommend = interestRecommendRepository.findByInterestList(interestIdList, pageable);
}

return interestRecommend;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public interface CategoryRepository extends JpaRepository<Categories, Long> {
@Query("select c from Categories c where c.level = 1")
List<Categories> findBigCategory();

@Query("select c from Categories c join fetch c.parentCategory pc where c.level = 2")
@Query("select c from Categories c join fetch c.parentCategory pc where c.level = 2 order by pc.id")
List<Categories> findChildCategories();

@Query("select c from Categories c where c.name in :categoryList")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand All @@ -36,7 +33,7 @@ public List<CategoryDto> getChildCategory(String categoryName) {
public Map<String, List<String>> getAllCategoryGrouped() {
List<Categories> allCategories = categoryRepository.findChildCategories();

Map<String, List<String>> map = new HashMap<>();
Map<String, List<String>> map = new LinkedHashMap<>();

for (Categories category : allCategories) {
String key = category.getParentCategory().getName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ public class ClientMypageDto {
private String description;
private int boardCount;
private int prescriptionCount;
private Boolean isOauth;

@Builder
public ClientMypageDto(Client client) {
if(client.getLoginId().startsWith("naver")){
this.loginId = client.getLoginId().substring(6,12);
this.isOauth = true;
}else{
this.loginId = client.getLoginId();
this.isOauth = false;
}
this.name = client.getName();
this.nickname = client.getNickname();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,31 +61,6 @@ public void updateReadExperience(ReadExperienceUpdateRequestDto readExperienceDT
applicationEventPublisher.publishEvent(new ReadExperienceUpdatedEvent(this,client.getId()));
}

/**
* 단일 책에 대한 독서경험을 추가할때 사용되는 서비스 코드
* ex) 책 상세정보 페이지에서 '독서경험 추가하기', 한줄처방 페이지에서 '한줄처방 작성하기' 에서 사용된다.
*
* @return
*/
@Transactional
public ReadExperience createReadExperience(ReadExperienceCreateDto readExperienceCreateDto, AuthenticationAdapter authentication){

String loginId = authentication.getUsername();
Client client = clientRepository.findByLoginId(loginId).get();

String isbn = readExperienceCreateDto.getBookIsbn();
Book book = bookRepository.findOptionalByIsbn(isbn).get();

ReadExperience readExperience = ReadExperience.builder().book(book).client(client).build();
return readExperienceRepository.save(readExperience);
}

public ReadExperience createReadExperience(Client client, Book book) {
ReadExperience readExperience = ReadExperience.builder().book(book).client(client).build();

return readExperienceRepository.save(readExperience);
}

/**
* 독서 경험을 페이징 하여 조회하는 서비스
* */
Expand All @@ -100,4 +75,4 @@ public Page<ReadExperienceResponseDto> getReadExperiences(AuthenticationAdapter

return readExperienceResponseDtoPage;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,23 +104,4 @@ class ReadExperienceServiceTest {
assertThat(result.getTotalElements()).isEqualTo(3); // 전체 개수는 3개여야 함
}

@Test
void 독서경험_단일추가() {
//given
Client client = clientRepository.findByLoginId("kw_lsh_3717").get();
ClientDetails userDetails = new ClientDetails(client);

List<ReadExperience> previousList = readExperienceRepository.findByLoginId("kw_lsh_3717");
assertThat(previousList.size()).isEqualTo(3); // 기존의 독서경험의 수는 3개여야 함

ReadExperienceCreateDto dto = new ReadExperienceCreateDto("0002");

//when
readExperienceService.createReadExperience(dto, userDetails);
em.clear();

//then
List<ReadExperience> updatedList = readExperienceRepository.findByLoginId("kw_lsh_3717");
assertThat(updatedList.size()).isEqualTo(4); // 새로 업데이트 된 독서경험의 수는 4개여야 함
}
}
2 changes: 1 addition & 1 deletion submodule-config

0 comments on commit 4775e0b

Please sign in to comment.