diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/BookPharmacyApplication.java b/src/main/java/kr/KWGraduate/BookPharmacy/BookPharmacyApplication.java index c952a864..ecee903e 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/BookPharmacyApplication.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/BookPharmacyApplication.java @@ -3,9 +3,11 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableJpaAuditing +@EnableScheduling public class BookPharmacyApplication { public static void main(String[] args) { diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/board/dto/response/BoardMyPageDto.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/board/dto/response/BoardMyPageDto.java index cfbd14c9..bb9952ff 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/domain/board/dto/response/BoardMyPageDto.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/board/dto/response/BoardMyPageDto.java @@ -13,6 +13,7 @@ @NoArgsConstructor public class BoardMyPageDto { private Long boardId; + private String nickname; private String title; private LocalDate createdDate; private Keyword keyword; @@ -21,6 +22,7 @@ public class BoardMyPageDto { @Builder public BoardMyPageDto(Board board, Long count){ boardId = board.getId(); + nickname = board.getClient().getNickname(); title = board.getTitle(); createdDate = board.getCreatedDate().toLocalDate(); keyword = board.getKeyword(); diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/board/event/BoardUpdatedEvent.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/board/event/BoardUpdatedEvent.java new file mode 100644 index 00000000..fcb70344 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/board/event/BoardUpdatedEvent.java @@ -0,0 +1,14 @@ +package kr.KWGraduate.BookPharmacy.domain.board.event; + +import lombok.Getter; +import org.springframework.context.ApplicationEvent; + +@Getter +public class BoardUpdatedEvent extends ApplicationEvent { + private final Long boardId; + + public BoardUpdatedEvent(Object source, Long boardId) { + super(source); + this.boardId = boardId; + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/board/service/BoardService.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/board/service/BoardService.java index 087c524a..58501760 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/domain/board/service/BoardService.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/board/service/BoardService.java @@ -6,6 +6,7 @@ import kr.KWGraduate.BookPharmacy.domain.board.dto.response.BoardConcernPageDto; import kr.KWGraduate.BookPharmacy.domain.board.dto.response.BoardDetailDto; import kr.KWGraduate.BookPharmacy.domain.board.dto.response.BoardMyPageDto; +import kr.KWGraduate.BookPharmacy.domain.board.event.BoardUpdatedEvent; import kr.KWGraduate.BookPharmacy.domain.keyword.service.KeywordBiMapService; import kr.KWGraduate.BookPharmacy.domain.onelineprescription.dto.response.OneLineResponseDto; import kr.KWGraduate.BookPharmacy.global.security.common.dto.AuthenticationAdapter; @@ -16,6 +17,7 @@ import kr.KWGraduate.BookPharmacy.domain.client.repository.ClientRepository; import kr.KWGraduate.BookPharmacy.domain.prescription.repository.PrescriptionRepository; import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; @@ -34,7 +36,7 @@ public class BoardService { private final PrescriptionRepository prescriptionRepository; private final AnswerService answerService; private final KeywordBiMapService keywordBiMapService; - + private final ApplicationEventPublisher applicationEventPublisher; public Page getBoards(Pageable pageable){ Page pageResult = boardRepository.findAllBoards(pageable); Page dtoList = pageResult.map(board -> new BoardConcernPageDto(board)); @@ -66,8 +68,17 @@ public Page getBoards(Pageable pageable , String searchKeyw @Transactional public Long modifyBoard(Long boardId, BoardModifyDto boardModifyDto) throws Exception { Board board = boardRepository.findById(boardId).orElseThrow(Exception::new); + + Keyword originKeyword = board.getKeyword(); + String originDescription = board.getDescription(); + board.modifyBoard(boardModifyDto.getTitle() , boardModifyDto.getDescription(), boardModifyDto.getKeyword()); answerService.updateAnswers(boardModifyDto.getAnswers()); + + if(!(originDescription.equals(board.getDescription()) && originKeyword == board.getKeyword())){ + applicationEventPublisher.publishEvent(new BoardUpdatedEvent(this,boardId)); + } + return boardId; } @@ -77,6 +88,9 @@ public Long createBoard(BoardCreateDto boardCreateDto, AuthenticationAdapter aut Board board = boardCreateDto.toEntity(client); Long id = boardRepository.save(board).getId(); answerService.createAnswer(id,boardCreateDto.getAnswers()); + + applicationEventPublisher.publishEvent(new BoardUpdatedEvent(this,id)); + return id; } diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/api/BestSellerBookController.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/api/BestSellerBookController.java new file mode 100644 index 00000000..a6b972f1 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/api/BestSellerBookController.java @@ -0,0 +1,26 @@ +package kr.KWGraduate.BookPharmacy.domain.book.api; + +import kr.KWGraduate.BookPharmacy.domain.book.dto.response.BestSellerBookDto; +import kr.KWGraduate.BookPharmacy.domain.book.service.BestSellerBookService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("/api/best-seller") +@RequiredArgsConstructor +public class BestSellerBookController { + + private final BestSellerBookService bestSellerBookService; + + @GetMapping() + public ResponseEntity> getBestSellerBooks() { + List result = bestSellerBookService.getBestSellerBookList(); + + return ResponseEntity.ok(result); + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/api/NewBookController.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/api/NewBookController.java new file mode 100644 index 00000000..1b1c76e4 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/api/NewBookController.java @@ -0,0 +1,26 @@ +package kr.KWGraduate.BookPharmacy.domain.book.api; + +import kr.KWGraduate.BookPharmacy.domain.book.dto.response.NewBookDto; +import kr.KWGraduate.BookPharmacy.domain.book.service.NewBookService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("/api/new-book") +@RequiredArgsConstructor +public class NewBookController { + + private final NewBookService newBookService; + + @GetMapping() + public ResponseEntity> getBestSellerBooks() { + List result = newBookService.getNewBookList(); + + return ResponseEntity.ok(result); + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/api/RecommendController.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/api/RecommendController.java new file mode 100644 index 00000000..556f9ed6 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/api/RecommendController.java @@ -0,0 +1,48 @@ +package kr.KWGraduate.BookPharmacy.domain.book.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import kr.KWGraduate.BookPharmacy.domain.book.service.RecommendService; +import kr.KWGraduate.BookPharmacy.global.security.common.dto.AuthenticationAdapter; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/recommend/book") +@Tag(name = "책 추천 api") +public class RecommendController { + + private final RecommendService recommendService; + + @GetMapping("/clientbased/aiprescription") + @Operation(summary = "메인 페이지에 출력되는 ai처방 3개", description = "아이디: string, password: string만 가능, 로그인 필수") + public ResponseEntity getClientBasedAiPrescription(@AuthenticationPrincipal UserDetails userDetails){ + return ResponseEntity.ok(recommendService.getClientBasedAiPrescription((AuthenticationAdapter) userDetails)); + } + + @GetMapping("/clientbased") + @Operation(summary = "메인 페이지에 출력되는 비슷한 유저 기반 책 추천 10개", description = "아이디: string, password: string만 가능,로그인 필수") + public ResponseEntity getClientBasedRecommend(@AuthenticationPrincipal UserDetails userDetails){ + return ResponseEntity.ok(recommendService.getClientBasedRecommend((AuthenticationAdapter) userDetails)); + } + + @GetMapping("/boardbased") + @Operation(summary = "고민 게시판 ai처방", description = "예시 boardId는 167임. 키워드(max=3) 넘겨주면 description은 프론트에서 구현해야함") + public ResponseEntity getBoardBasedRecommend(@RequestParam("boardId") Long boardId){ + return ResponseEntity.ok(recommendService.getBoardBasedRecommend(boardId)); + } + + @GetMapping("/bookbased") + @Operation(summary = "연관 책 리스트", description = "예시 isbn은 9788901126050임. 10개 넘겨짐") + public ResponseEntity getBookBasedRecommend(@RequestParam("isbn") String isbn){ + return ResponseEntity.ok(recommendService.getBookBasedRecommend(isbn)); + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/BestSellerBook.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/BestSellerBook.java new file mode 100644 index 00000000..fddbf45d --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/BestSellerBook.java @@ -0,0 +1,27 @@ +package kr.KWGraduate.BookPharmacy.domain.book.domain; + +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class BestSellerBook { + + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotNull + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "book_id") + private Book book; + + @Builder + public BestSellerBook(Book book) { + this.book = book; + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/BoardRecommend.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/BoardRecommend.java new file mode 100644 index 00000000..2192b65c --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/BoardRecommend.java @@ -0,0 +1,38 @@ +package kr.KWGraduate.BookPharmacy.domain.book.domain; + +import jakarta.persistence.*; +import kr.KWGraduate.BookPharmacy.domain.board.domain.Board; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class BoardRecommend { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "board_recommend_id") + private Long id; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "board_id") + @OnDelete(action = OnDeleteAction.CASCADE) + private Board board; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "book_id") + private Book book; + + private String keywords; + + @Builder + public BoardRecommend(Board board, Book book, String keywords){ + this.board = board; + this.book = book; + this.keywords = keywords; + } +} + diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/Book.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/Book.java index 2e5cfba6..8c8f3345 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/Book.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/Book.java @@ -46,6 +46,7 @@ public class Book { @JoinColumn(name = "middle_category_id") private Categories middleCategory; + @Builder public Book(String isbn, String title, String author, String publishingHouse, String publishYear, String content, int reviewNum, Categories bigCategory, Categories middleCategory, String imageUrl, int count) { diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/BookRecommend.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/BookRecommend.java new file mode 100644 index 00000000..e761a2d9 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/BookRecommend.java @@ -0,0 +1,30 @@ +package kr.KWGraduate.BookPharmacy.domain.book.domain; + +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class BookRecommend { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "book_recommend_id") + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "recommending_book_id") + private Book recommendingBook; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "recommended_book_id") + private Book recommendedBook; + + @Builder + public BookRecommend(Book recommendedBook, Book recommendingBook){ + this.recommendedBook = recommendedBook; + this.recommendingBook = recommendingBook; + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/ClientRecommend.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/ClientRecommend.java new file mode 100644 index 00000000..8f7e07a4 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/ClientRecommend.java @@ -0,0 +1,38 @@ +package kr.KWGraduate.BookPharmacy.domain.book.domain; + +import jakarta.persistence.*; +import kr.KWGraduate.BookPharmacy.domain.client.domain.Client; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class ClientRecommend { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "client_recommend_id") + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "client_id") + @OnDelete(action = OnDeleteAction.CASCADE) + private Client client; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "book_id") + private Book book; + + private Integer rank; + + @Builder + public ClientRecommend(Client client, Book book, Integer rank){ + this.client = client; + this.book = book; + this.rank = rank; + } + +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/NewBook.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/NewBook.java new file mode 100644 index 00000000..fe751820 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/domain/NewBook.java @@ -0,0 +1,20 @@ +package kr.KWGraduate.BookPharmacy.domain.book.domain; + +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; +import lombok.*; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class NewBook { + + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotNull + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "book_id") + private Book book; + +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/BestSellerBookDto.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/BestSellerBookDto.java new file mode 100644 index 00000000..801a6c73 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/BestSellerBookDto.java @@ -0,0 +1,25 @@ +package kr.KWGraduate.BookPharmacy.domain.book.dto.response; + +import kr.KWGraduate.BookPharmacy.domain.book.domain.BestSellerBook; +import kr.KWGraduate.BookPharmacy.domain.book.domain.Book; +import lombok.Builder; +import lombok.Data; + +@Data +public class BestSellerBookDto { + + private String isbn; + private String imageUrl; + private String title; + private String author; + + @Builder + public BestSellerBookDto(BestSellerBook bestSellerBook) { + Book book = bestSellerBook.getBook(); + + this.isbn = book.getIsbn(); + this.imageUrl = book.getImageUrl(); + this.title = book.getTitle(); + this.author = book.getAuthor(); + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/BoardBasedRecommendDto.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/BoardBasedRecommendDto.java new file mode 100644 index 00000000..35af24dd --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/BoardBasedRecommendDto.java @@ -0,0 +1,31 @@ +package kr.KWGraduate.BookPharmacy.domain.book.dto.response; + +import kr.KWGraduate.BookPharmacy.domain.book.domain.BoardRecommend; +import kr.KWGraduate.BookPharmacy.domain.book.domain.Book; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class BoardBasedRecommendDto { + private Long id; + private String isbn; + private String imageUrl; + private String title; + private String author; + private String[] keywords; + + @Builder + public BoardBasedRecommendDto(BoardRecommend boardRecommend){ + Book book = boardRecommend.getBook(); + + this.id = book.getId(); + this.isbn = book.getIsbn(); + this.imageUrl = book.getImageUrl(); + this.title = book.getTitle(); + this.author = book.getAuthor(); + + this.keywords = boardRecommend.getKeywords().split(" "); + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/BookBasedRecommendDto.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/BookBasedRecommendDto.java new file mode 100644 index 00000000..af740d13 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/BookBasedRecommendDto.java @@ -0,0 +1,27 @@ +package kr.KWGraduate.BookPharmacy.domain.book.dto.response; + +import kr.KWGraduate.BookPharmacy.domain.book.domain.Book; +import kr.KWGraduate.BookPharmacy.domain.book.domain.BookRecommend; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class BookBasedRecommendDto { + private Long id; + private String isbn; + private String imageUrl; + private String title; + private String author; + + @Builder + public BookBasedRecommendDto(BookRecommend bookRecommend){ + Book book = bookRecommend.getRecommendingBook(); + this.id = book.getId(); + this.isbn = book.getIsbn(); + this.imageUrl = book.getImageUrl(); + this.title = book.getTitle(); + this.author = book.getAuthor(); + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/ClientBasedRecommendDto.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/ClientBasedRecommendDto.java new file mode 100644 index 00000000..eeb93266 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/ClientBasedRecommendDto.java @@ -0,0 +1,27 @@ +package kr.KWGraduate.BookPharmacy.domain.book.dto.response; + +import kr.KWGraduate.BookPharmacy.domain.book.domain.Book; +import kr.KWGraduate.BookPharmacy.domain.book.domain.ClientRecommend; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class ClientBasedRecommendDto { + private Long id; + private String isbn; + private String imageUrl; + private String title; + private String author; + + @Builder + public ClientBasedRecommendDto(ClientRecommend clientRecommend){ + Book book = clientRecommend.getBook(); + this.id = book.getId(); + this.isbn = book.getIsbn(); + this.imageUrl = book.getImageUrl(); + this.title = book.getTitle(); + this. author = book.getAuthor(); + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/NewBookDto.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/NewBookDto.java new file mode 100644 index 00000000..78c8f749 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/NewBookDto.java @@ -0,0 +1,25 @@ +package kr.KWGraduate.BookPharmacy.domain.book.dto.response; + +import kr.KWGraduate.BookPharmacy.domain.book.domain.Book; +import kr.KWGraduate.BookPharmacy.domain.book.domain.NewBook; +import lombok.Builder; +import lombok.Data; + +@Data +public class NewBookDto { + + private String isbn; + private String imageUrl; + private String title; + private String author; + + @Builder + public NewBookDto(NewBook newBook) { + Book book = newBook.getBook(); + + this.isbn = book.getIsbn(); + this.imageUrl = book.getImageUrl(); + this.title = book.getTitle(); + this.author = book.getAuthor(); + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/ReadExperienceTop10Dto.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/ReadExperienceTop10Dto.java new file mode 100644 index 00000000..31c5c09f --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/dto/response/ReadExperienceTop10Dto.java @@ -0,0 +1,15 @@ +package kr.KWGraduate.BookPharmacy.domain.book.dto.response; + +import lombok.Data; + +@Data +public class ReadExperienceTop10Dto { + + private Long bookId; + private Long count; + + public ReadExperienceTop10Dto(Long bookId, Long count) { + this.bookId = bookId; + this.count = count; + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/BestSellerBookRepository.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/BestSellerBookRepository.java new file mode 100644 index 00000000..a6192d54 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/BestSellerBookRepository.java @@ -0,0 +1,15 @@ +package kr.KWGraduate.BookPharmacy.domain.book.repository; + +import kr.KWGraduate.BookPharmacy.domain.book.domain.BestSellerBook; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; + +public interface BestSellerBookRepository extends JpaRepository { + + @EntityGraph(attributePaths = {"book"}) + @Query("SELECT b FROM BestSellerBook b") + List findAllBestSeller(); +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/BoardRecommendRepository.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/BoardRecommendRepository.java new file mode 100644 index 00000000..5774c68d --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/BoardRecommendRepository.java @@ -0,0 +1,15 @@ +package kr.KWGraduate.BookPharmacy.domain.book.repository; + +import kr.KWGraduate.BookPharmacy.domain.board.repository.BoardRepository; +import kr.KWGraduate.BookPharmacy.domain.book.domain.BoardRecommend; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.Optional; + +public interface BoardRecommendRepository extends JpaRepository { + + @Query("select br from BoardRecommend br join fetch br.book b where br.board.id = :boardId") + Optional findByBoardBasedRecommend(@Param("boardId") Long boardId); +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/BookRecommendRepository.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/BookRecommendRepository.java new file mode 100644 index 00000000..c03a2dc8 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/BookRecommendRepository.java @@ -0,0 +1,15 @@ +package kr.KWGraduate.BookPharmacy.domain.book.repository; + +import kr.KWGraduate.BookPharmacy.domain.book.domain.Book; +import kr.KWGraduate.BookPharmacy.domain.book.domain.BookRecommend; +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 BookRecommendRepository extends JpaRepository { + + @Query("select br from BookRecommend br join fetch br.recommendingBook b join fetch br.recommendedBook rb where rb.isbn = :isbn") + List findByBookBasedRecommend(@Param("isbn") String isbn); +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/BookRepository.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/BookRepository.java index 6188b42a..4387c6b4 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/BookRepository.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/BookRepository.java @@ -21,18 +21,6 @@ public interface BookRepository extends JpaRepository { Optional findOptionalByIsbn(String isbn); - /** - * 키워드로 책 조회 - */ - @Query("select b from Book b join fetch b.bookKeywords bk join fetch bk.keywordItem k where k.name = :keyword") - List findByKeywordName(@Param("keyword") String keywordName); - - /** - * 중분류로 책 조회 - */ - @Query("select b from Book b join fetch b.middleCategory mc where mc.name = :categoryName") - List findByMiddleCategory(@Param("categoryName") String categoryName); - /** * 중분류로 책 조회 ( 페이징 ) */ @@ -44,21 +32,6 @@ public interface BookRepository extends JpaRepository { "from Book b join b.middleCategory mc where mc.name = :categoryName") Page findDtoBook10ListByMiddleCategory(@Param("categoryName") String categoryName, Pageable pageable); - /** - * 대분류로 책 조회 (대분류로 조회할 경우, 중분류와 함께 리스트로 출력하므로 fetch join을 걸었음) - * 다만, Map<중분류, List> 으로 나타내는 것을 DB조회에서 한번에 처리할지 or 조회 후 따로 처리할지 고민해봐야 할 듯 - */ - @Query("select b from Book b join fetch b.bigCategory bc join fetch b.middleCategory where bc.name = :categoryName") - List findByBigCategory(@Param("categoryName") String categoryName); - - /** - * 검색어로 제목에 대하여 책 조회 - * @param searchWord - * @return List - */ - @EntityGraph(attributePaths = {"bigCategory", "middleCategory"}) - List findByTitleContaining(String searchWord); - /** * 검색어로 제목에 대하여 책 조회 (페이징) * @param searchWord @@ -75,19 +48,9 @@ public interface BookRepository extends JpaRepository { @EntityGraph(attributePaths = {"bigCategory", "middleCategory"}) Page findPagingByAuthorContaining(String searchWord, Pageable pageable); - /** - * 검색어로 제목과 작가명에 대하여 책 조회 (페이징) - * @param searchWord - * @return Page - */ - @Query("SELECT b FROM Book b WHERE LOWER(b.title) LIKE %:searchWord% OR LOWER(b.author) LIKE %:searchWord%") - Page findPagingByTitleContainingOrAuthorContaining(@Param("searchWord") String searchWord, Pageable pageable); - - List findAllByIsbnIn(List isbn); - - - @Query("select b from Book b left join fetch b.bookKeywords bk left join fetch bk.keywordItem where b.isbn = :isbn") - Book findBookDetailWithKeywordByIsbn(String isbn); + @EntityGraph(attributePaths = {"bigCategory", "middleCategory"}) + @Query("select b from Book b left join b.bookKeywords bk join bk.keywordItem where b.isbn = :isbn") + Book findBookDetailWithKeywordByIsbn(@Param("isbn") String isbn); /** * 해당 키워드를 갖고 있는 책을 검색 (리스트) @@ -100,12 +63,12 @@ public interface BookRepository extends JpaRepository { Page findPagingByKeyword(@Param("keywordName") String keywordName, Pageable pageable); /** - * 제목에 대한 검색 OR 키워드에 대한 검색 (리스트) + * 제목 및 작가에 대한 검색 OR 키워드에 대한 검색 (리스트) * @param keywordNameList * @return */ @EntityGraph(attributePaths = {"bigCategory", "middleCategory"}) - @Query("select b from Book b join fetch b.bookKeywords bk join fetch bk.keywordItem ki " + + @Query("select b from Book b join b.bookKeywords bk inner join bk.keywordItem ki " + "where (LOWER(b.title) like %:searchWord% or LOWER(b.author) like %:searchWord%) and ki.name in :names") Page findPagingBySearchWordAndKeyword(@Param("searchWord") String searchWord, @Param("names") List keywordNameList, Pageable pageable); diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/ClientRecommendRepository.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/ClientRecommendRepository.java new file mode 100644 index 00000000..1f4a7e85 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/ClientRecommendRepository.java @@ -0,0 +1,17 @@ +package kr.KWGraduate.BookPharmacy.domain.book.repository; + +import kr.KWGraduate.BookPharmacy.domain.book.domain.Book; +import kr.KWGraduate.BookPharmacy.domain.book.domain.ClientRecommend; +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 ClientRecommendRepository extends JpaRepository { + @Query("select cr from ClientRecommend cr join fetch cr.book b where cr.client.id = :clientId and cr.rank >= 3") + List findByClientBasedRecommend(@Param("clientId") Long clientId); + + @Query("select cr from ClientRecommend cr join fetch cr.book b where cr.client.id = :clientId and cr.rank < 3") + List findByClientAiPrescription(@Param("clientId") Long clientId); +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/NewBookRepository.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/NewBookRepository.java new file mode 100644 index 00000000..5dea7650 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/repository/NewBookRepository.java @@ -0,0 +1,15 @@ +package kr.KWGraduate.BookPharmacy.domain.book.repository; + +import kr.KWGraduate.BookPharmacy.domain.book.domain.NewBook; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; + +public interface NewBookRepository extends JpaRepository { + + @EntityGraph(attributePaths = {"book"}) + @Query("SELECT b FROM NewBook b") + List findAllNewBooks(); +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/service/BestSellerBookService.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/service/BestSellerBookService.java new file mode 100644 index 00000000..54d0c542 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/service/BestSellerBookService.java @@ -0,0 +1,62 @@ +package kr.KWGraduate.BookPharmacy.domain.book.service; + +import kr.KWGraduate.BookPharmacy.domain.book.domain.BestSellerBook; +import kr.KWGraduate.BookPharmacy.domain.book.domain.Book; +import kr.KWGraduate.BookPharmacy.domain.book.dto.response.BestSellerBookDto; +import kr.KWGraduate.BookPharmacy.domain.book.dto.response.ReadExperienceTop10Dto; +import kr.KWGraduate.BookPharmacy.domain.book.repository.BestSellerBookRepository; +import kr.KWGraduate.BookPharmacy.domain.book.repository.BookRepository; +import kr.KWGraduate.BookPharmacy.domain.readexperience.repository.ReadExperienceRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class BestSellerBookService { + + private final BestSellerBookRepository bestSellerBookRepository; + private final ReadExperienceRepository readExperienceRepository; + private final BookRepository bookRepository; + + public List getBestSellerBookList() { + List allBestSeller = bestSellerBookRepository.findAllBestSeller(); + + List dtoList = allBestSeller.stream().map(book -> BestSellerBookDto.builder().bestSellerBook(book).build()) + .collect(Collectors.toList()); + + return dtoList; + } + + // 스프링 배치 프로그램으로 돌아감 + @Transactional + public void setBestSellerBooks() { + + // 사람들이 가장 많이 읽었던 책 10권을 가져옴 + PageRequest pageRequest = PageRequest.of(0, 10); + List top10ReadExperiences = readExperienceRepository.findTop10ReadExperiences(pageRequest); + + + // 상위 10권에 대하여 BestSellerBook 엔티티 리스트로 변환함. + List newBestSellerBooks = new ArrayList<>(); + for (ReadExperienceTop10Dto readExperienceTop10Dto : top10ReadExperiences ) { + Long bookId = readExperienceTop10Dto.getBookId(); + Book book = bookRepository.findById(bookId).get(); + + BestSellerBook bestSellerBook = BestSellerBook.builder().book(book).build(); + + newBestSellerBooks.add(bestSellerBook); + } + + // 기존 베스트셀러 목록을 지우고, 새로운 베스트셀러 목록을 저장함 + bestSellerBookRepository.deleteAll(); + bestSellerBookRepository.flush(); + bestSellerBookRepository.saveAll(newBestSellerBooks); + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/service/NewBookService.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/service/NewBookService.java new file mode 100644 index 00000000..f1856e52 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/service/NewBookService.java @@ -0,0 +1,27 @@ +package kr.KWGraduate.BookPharmacy.domain.book.service; + +import kr.KWGraduate.BookPharmacy.domain.book.domain.NewBook; +import kr.KWGraduate.BookPharmacy.domain.book.dto.response.NewBookDto; +import kr.KWGraduate.BookPharmacy.domain.book.repository.NewBookRepository; +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 NewBookService { + + private final NewBookRepository newBookRepository; + + public List getNewBookList() { + List allNewBooks = newBookRepository.findAllNewBooks(); + + List dtoList = allNewBooks.stream().map(book -> NewBookDto.builder().newBook(book).build()).collect(Collectors.toList()); + + return dtoList; + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/service/RecommendService.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/service/RecommendService.java new file mode 100644 index 00000000..0e1c6d07 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/book/service/RecommendService.java @@ -0,0 +1,52 @@ +package kr.KWGraduate.BookPharmacy.domain.book.service; + +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.client.domain.Client; +import kr.KWGraduate.BookPharmacy.domain.client.repository.ClientRepository; +import kr.KWGraduate.BookPharmacy.global.security.common.dto.AuthenticationAdapter; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class RecommendService { + private final BoardRecommendRepository boardRecommendRepository; + private final BookRecommendRepository bookRecommendRepository; + private final ClientRecommendRepository clientRecommendRepository; + private final ClientRepository clientRepository; + + public List getClientBasedAiPrescription(AuthenticationAdapter authentication){ + String username = authentication.getUsername(); + Client client = clientRepository.findByLoginId(username).get(); + + return clientRecommendRepository.findByClientAiPrescription(client.getId()).stream() + .map(ClientBasedRecommendDto::new) + .collect(Collectors.toList()); + } + public List getClientBasedRecommend(AuthenticationAdapter authentication){ + String username = authentication.getUsername(); + Client client = clientRepository.findByLoginId(username).get(); + + return clientRecommendRepository.findByClientBasedRecommend(client.getId()).stream() + .map(ClientBasedRecommendDto::new) + .collect(Collectors.toList()); + } + public BoardBasedRecommendDto getBoardBasedRecommend(Long boardId){ + return boardRecommendRepository.findByBoardBasedRecommend(boardId) + .map(BoardBasedRecommendDto::new) + .orElse(null); + } + public List getBookBasedRecommend(String isbn){ + return bookRecommendRepository.findByBookBasedRecommend(isbn).stream() + .map(BookBasedRecommendDto::new) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/client/api/UserController.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/client/api/UserController.java index 3554c9fc..d4468747 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/domain/client/api/UserController.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/client/api/UserController.java @@ -38,6 +38,13 @@ public ResponseEntity signup(@RequestBody ClientJoinDto clientJoinDto){ return ResponseEntity.ok("success"); } + @Operation(summary = "oauth 회원가입", description = "id, 비밀번호, 이메일, 이름 제외하고 받음") + @PostMapping("/signup/oauth") + public ResponseEntity signup(@RequestParam("email") String email, @RequestBody ClientOauthJoinDto clientOauthJoinDto){ + clientService.signUp(email,clientOauthJoinDto); + return ResponseEntity.ok("success"); + } + @Operation(summary = "아이디 중복확인", description = "false이면 사용가능한 아이디, true이면 중복") @GetMapping("/duplicate/username") public ResponseEntity isExistUsername(@RequestParam("username") String username){ diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/client/dto/request/ClientOauthJoinDto.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/client/dto/request/ClientOauthJoinDto.java new file mode 100644 index 00000000..7669d997 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/client/dto/request/ClientOauthJoinDto.java @@ -0,0 +1,43 @@ +package kr.KWGraduate.BookPharmacy.domain.client.dto.request; + +import kr.KWGraduate.BookPharmacy.domain.client.domain.Client; +import kr.KWGraduate.BookPharmacy.global.infra.redis.oauth2.Oauth2SignUpInfo; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDate; +import java.util.List; + +@Data +@NoArgsConstructor +public class ClientOauthJoinDto { + private String nickname; + private Client.Gender gender; + private String occupation; + private LocalDate birth; + private List interestList; + @Builder + public ClientOauthJoinDto(String nickname, Client.Gender gender, String occupation,LocalDate birth, List interestList) { + this.nickname = nickname; + this.gender = gender; + this.occupation = occupation; + this.birth = birth; + this.interestList = interestList; + } + public Client toEntity(Oauth2SignUpInfo oauth2SignUpInfo, Client.Occupation occupation, String password){ + return Client.builder() + .loginId(oauth2SignUpInfo.getProviderId()) + .password(password) + .name(oauth2SignUpInfo.getName()) + .nickname(nickname) + .email(oauth2SignUpInfo.getEmail()) + .gender(gender) + .occupation(occupation) + .birth(birth) + .role("ROLE_USER") + .passwordLength(9) + .description("안녕하세요! 책을 좋아하는 "+nickname+"입니다") + .build(); + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/client/service/ClientService.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/client/service/ClientService.java index 6497bcb0..84fd4e46 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/domain/client/service/ClientService.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/client/service/ClientService.java @@ -1,17 +1,16 @@ package kr.KWGraduate.BookPharmacy.domain.client.service; -import kr.KWGraduate.BookPharmacy.domain.client.dto.request.ClientNicknameDto; -import kr.KWGraduate.BookPharmacy.domain.client.dto.request.ClientPasswordUpdateDto; +import kr.KWGraduate.BookPharmacy.domain.client.dto.request.*; import kr.KWGraduate.BookPharmacy.domain.client.dto.response.ClientMainPageDto; import kr.KWGraduate.BookPharmacy.domain.client.exception.ExistEmailException; import kr.KWGraduate.BookPharmacy.domain.client.exception.ExistIdException; import kr.KWGraduate.BookPharmacy.domain.client.exception.ExistNicknameException; import kr.KWGraduate.BookPharmacy.domain.interest.repository.InterestRepository; import kr.KWGraduate.BookPharmacy.domain.interest.service.InterestService; +import kr.KWGraduate.BookPharmacy.global.infra.redis.oauth2.Oauth2SignUpInfo; +import kr.KWGraduate.BookPharmacy.global.infra.redis.oauth2.Oauth2SignUpService; import kr.KWGraduate.BookPharmacy.global.security.common.dto.AuthenticationAdapter; -import kr.KWGraduate.BookPharmacy.domain.client.dto.request.ClientJoinDto; import kr.KWGraduate.BookPharmacy.domain.client.dto.response.ClientMypageDto; -import kr.KWGraduate.BookPharmacy.domain.client.dto.request.ClientUpdateDto; import kr.KWGraduate.BookPharmacy.domain.client.domain.Client; import kr.KWGraduate.BookPharmacy.domain.client.repository.ClientRepository; import kr.KWGraduate.BookPharmacy.global.common.error.BusinessException; @@ -28,6 +27,7 @@ public class ClientService { private final BCryptPasswordEncoder bCryptPasswordEncoder; private final ClientOccupationMapService clientOccupationMapService; private final InterestService interestService; + private final Oauth2SignUpService oauth2SignUpService; @Transactional public void signUp(ClientJoinDto clientJoinDto) throws BusinessException { @@ -41,6 +41,20 @@ public void signUp(ClientJoinDto clientJoinDto) throws BusinessException { Client savedClient = clientRepository.save(client); interestService.updateInterest(clientJoinDto.getInterestList(), savedClient); } + @Transactional + public void signUp(String email, ClientOauthJoinDto clientOauthJoinDto){ + Oauth2SignUpInfo signUpInfo = oauth2SignUpService.getSignUpInfo(email); + String password = bCryptPasswordEncoder.encode(signUpInfo.getPassword()); + Client.Occupation occupation = clientOccupationMapService.getValue(clientOauthJoinDto.getOccupation()); + + Client client = clientOauthJoinDto.toEntity(signUpInfo, occupation, password); + validateDuplicateClient(client); + + Client savedClient = clientRepository.save(client); + interestService.updateInterest(clientOauthJoinDto.getInterestList(), savedClient); + + oauth2SignUpService.deleteInfo(email); + } private void validateDuplicateClient(Client client) { diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/api/OneLinePrescriptionController.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/api/OneLinePrescriptionController.java index 13b415f7..675021cd 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/api/OneLinePrescriptionController.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/api/OneLinePrescriptionController.java @@ -32,9 +32,12 @@ public class OneLinePrescriptionController { @Operation(summary = "모든 한줄처방 리스트를 페이징하여 요청", description = "page와 size를 입력받아 이를 반환") @GetMapping("/all") public ResponseEntity> getAllOneLinePrescriptions(@RequestParam(name = "page") int page, - @RequestParam(name = "size") int size) { + @RequestParam(name = "size") int size, + @AuthenticationPrincipal UserDetails userDetails) { + + PageRequest pageRequest = PageRequest.of(page, size, Sort.by("createdDate").descending()); - Page result = oneLinePrescriptionService.getAllOneLinePrescriptions(pageRequest); + Page result = oneLinePrescriptionService.getAllOneLinePrescriptions((AuthenticationAdapter) userDetails, pageRequest); return ResponseEntity.ok(result); } @@ -54,10 +57,11 @@ public ResponseEntity> getMyOneLinePrescriptions(@Reque @Operation(summary = "한줄처방 키워드 별 조회", description = "무한 스크롤을 위한 size와 page입력 필수, 키워드 입력") public ResponseEntity> getOneLinePrescriptionsByKeyword(@RequestParam(name = "keyword") Keyword keyword, @RequestParam("page") int page, - @RequestParam("size") int size) + @RequestParam("size") int size, + @AuthenticationPrincipal UserDetails userDetails) { PageRequest pageRequest = PageRequest.of(page,size, Sort.by("createdDate").descending()); - Page result = oneLinePrescriptionService.getOneLinePrescriptionsByKeyword(keyword, pageRequest); + Page result = oneLinePrescriptionService.getOneLinePrescriptionsByKeyword(keyword, (AuthenticationAdapter) userDetails, pageRequest); return ResponseEntity.ok(result); } @@ -66,10 +70,22 @@ public ResponseEntity> getOneLinePrescriptionsByKeyword @GetMapping(value = "/search") public ResponseEntity> getOneLinePrescriptionsBySearch(@RequestParam(name = "name") String searchWord, @RequestParam("page") int page, - @RequestParam("size") int size) + @RequestParam("size") int size, + @AuthenticationPrincipal UserDetails userDetails) { PageRequest pageRequest = PageRequest.of(page,size, Sort.by("createdDate").descending()); - Page result = oneLinePrescriptionService.getOneLinePrescriptionsBySearch(searchWord, pageRequest); + Page result = oneLinePrescriptionService.getOneLinePrescriptionsBySearch(searchWord, (AuthenticationAdapter) userDetails, pageRequest); + + return ResponseEntity.ok(result); + } + + @Operation(summary = "책에 대한 한줄처방 리스트 조회 ", description = "책에 대한 한줄처방 리스트를 5개 조회 (페이지, 사이즈 안받음)") + @GetMapping(value = "/book") + public ResponseEntity> getOneLinePrescriptionsByBook(@RequestParam(name = "isbn") String isbn, + @AuthenticationPrincipal UserDetails userDetails) { + PageRequest pageRequest = PageRequest.of(0, 5); + + Page result = oneLinePrescriptionService.getOneLinePrescriptionsByBook(isbn, (AuthenticationAdapter) userDetails, pageRequest); return ResponseEntity.ok(result); } @@ -95,8 +111,9 @@ public ResponseEntity createOneLinePrescription(@RequestBody OneLineCreate @Operation(summary = "한줄처방을 단건으로 조회할 때 요청") @GetMapping("/{prescriptionId}") - public ResponseEntity getOneLinePrescription(@PathVariable(value = "prescriptionId") Long prescriptionId) { - OneLineResponseDto result = oneLinePrescriptionService.getOneLinePrescription(prescriptionId); + public ResponseEntity getOneLinePrescription(@PathVariable(value = "prescriptionId") Long prescriptionId, + @AuthenticationPrincipal UserDetails userDetails) { + OneLineResponseDto result = oneLinePrescriptionService.getOneLinePrescription(prescriptionId, (AuthenticationAdapter) userDetails); return ResponseEntity.ok(result); } diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/dto/response/OneLineResponseDto.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/dto/response/OneLineResponseDto.java index e11f3539..7f7d8ea8 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/dto/response/OneLineResponseDto.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/dto/response/OneLineResponseDto.java @@ -24,11 +24,15 @@ public class OneLineResponseDto { private String bookPublishYear; private String bookPublishingHouse; private String clientNickname; + private boolean isLike; + private boolean isHelpful; + private long likeCount; + private long helpfulCount; private LocalDate createdDate; @Builder public OneLineResponseDto(Long id, String title, String description, Keyword keyword, String bookTitle, String bookIsbn, String bookAuthor, String bookImageUrl, - String bookPublishYear, String bookPublishingHouse) { + String bookPublishYear, String bookPublishingHouse, boolean isLike, boolean isHelpful, Integer likeCount, Integer helpfulCount) { this.id = id; this.title = title; this.description = description; @@ -39,6 +43,10 @@ public OneLineResponseDto(Long id, String title, String description, Keyword key this.bookImageUrl = bookImageUrl; this.bookPublishYear = bookPublishYear; this.bookPublishingHouse = bookPublishingHouse; + this.isLike = isLike; + this.isHelpful = isHelpful; + this.likeCount = likeCount; + this.helpfulCount = helpfulCount; } public OneLineResponseDto setAllAttr(Book book, Client client, OneLinePrescription oneLinePrescription) { @@ -75,4 +83,25 @@ private OneLineResponseDto setOneLinePrescriptionAttr(OneLinePrescription oneLin return this; } + + public OneLineResponseDto setIsLike(boolean like) { + isLike = like; + return this; + } + + public OneLineResponseDto setIsHelpful(boolean helpful) { + isHelpful = helpful; + return this; + } + + public OneLineResponseDto setLikeCount(long likeCount) { + this.likeCount = likeCount; + return this; + } + + public OneLineResponseDto setHelpfulCount(long helpfulCount) { + this.helpfulCount = helpfulCount; + return this; + } + } diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/repository/OneLineHelpfulEmotionRepository.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/repository/OneLineHelpfulEmotionRepository.java index bc75c8d5..3284099f 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/repository/OneLineHelpfulEmotionRepository.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/repository/OneLineHelpfulEmotionRepository.java @@ -17,4 +17,8 @@ public interface OneLineHelpfulEmotionRepository extends JpaRepository findByLoginIdAndOneLinePreId(@Param("loginId") String loginId, @Param("oneLineId") Long oneLineId); + + @Query("select count(oh) from OneLineHelpfulEmotion oh inner join oh.oneLinePrescription op where op.id = :oneLineId") + long findCountByOneLinePreId(@Param("oneLineId") Long oneLineId); + } diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/repository/OneLineLikeEmotionRepository.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/repository/OneLineLikeEmotionRepository.java index 02adad22..05049681 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/repository/OneLineLikeEmotionRepository.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/repository/OneLineLikeEmotionRepository.java @@ -17,4 +17,8 @@ public interface OneLineLikeEmotionRepository extends JpaRepository findByLoginIdAndOneLinePreId(@Param("loginId") String loginId, @Param("oneLineId") Long oneLineId); + + @Query("select count(ol) from OneLineLikeEmotion ol inner join ol.oneLinePrescription op where op.id = :oneLineId") + long findCountByOneLinePreId(@Param("oneLineId") Long oneLineId); + } diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/service/OneLinePrescriptionService.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/service/OneLinePrescriptionService.java index 0680d755..11927eb1 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/service/OneLinePrescriptionService.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/onelineprescription/service/OneLinePrescriptionService.java @@ -3,7 +3,8 @@ import kr.KWGraduate.BookPharmacy.domain.onelineprescription.dto.request.OneLineCreateDto; import kr.KWGraduate.BookPharmacy.domain.onelineprescription.dto.request.OneLineUpdateDto; import kr.KWGraduate.BookPharmacy.domain.onelineprescription.dto.response.OneLineResponseDto; -import kr.KWGraduate.BookPharmacy.domain.readexperience.service.ReadExperienceService; +import kr.KWGraduate.BookPharmacy.domain.onelineprescription.repository.OneLineHelpfulEmotionRepository; +import kr.KWGraduate.BookPharmacy.domain.onelineprescription.repository.OneLineLikeEmotionRepository; import kr.KWGraduate.BookPharmacy.global.security.common.dto.AuthenticationAdapter; import kr.KWGraduate.BookPharmacy.domain.book.domain.Book; import kr.KWGraduate.BookPharmacy.domain.client.domain.Client; @@ -24,6 +25,8 @@ public class OneLinePrescriptionService { private final OneLinePrescriptionRepository oneLinePrescriptionRepository; + private final OneLineLikeEmotionRepository oneLineLikeEmotionRepository; + private final OneLineHelpfulEmotionRepository oneLineHelpfulEmotionRepository; private final BookRepository bookRepository; private final ClientRepository clientRepository; @@ -72,42 +75,72 @@ public void deleteOneLinePrescription(Long oneLinePrescriptionId, Authentication client.setPrescriptionCount(client.getPrescriptionCount() - 1); } - public OneLineResponseDto getOneLinePrescription(Long oneLinePrescriptionId) { + public OneLineResponseDto getOneLinePrescription(Long oneLinePrescriptionId, AuthenticationAdapter authentication) { + String loginId = authentication.getUsername(); + OneLinePrescription oneLinePrescription = oneLinePrescriptionRepository.findOneLinePrescriptionById(oneLinePrescriptionId).get(); - OneLineResponseDto dto = new OneLineResponseDto(); - dto.setAllAttr(oneLinePrescription.getBook(), oneLinePrescription.getClient(), oneLinePrescription); + OneLineResponseDto dto = new OneLineResponseDto() + .setAllAttr(oneLinePrescription.getBook(), oneLinePrescription.getClient(), oneLinePrescription) + .setLikeCount(oneLineLikeEmotionRepository.findCountByOneLinePreId(oneLinePrescription.getId())) + .setHelpfulCount(oneLineHelpfulEmotionRepository.findCountByOneLinePreId(oneLinePrescription.getId())) + .setIsLike(oneLineLikeEmotionRepository.findByLoginIdAndOneLinePreId(loginId, oneLinePrescription.getId()).isPresent()) + .setIsHelpful(oneLineHelpfulEmotionRepository.findByLoginIdAndOneLinePreId(loginId, oneLinePrescription.getId()).isPresent()); return dto; } - public Page getAllOneLinePrescriptions(Pageable pageable) { + public Page getAllOneLinePrescriptions(AuthenticationAdapter authentication, Pageable pageable) { + String loginId = authentication.getUsername(); + Page pageResult = oneLinePrescriptionRepository.findPagingAll(pageable); Page dtoList = pageResult.map(oneLine -> new OneLineResponseDto() - .setAllAttr(oneLine.getBook(), oneLine.getClient(), oneLine)); + .setAllAttr(oneLine.getBook(), oneLine.getClient(), oneLine) + .setLikeCount(oneLineLikeEmotionRepository.findCountByOneLinePreId(oneLine.getId())) + .setHelpfulCount(oneLineHelpfulEmotionRepository.findCountByOneLinePreId(oneLine.getId())) + .setIsLike(oneLineLikeEmotionRepository.findByLoginIdAndOneLinePreId(loginId, oneLine.getId()).isPresent()) + .setIsHelpful(oneLineHelpfulEmotionRepository.findByLoginIdAndOneLinePreId(loginId, oneLine.getId()).isPresent())); return dtoList; } - public Page getOneLinePrescriptionsByKeyword(Keyword keyword, Pageable pageable) { + public Page getOneLinePrescriptionsByKeyword(Keyword keyword, AuthenticationAdapter authentication, Pageable pageable) { + String loginId = authentication.getUsername(); + Page pageResult = oneLinePrescriptionRepository.findByKeyword(keyword, pageable); Page dtoList = pageResult.map(oneLine -> new OneLineResponseDto() - .setAllAttr(oneLine.getBook(), oneLine.getClient(), oneLine)); + .setAllAttr(oneLine.getBook(), oneLine.getClient(), oneLine) + .setLikeCount(oneLineLikeEmotionRepository.findCountByOneLinePreId(oneLine.getId())) + .setHelpfulCount(oneLineHelpfulEmotionRepository.findCountByOneLinePreId(oneLine.getId())) + .setIsLike(oneLineLikeEmotionRepository.findByLoginIdAndOneLinePreId(loginId, oneLine.getId()).isPresent()) + .setIsHelpful(oneLineHelpfulEmotionRepository.findByLoginIdAndOneLinePreId(loginId, oneLine.getId()).isPresent())); return dtoList; } - public Page getOneLinePrescriptionsBySearch(String searchWord, Pageable pageable) { + public Page getOneLinePrescriptionsBySearch(String searchWord, AuthenticationAdapter authentication, Pageable pageable) { + String loginId = authentication.getUsername(); + Page pageResult = oneLinePrescriptionRepository.findByTitleContainingOrDescriptionContaining(searchWord, pageable); Page dtoList = pageResult.map(oneLine -> new OneLineResponseDto() - .setAllAttr(oneLine.getBook(), oneLine.getClient(), oneLine)); + .setAllAttr(oneLine.getBook(), oneLine.getClient(), oneLine) + .setLikeCount(oneLineLikeEmotionRepository.findCountByOneLinePreId(oneLine.getId())) + .setHelpfulCount(oneLineHelpfulEmotionRepository.findCountByOneLinePreId(oneLine.getId())) + .setIsLike(oneLineLikeEmotionRepository.findByLoginIdAndOneLinePreId(loginId, oneLine.getId()).isPresent()) + .setIsHelpful(oneLineHelpfulEmotionRepository.findByLoginIdAndOneLinePreId(loginId, oneLine.getId()).isPresent())); return dtoList; } - public Page getOneLinePrescriptionsByBook(String isbn, Pageable pageable) { + public Page getOneLinePrescriptionsByBook(String isbn, AuthenticationAdapter authentication, Pageable pageable) { + String loginId = authentication.getUsername(); + Page pageResult = oneLinePrescriptionRepository.findByBookIsbn(isbn, pageable); Page dtoList = pageResult.map(oneLine -> new OneLineResponseDto() - .setAllAttr(oneLine.getBook(), oneLine.getClient(), oneLine)); + .setAllAttr(oneLine.getBook(), oneLine.getClient(), oneLine) + .setLikeCount(oneLineLikeEmotionRepository.findCountByOneLinePreId(oneLine.getId())) + .setHelpfulCount(oneLineHelpfulEmotionRepository.findCountByOneLinePreId(oneLine.getId())) + .setIsLike(oneLineLikeEmotionRepository.findByLoginIdAndOneLinePreId(loginId, oneLine.getId()).isPresent()) + .setIsHelpful(oneLineHelpfulEmotionRepository.findByLoginIdAndOneLinePreId(loginId, oneLine.getId()).isPresent())); return dtoList; @@ -118,7 +151,11 @@ public Page getMyOneLinePrescriptions(AuthenticationAdapter Page pageResult = oneLinePrescriptionRepository.findByLoginId(loginId, pageable); Page dtoList = pageResult.map(oneLine -> new OneLineResponseDto() - .setAllAttr(oneLine.getBook(), oneLine.getClient(), oneLine)); + .setAllAttr(oneLine.getBook(), oneLine.getClient(), oneLine) + .setLikeCount(oneLineLikeEmotionRepository.findCountByOneLinePreId(oneLine.getId())) + .setHelpfulCount(oneLineHelpfulEmotionRepository.findCountByOneLinePreId(oneLine.getId())) + .setIsLike(oneLineLikeEmotionRepository.findByLoginIdAndOneLinePreId(loginId, oneLine.getId()).isPresent()) + .setIsHelpful(oneLineHelpfulEmotionRepository.findByLoginIdAndOneLinePreId(loginId, oneLine.getId()).isPresent())); return dtoList; } diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/prescription/domain/Prescription.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/prescription/domain/Prescription.java index 7864d9bc..2562cc20 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/domain/prescription/domain/Prescription.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/prescription/domain/Prescription.java @@ -23,6 +23,7 @@ public class Prescription extends BaseTimeEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "client_id") + @OnDelete(action = OnDeleteAction.CASCADE) private Client client; @ManyToOne(fetch = FetchType.LAZY) diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/readexperience/event/ReadExperienceUpdatedEvent.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/readexperience/event/ReadExperienceUpdatedEvent.java new file mode 100644 index 00000000..87502357 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/readexperience/event/ReadExperienceUpdatedEvent.java @@ -0,0 +1,13 @@ +package kr.KWGraduate.BookPharmacy.domain.readexperience.event; + +import lombok.Getter; +import org.springframework.context.ApplicationEvent; + +@Getter +public class ReadExperienceUpdatedEvent extends ApplicationEvent { + private final Long clientId; + public ReadExperienceUpdatedEvent(Object source, Long clientId) { + super(source); + this.clientId = clientId; + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/readexperience/repository/ReadExperienceRepository.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/readexperience/repository/ReadExperienceRepository.java index 136b65e5..57b1b114 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/domain/readexperience/repository/ReadExperienceRepository.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/readexperience/repository/ReadExperienceRepository.java @@ -1,5 +1,6 @@ package kr.KWGraduate.BookPharmacy.domain.readexperience.repository; +import kr.KWGraduate.BookPharmacy.domain.book.dto.response.ReadExperienceTop10Dto; import kr.KWGraduate.BookPharmacy.domain.readexperience.domain.ReadExperience; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -47,4 +48,11 @@ public interface ReadExperienceRepository extends JpaRepository findByBookIsbn(@Param("isbn") String bookIsbn); + /** + * 베스트셀러 주기적 업데이트를 위한 배치 프로세스에 의해 실행되는 코드 + * 유저들에게 가장 많이 읽힌 책 상위 10권에 대하여 (book_id, count)를 조회함 + * */ + @Query("SELECT new kr.KWGraduate.BookPharmacy.domain.book.dto.response.ReadExperienceTop10Dto(r.book.id, COUNT(r.book.id)) " + + "FROM ReadExperience r GROUP BY r.book.id ORDER BY COUNT(r.book.id) DESC") + List findTop10ReadExperiences(Pageable pageable); } diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/domain/readexperience/service/ReadExperienceService.java b/src/main/java/kr/KWGraduate/BookPharmacy/domain/readexperience/service/ReadExperienceService.java index 39668ab8..336fafa5 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/domain/readexperience/service/ReadExperienceService.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/domain/readexperience/service/ReadExperienceService.java @@ -3,6 +3,7 @@ import kr.KWGraduate.BookPharmacy.domain.readexperience.dto.request.ReadExperienceCreateDto; import kr.KWGraduate.BookPharmacy.domain.readexperience.dto.request.ReadExperienceUpdateRequestDto; import kr.KWGraduate.BookPharmacy.domain.readexperience.dto.response.ReadExperienceResponseDto; +import kr.KWGraduate.BookPharmacy.domain.readexperience.event.ReadExperienceUpdatedEvent; import kr.KWGraduate.BookPharmacy.global.security.common.dto.AuthenticationAdapter; import kr.KWGraduate.BookPharmacy.domain.book.domain.Book; import kr.KWGraduate.BookPharmacy.domain.client.domain.Client; @@ -11,6 +12,7 @@ import kr.KWGraduate.BookPharmacy.domain.client.repository.ClientRepository; import kr.KWGraduate.BookPharmacy.domain.readexperience.repository.ReadExperienceRepository; import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @@ -26,6 +28,7 @@ public class ReadExperienceService { private final ReadExperienceRepository readExperienceRepository; private final BookRepository bookRepository; private final ClientRepository clientRepository; + private final ApplicationEventPublisher applicationEventPublisher; /** * '독서 경험 수정하기' 모달창에서 사용되는 서비스 코드 @@ -54,6 +57,8 @@ public void updateReadExperience(ReadExperienceUpdateRequestDto readExperienceDT // 3. 2번에서 생성한 독서경험 리스트를 저장함 readExperienceRepository.saveAll(updatedList); + + applicationEventPublisher.publishEvent(new ReadExperienceUpdatedEvent(this,client.getId())); } /** diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/common/service/BookSchedulerService.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/common/service/BookSchedulerService.java new file mode 100644 index 00000000..a7ed903b --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/common/service/BookSchedulerService.java @@ -0,0 +1,20 @@ +package kr.KWGraduate.BookPharmacy.global.common.service; + +import kr.KWGraduate.BookPharmacy.domain.book.service.BestSellerBookService; +import lombok.RequiredArgsConstructor; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; + +@Service +@RequiredArgsConstructor +public class BookSchedulerService { + + private final BestSellerBookService bestSellerBookService; + + @Scheduled(cron = "0 0 0 * * *", zone = "Asia/Seoul") // 매일 서울기준, 00시 00분 00초에 실행 + public void setBestSeller() { + bestSellerBookService.setBestSellerBooks(); + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/config/SecurityConfig.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/config/SecurityConfig.java index d7eb2f14..0ad95c86 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/global/config/SecurityConfig.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/config/SecurityConfig.java @@ -8,7 +8,7 @@ import kr.KWGraduate.BookPharmacy.global.security.oauth.filter.Oauth2SuccessHandler; import kr.KWGraduate.BookPharmacy.global.security.auth.service.ClientDetailsService; import kr.KWGraduate.BookPharmacy.global.security.oauth.service.Oauth2ClientService; -import kr.KWGraduate.BookPharmacy.global.infra.redis.RefreshTokenService; +import kr.KWGraduate.BookPharmacy.global.infra.redis.refreshtoken.RefreshTokenService; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/fastapi/FastApiRequestListener.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/fastapi/FastApiRequestListener.java new file mode 100644 index 00000000..e79e5168 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/fastapi/FastApiRequestListener.java @@ -0,0 +1,45 @@ +package kr.KWGraduate.BookPharmacy.global.infra.fastapi; + +import kr.KWGraduate.BookPharmacy.domain.board.event.BoardUpdatedEvent; +import kr.KWGraduate.BookPharmacy.domain.readexperience.event.ReadExperienceUpdatedEvent; +import lombok.RequiredArgsConstructor; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import org.springframework.transaction.event.TransactionPhase; +import org.springframework.transaction.event.TransactionalEventListener; + +import java.io.IOException; +import java.util.concurrent.CompletableFuture; + +@Component +@RequiredArgsConstructor +public class FastApiRequestListener { + private final FastApiService fastApiService; + + @EventListener + @Async + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) + public void handleClientUpdatedEvent(ReadExperienceUpdatedEvent event) { + CompletableFuture.supplyAsync(() -> { + try { + return fastApiService.RecommendUpdate(FastApiService.RecommendType.Client, event.getClientId()); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + + @EventListener + @Async + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) + public void handleBoardUpdatedEvent(BoardUpdatedEvent event) { + CompletableFuture.supplyAsync(() -> { + try { + return fastApiService.RecommendUpdate(FastApiService.RecommendType.Board, event.getBoardId()); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/fastapi/FastApiService.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/fastapi/FastApiService.java new file mode 100644 index 00000000..2ca324f3 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/fastapi/FastApiService.java @@ -0,0 +1,52 @@ +package kr.KWGraduate.BookPharmacy.global.infra.fastapi; + +import com.nimbusds.jose.shaded.gson.JsonObject; +import com.nimbusds.jose.shaded.gson.JsonParser; +import org.springframework.stereotype.Service; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.ProtocolException; +import java.net.URL; + +@Service +public class FastApiService { + + public enum RecommendType{ + Board("board/"),Client("client/"),Book("book/"); + private final String urlPath; + private final String fastApi = "http://ec2-3-35-175-141.ap-northeast-2.compute.amazonaws.com:8000/"; + private final String localhost = "http://localhost:8000/"; + RecommendType(String urlPath){ + this.urlPath = urlPath; + } + public String getUrlPath(Long id){ + return fastApi + this.urlPath +Long.toString(id); + } + } + + public String RecommendUpdate(RecommendType type, Long id) throws IOException { + URL url = new URL(type.getUrlPath(id)); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + + connection.setRequestMethod("GET"); + + int responseCode = connection.getResponseCode(); + + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + StringBuffer stringBuffer = new StringBuffer(); + String inputLine; + + while ((inputLine = bufferedReader.readLine()) != null) { + stringBuffer.append(inputLine); + } + bufferedReader.close(); + + return stringBuffer.toString(); + } + + +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/oauth2/Oauth2SignUpInfo.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/oauth2/Oauth2SignUpInfo.java new file mode 100644 index 00000000..33a9c713 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/oauth2/Oauth2SignUpInfo.java @@ -0,0 +1,29 @@ +package kr.KWGraduate.BookPharmacy.global.infra.redis.oauth2; + +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import lombok.*; +import org.springframework.data.annotation.Id; +import org.springframework.data.redis.core.RedisHash; + +import java.util.UUID; + +@Getter +@RedisHash(value = "oauth2SignUpInfo",timeToLive = 3600) +@NoArgsConstructor +@EqualsAndHashCode +public class Oauth2SignUpInfo { + @Id + private String email; + private String name; + private String providerId; + private String password; + + @Builder + public Oauth2SignUpInfo(String email, String name, String providerId){ + this.email = email; + this.name = name; + this.providerId = providerId; + this.password = Integer.toString((email + name + providerId).hashCode()); + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/oauth2/Oauth2SignUpRepository.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/oauth2/Oauth2SignUpRepository.java new file mode 100644 index 00000000..cc54c6e1 --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/oauth2/Oauth2SignUpRepository.java @@ -0,0 +1,10 @@ +package kr.KWGraduate.BookPharmacy.global.infra.redis.oauth2; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +import java.util.UUID; + +@Repository +public interface Oauth2SignUpRepository extends CrudRepository { +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/oauth2/Oauth2SignUpService.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/oauth2/Oauth2SignUpService.java new file mode 100644 index 00000000..5d51e17d --- /dev/null +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/oauth2/Oauth2SignUpService.java @@ -0,0 +1,31 @@ +package kr.KWGraduate.BookPharmacy.global.infra.redis.oauth2; + +import kr.KWGraduate.BookPharmacy.domain.client.exception.NoExistIdException; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.UUID; + +@Service +@RequiredArgsConstructor +public class Oauth2SignUpService { + private final Oauth2SignUpRepository oauth2SignUpRepository; + + public void save(String providerId, String email, String name){ + Oauth2SignUpInfo info = Oauth2SignUpInfo.builder() + .email(email) + .name(name) + .providerId(providerId) + .build(); + oauth2SignUpRepository.save(info); + } + + public Oauth2SignUpInfo getSignUpInfo(String email){ + return oauth2SignUpRepository.findById(email).orElseThrow(() -> new NoExistIdException("there is no id")); + } + + public void deleteInfo(String email){ + oauth2SignUpRepository.deleteById(email); + } +} diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/RefreshToken.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/refreshtoken/RefreshToken.java similarity index 87% rename from src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/RefreshToken.java rename to src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/refreshtoken/RefreshToken.java index c68c8303..0ff50f27 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/RefreshToken.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/refreshtoken/RefreshToken.java @@ -1,4 +1,4 @@ -package kr.KWGraduate.BookPharmacy.global.infra.redis; +package kr.KWGraduate.BookPharmacy.global.infra.redis.refreshtoken; import lombok.*; import org.springframework.data.annotation.Id; diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/RefreshTokenRepository.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/refreshtoken/RefreshTokenRepository.java similarity index 76% rename from src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/RefreshTokenRepository.java rename to src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/refreshtoken/RefreshTokenRepository.java index 99f28fa8..3b0c6139 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/RefreshTokenRepository.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/refreshtoken/RefreshTokenRepository.java @@ -1,10 +1,8 @@ -package kr.KWGraduate.BookPharmacy.global.infra.redis; +package kr.KWGraduate.BookPharmacy.global.infra.redis.refreshtoken; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.Optional; - @Repository public interface RefreshTokenRepository extends CrudRepository { //Optional findByLoginId(String loginId); diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/RefreshTokenService.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/refreshtoken/RefreshTokenService.java similarity index 94% rename from src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/RefreshTokenService.java rename to src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/refreshtoken/RefreshTokenService.java index 10929aec..839a424d 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/RefreshTokenService.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/infra/redis/refreshtoken/RefreshTokenService.java @@ -1,4 +1,4 @@ -package kr.KWGraduate.BookPharmacy.global.infra.redis; +package kr.KWGraduate.BookPharmacy.global.infra.redis.refreshtoken; import kr.KWGraduate.BookPharmacy.global.security.common.dto.TokenDto; import kr.KWGraduate.BookPharmacy.domain.client.exception.NoExistIdException; diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/security/auth/filter/LoginFilter.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/security/auth/filter/LoginFilter.java index 3962f7d1..1f3749a6 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/global/security/auth/filter/LoginFilter.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/security/auth/filter/LoginFilter.java @@ -11,7 +11,7 @@ import kr.KWGraduate.BookPharmacy.global.security.common.dto.TokenDto; import kr.KWGraduate.BookPharmacy.global.common.error.BusinessException; import kr.KWGraduate.BookPharmacy.global.security.common.util.JWTUtil; -import kr.KWGraduate.BookPharmacy.global.infra.redis.RefreshTokenService; +import kr.KWGraduate.BookPharmacy.global.infra.redis.refreshtoken.RefreshTokenService; import org.springframework.http.HttpHeaders; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationServiceException; diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/security/common/filter/JWTFilter.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/security/common/filter/JWTFilter.java index 4d1c509e..1ccc4f4d 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/global/security/common/filter/JWTFilter.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/security/common/filter/JWTFilter.java @@ -7,11 +7,11 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import kr.KWGraduate.BookPharmacy.global.security.common.dto.TokenDto; -import kr.KWGraduate.BookPharmacy.global.infra.redis.RefreshToken; +import kr.KWGraduate.BookPharmacy.global.infra.redis.refreshtoken.RefreshToken; import kr.KWGraduate.BookPharmacy.global.security.common.util.CookieType; import kr.KWGraduate.BookPharmacy.global.security.common.util.JWTUtil; import kr.KWGraduate.BookPharmacy.global.security.auth.service.ClientDetailsService; -import kr.KWGraduate.BookPharmacy.global.infra.redis.RefreshTokenService; +import kr.KWGraduate.BookPharmacy.global.infra.redis.refreshtoken.RefreshTokenService; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpHeaders; import org.springframework.security.core.Authentication; diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/security/common/filter/LogoutService.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/security/common/filter/LogoutService.java index 2fb8e8e9..f7408d52 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/global/security/common/filter/LogoutService.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/security/common/filter/LogoutService.java @@ -1,19 +1,15 @@ package kr.KWGraduate.BookPharmacy.global.security.common.filter; -import io.jsonwebtoken.JwtException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import kr.KWGraduate.BookPharmacy.global.infra.redis.RefreshToken; +import kr.KWGraduate.BookPharmacy.global.infra.redis.refreshtoken.RefreshToken; import kr.KWGraduate.BookPharmacy.global.security.common.util.CookieType; import kr.KWGraduate.BookPharmacy.global.security.common.util.JWTUtil; -import kr.KWGraduate.BookPharmacy.global.infra.redis.RefreshTokenService; +import kr.KWGraduate.BookPharmacy.global.infra.redis.refreshtoken.RefreshTokenService; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.security.access.AccessDeniedException; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.stereotype.Service; -import org.springframework.web.servlet.HandlerExceptionResolver; @Service @RequiredArgsConstructor diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/security/common/util/JWTUtil.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/security/common/util/JWTUtil.java index 89f66966..3a655858 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/global/security/common/util/JWTUtil.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/security/common/util/JWTUtil.java @@ -7,9 +7,9 @@ import kr.KWGraduate.BookPharmacy.global.security.oauth.dto.CustomOauth2Client; import kr.KWGraduate.BookPharmacy.global.security.oauth.dto.Oauth2ClientDto; import kr.KWGraduate.BookPharmacy.global.security.common.dto.TokenDto; -import kr.KWGraduate.BookPharmacy.global.infra.redis.RefreshToken; +import kr.KWGraduate.BookPharmacy.global.infra.redis.refreshtoken.RefreshToken; import kr.KWGraduate.BookPharmacy.global.security.auth.service.ClientDetailsService; -import kr.KWGraduate.BookPharmacy.global.infra.redis.RefreshTokenService; +import kr.KWGraduate.BookPharmacy.global.infra.redis.refreshtoken.RefreshTokenService; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/security/oauth/dto/CustomOauth2Client.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/security/oauth/dto/CustomOauth2Client.java index 61215bec..668024ad 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/global/security/oauth/dto/CustomOauth2Client.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/security/oauth/dto/CustomOauth2Client.java @@ -43,4 +43,8 @@ public String getName() { public String getUsername(){ return oauth2ClientDto.getUsername(); } + + public String getEmail(){ return oauth2ClientDto.getEmail(); } + + public Boolean isExist(){ return oauth2ClientDto.getIsExist(); } } diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/security/oauth/dto/Oauth2ClientDto.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/security/oauth/dto/Oauth2ClientDto.java index c867e791..2ccb4293 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/global/security/oauth/dto/Oauth2ClientDto.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/security/oauth/dto/Oauth2ClientDto.java @@ -10,11 +10,15 @@ public class Oauth2ClientDto { private String username; private String name; private String role; + private String email; + private Boolean isExist; @Builder - public Oauth2ClientDto(String username, String name, String role) { + public Oauth2ClientDto(String username, String name, String role, String email, Boolean isExist) { this.username = username; this.name = name; this.role=role; + this.email = email; + this.isExist = isExist; } } diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/security/oauth/filter/Oauth2SuccessHandler.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/security/oauth/filter/Oauth2SuccessHandler.java index 830f61f7..991f98b1 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/global/security/oauth/filter/Oauth2SuccessHandler.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/security/oauth/filter/Oauth2SuccessHandler.java @@ -3,10 +3,11 @@ import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import kr.KWGraduate.BookPharmacy.global.infra.redis.oauth2.Oauth2SignUpService; import kr.KWGraduate.BookPharmacy.global.security.oauth.dto.CustomOauth2Client; import kr.KWGraduate.BookPharmacy.global.security.common.dto.TokenDto; import kr.KWGraduate.BookPharmacy.global.security.common.util.JWTUtil; -import kr.KWGraduate.BookPharmacy.global.infra.redis.RefreshTokenService; +import kr.KWGraduate.BookPharmacy.global.infra.redis.refreshtoken.RefreshTokenService; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpHeaders; import org.springframework.security.core.Authentication; @@ -18,7 +19,6 @@ import java.util.Collection; import java.util.Iterator; -import static kr.KWGraduate.BookPharmacy.global.config.Domain.*; import static kr.KWGraduate.BookPharmacy.global.security.common.util.CookieType.Authorization; import static kr.KWGraduate.BookPharmacy.global.security.common.util.CookieType.Refresh; @@ -27,6 +27,7 @@ public class Oauth2SuccessHandler extends SimpleUrlAuthenticationSuccessHandler { private final JWTUtil jwtUtil; private final RefreshTokenService refreshTokenService; + private final Oauth2SignUpService oauth2SignUpService; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { @@ -34,7 +35,8 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo CustomOauth2Client oauth2Client = (CustomOauth2Client) authentication.getPrincipal(); - System.out.println(oauth2Client); + String email = oauth2Client.getEmail(); + String name = oauth2Client.getName(); String username = oauth2Client.getUsername(); Collection authorities = oauth2Client.getAuthorities(); @@ -42,14 +44,23 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo GrantedAuthority auth = iterator.next(); String role = auth.getAuthority(); - TokenDto token = jwtUtil.createJwt(username, role,"true"); + if(oauth2Client.isExist()){ + TokenDto token = jwtUtil.createJwt(username, role,"true"); + + refreshTokenService.save(token,username); + response.addHeader(HttpHeaders.SET_COOKIE,Authorization.createCookie(token.getAccessToken())); + response.addHeader(HttpHeaders.SET_COOKIE, Refresh.createCookie(token.getRefreshToken())); + + response.sendRedirect("https://www.bookpharmacy.store/main"); +// response.sendRedirect("https://localhost:3000"); + }else{ + oauth2SignUpService.save(username,email,name); + + response.sendRedirect("https://www.bookpharmacy.store/signup/oauth?email="+email); +// response.sendRedirect("https://localhost:3000?email="+email); + } - refreshTokenService.save(token,username); - response.addHeader(HttpHeaders.SET_COOKIE,Authorization.createCookie(token.getAccessToken())); - response.addHeader(HttpHeaders.SET_COOKIE, Refresh.createCookie(token.getRefreshToken())); - response.getWriter().write("success"); - response.sendRedirect("https://www.bookpharmacy.store/signup/2"); } diff --git a/src/main/java/kr/KWGraduate/BookPharmacy/global/security/oauth/service/Oauth2ClientService.java b/src/main/java/kr/KWGraduate/BookPharmacy/global/security/oauth/service/Oauth2ClientService.java index 3fd20c99..3518220f 100644 --- a/src/main/java/kr/KWGraduate/BookPharmacy/global/security/oauth/service/Oauth2ClientService.java +++ b/src/main/java/kr/KWGraduate/BookPharmacy/global/security/oauth/service/Oauth2ClientService.java @@ -37,34 +37,27 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic String username = oauth2Response.getProvider() + " " + oauth2Response.getProviderId(); String name = oauth2Response.getName(); + String email = oauth2Response.getEmail(); - Oauth2ClientDto oauth2ClientDto = getOauth2ClientDto(username, name); + Oauth2ClientDto oauth2ClientDto = getOauth2ClientDto(username, name, email); return new CustomOauth2Client(oauth2ClientDto); } - private Oauth2ClientDto getOauth2ClientDto(String username, String name) { - Oauth2ClientDto oauth2ClientDto = clientRepository.findByLoginId(username) + private Oauth2ClientDto getOauth2ClientDto(String username, String name, String email){ + return clientRepository.findByLoginId(username) .map(client -> Oauth2ClientDto.builder() - .username(client.getLoginId()) - .name(client.getName()) - .role(client.getRole()) - .build()) - .orElseGet(() -> { - Client client = Client.builder() - .loginId(username) - .name(name) - .role("ROLE_USER") - .build(); - - clientRepository.save(client); - - return Oauth2ClientDto.builder() - .username(username) - .name(name) - .role("ROLE_USER") - .build(); - }); - return oauth2ClientDto; + .email(client.getEmail()) + .username(client.getLoginId()) + .name(client.getName()) + .role(client.getRole()) + .isExist(true) + .build()) + .orElseGet(() -> Oauth2ClientDto.builder() + .email(email) + .username(username) + .name(name) + .isExist(false) + .build()); } } diff --git a/src/test/java/kr/KWGraduate/BookPharmacy/global/infra/fastapi/FastApiServiceTest.java b/src/test/java/kr/KWGraduate/BookPharmacy/global/infra/fastapi/FastApiServiceTest.java new file mode 100644 index 00000000..f49cb61e --- /dev/null +++ b/src/test/java/kr/KWGraduate/BookPharmacy/global/infra/fastapi/FastApiServiceTest.java @@ -0,0 +1,23 @@ +package kr.KWGraduate.BookPharmacy.global.infra.fastapi; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +class FastApiServiceTest { + @Autowired + FastApiService fastApiService; + + @Test + void test() throws IOException { + System.out.println(fastApiService.RecommendUpdate(FastApiService.RecommendType.Board,167L)); + System.out.println(fastApiService.RecommendUpdate(FastApiService.RecommendType.Book,34039L)); + System.out.println(fastApiService.RecommendUpdate(FastApiService.RecommendType.Client,150L)); + + } +} \ No newline at end of file diff --git a/src/test/java/kr/KWGraduate/BookPharmacy/repository/BookRepositoryTest.java b/src/test/java/kr/KWGraduate/BookPharmacy/repository/BookRepositoryTest.java index 2d39d84d..9a96c5ba 100644 --- a/src/test/java/kr/KWGraduate/BookPharmacy/repository/BookRepositoryTest.java +++ b/src/test/java/kr/KWGraduate/BookPharmacy/repository/BookRepositoryTest.java @@ -59,29 +59,6 @@ public void saveBook(){ Assertions.assertEquals(savedBook1.getIsbn(), book1.getIsbn()); } - @Test - @DisplayName("대분류로 조회하기") - public void findByBigCategory() { - - //then - List bookListByCategory = bookRepository.findByBigCategory("IT/컴퓨터"); - - for (Book book : bookListByCategory) { - System.out.println("book = " + book); - } - } - - @Test - @DisplayName("중분류로 조회하기") - public void findByMiddleCategory() { - - //then - List bookListByCategory = bookRepository.findByMiddleCategory("Java"); - - for (Book book : bookListByCategory) { - System.out.println("book = " + book); - } - } @Test @DisplayName("중분류로 조회하기(페이징)") @@ -106,15 +83,6 @@ public void findByName() { } } - @Test - @DisplayName("제목에 검색어를 포함하는 경우 조회하기") - public void findBySearchKeyword() { - List bookList = bookRepository.findByTitleContaining("자바"); - - for (Book book : bookList) { - System.out.println("book = " + book); - } - } @Test @DisplayName("제목 AND 키워드에 대해 조회하기") diff --git a/src/test/java/kr/KWGraduate/BookPharmacy/repository/OneLinePrescriptionRepositoryTest.java b/src/test/java/kr/KWGraduate/BookPharmacy/repository/OneLinePrescriptionRepositoryTest.java index 67ddf54a..afac75f4 100644 --- a/src/test/java/kr/KWGraduate/BookPharmacy/repository/OneLinePrescriptionRepositoryTest.java +++ b/src/test/java/kr/KWGraduate/BookPharmacy/repository/OneLinePrescriptionRepositoryTest.java @@ -6,11 +6,13 @@ import kr.KWGraduate.BookPharmacy.domain.client.repository.ClientRepository; import kr.KWGraduate.BookPharmacy.domain.keyword.domain.Keyword; import kr.KWGraduate.BookPharmacy.domain.onelineprescription.domain.OneLinePrescription; +import kr.KWGraduate.BookPharmacy.domain.onelineprescription.repository.OneLineLikeEmotionRepository; import kr.KWGraduate.BookPharmacy.domain.onelineprescription.repository.OneLinePrescriptionRepository; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.transaction.annotation.Transactional; @@ -24,6 +26,8 @@ class OneLinePrescriptionRepositoryTest { @Autowired OneLinePrescriptionRepository oneLinePrescriptionRepository; + @Autowired + OneLineLikeEmotionRepository oneLineLikeEmotionRepository; @Autowired ClientRepository clientRepository; @Autowired BookRepository bookRepository; @@ -121,7 +125,9 @@ class OneLinePrescriptionRepositoryTest { @Test void 책의_isbn으로_한줄처방_조회() { - List result = oneLinePrescriptionRepository.findByBookIsbn("1234"); + PageRequest pageRequest = PageRequest.of(0, 8); + + List result = oneLinePrescriptionRepository.findByBookIsbn("1234", pageRequest).getContent(); assertThat(3).isEqualTo(result.size()); } @@ -130,4 +136,11 @@ class OneLinePrescriptionRepositoryTest { // List result = oneLinePrescriptionRepository.findByKeyword(Keyword.Economy_Management, Pageable ); // assertThat(5).isEqualTo(result.size()); } + + @Test + void 책의_Id로_한줄처방_조회() { + long countByOneLinePreId = oneLineLikeEmotionRepository.findCountByOneLinePreId(148L); + + System.out.println(countByOneLinePreId); + } } \ No newline at end of file diff --git a/src/test/java/kr/KWGraduate/BookPharmacy/repository/RecommendRepositoryTest.java b/src/test/java/kr/KWGraduate/BookPharmacy/repository/RecommendRepositoryTest.java new file mode 100644 index 00000000..a6e936a4 --- /dev/null +++ b/src/test/java/kr/KWGraduate/BookPharmacy/repository/RecommendRepositoryTest.java @@ -0,0 +1,193 @@ +package kr.KWGraduate.BookPharmacy.repository; + +import kr.KWGraduate.BookPharmacy.domain.board.domain.Board; +import kr.KWGraduate.BookPharmacy.domain.board.repository.BoardRepository; +import kr.KWGraduate.BookPharmacy.domain.book.domain.BoardRecommend; +import kr.KWGraduate.BookPharmacy.domain.book.domain.Book; +import kr.KWGraduate.BookPharmacy.domain.book.domain.BookRecommend; +import kr.KWGraduate.BookPharmacy.domain.book.domain.ClientRecommend; +import kr.KWGraduate.BookPharmacy.domain.book.repository.*; +import kr.KWGraduate.BookPharmacy.domain.client.domain.Client; +import kr.KWGraduate.BookPharmacy.domain.client.repository.ClientRepository; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.test.annotation.Rollback; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.LongStream; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +@Transactional +public class RecommendRepositoryTest { + + + @Autowired + BookRepository bookRepository; + @Autowired + ClientRepository clientRepository; + @Autowired + BookRecommendRepository bookRecommendRepository; + @Autowired + BoardRecommendRepository boardRecommendRepository; + @Autowired + ClientRecommendRepository clientRecommendRepository; + @Autowired + BoardRepository boardRepository; + + + @Test + @DisplayName("연관된 책 기반 추천 책 조회하기") + @Rollback(value = false) + public void findByBookbased(){ + Book recommendedBook = bookRepository.findById(1L).get(); + + List books = LongStream.rangeClosed(2, 11) + .boxed() + .map(l -> bookRepository.findById(l).get()) + .collect(Collectors.toList()); + + List brList = new ArrayList<>(); + for (Book recommendingBook : books) { + BookRecommend bookRecommend = BookRecommend.builder() + .recommendedBook(recommendedBook) + .recommendingBook(recommendingBook) + .build(); + brList.add(bookRecommendRepository.save(bookRecommend)); + } + + assertThat(bookRecommendRepository.count()).isEqualTo(10); + assertThat(bookRecommendRepository.findByBookBasedRecommend(recommendedBook.getIsbn())).containsAll(brList); + + } + @Test + @DisplayName("비슷한 유저가 읽은 책 추천 조회하기") + @Rollback(value = false) + public void findByClientbased(){ + Client client = clientRepository.findById(1L).get(); + System.out.println(client); + + List books = LongStream.rangeClosed(2, 14) + .boxed() + .map(l -> bookRepository.findById(l).get()) + .collect(Collectors.toList()); + + List aiPrescription = new ArrayList<>(); + List clientBasedRecommend = new ArrayList<>(); + + int rank=0; + for(Book bookRecommend : books) { + ClientRecommend clientRecommend = ClientRecommend + .builder() + .client(client) + .book(bookRecommend) + .rank(rank++) + .build(); + + if(rank < 4){ + aiPrescription.add(clientRecommendRepository.save(clientRecommend)); + }else{ + clientBasedRecommend.add(clientRecommendRepository.save(clientRecommend)); + } + } + + + + assertThat(clientRecommendRepository.count()).isEqualTo(13); + assertThat(clientRecommendRepository.findByClientBasedRecommend(1L)).containsAll(clientBasedRecommend); + assertThat(clientRecommendRepository.findByClientAiPrescription(1L)).containsAll(aiPrescription); + } + + @Test + @DisplayName("고민게시판 책 추천 unique값 확인") + public void isBoardUnique(){ + Board board1 = boardRepository.findById(173L).get(); + + + Book book1 = bookRepository.findById(1L).get(); + Book book2 = bookRepository.findById(2L).get(); + + BoardRecommend boardRecommend1 = BoardRecommend + .builder() + .board(board1) + .book(book1) + .build(); + boardRecommendRepository.save(boardRecommend1); + + + BoardRecommend boardRecommend2 = BoardRecommend + .builder() + .board(board1) + .book(book2) + .build(); + + Assertions.assertThrowsExactly(DataIntegrityViolationException.class, () ->{ + boardRecommendRepository.save(boardRecommend2); + }); + + + } + + @Test + @DisplayName("고민 게시판 책 추천 조회") + @Rollback(value = false) + public void findBoardbased(){ + Board board1 = boardRepository.findById(167L).get(); + Board board2 = boardRepository.findById(168L).get(); + Board board3 = boardRepository.findById(169L).get(); + Board board4 = boardRepository.findById(170L).get(); + + Book book1 = bookRepository.findById(1L).get(); + Book book2 = bookRepository.findById(2L).get(); + + BoardRecommend boardRecommend1 = BoardRecommend + .builder() + .board(board1) + .book(book1) + .keywords("한국 영어 일본어") + .build(); + BoardRecommend save1 = boardRecommendRepository.save(boardRecommend1); + + + BoardRecommend boardRecommend2 = BoardRecommend + .builder() + .board(board2) + .book(book2) + .keywords("자바 연애 컴퓨터") + .build(); + BoardRecommend save2 = boardRecommendRepository.save(boardRecommend2); + + BoardRecommend boardRecommend3 = BoardRecommend + .builder() + .board(board3) + .book(book1) + .keywords("한국 영어 일본어") + .build(); + BoardRecommend save3 = boardRecommendRepository.save(boardRecommend3); + + BoardRecommend boardRecommend4 = BoardRecommend + .builder() + .board(board4) + .book(book2) + .keywords("자바 연애 컴퓨터") + .build(); + BoardRecommend save4 = boardRecommendRepository.save(boardRecommend4); + + assertThat(boardRecommendRepository.count()).isEqualTo(4); + assertThat(boardRecommendRepository.findByBoardBasedRecommend(167L).get()).isEqualTo(save1); + assertThat(boardRecommendRepository.findByBoardBasedRecommend(168L).get()).isEqualTo(save2); + assertThat(boardRecommendRepository.findByBoardBasedRecommend(169L).get()).isEqualTo(save3); + assertThat(boardRecommendRepository.findByBoardBasedRecommend(170L).get()).isEqualTo(save4); + + + } + +} diff --git a/src/test/java/kr/KWGraduate/BookPharmacy/service/BestSellerBookServiceTest.java b/src/test/java/kr/KWGraduate/BookPharmacy/service/BestSellerBookServiceTest.java new file mode 100644 index 00000000..b72b9a72 --- /dev/null +++ b/src/test/java/kr/KWGraduate/BookPharmacy/service/BestSellerBookServiceTest.java @@ -0,0 +1,32 @@ +package kr.KWGraduate.BookPharmacy.service; + +import kr.KWGraduate.BookPharmacy.domain.book.dto.response.BestSellerBookDto; +import kr.KWGraduate.BookPharmacy.domain.book.service.BestSellerBookService; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +import static org.assertj.core.api.Assertions.*; + +@SpringBootTest +@Transactional +class BestSellerBookServiceTest { + + @Autowired + BestSellerBookService bestSellerBookService; + + @Test + void getBestSellerBooks() { + List bestSellerBooks = bestSellerBookService.getBestSellerBookList(); + + assertThat(bestSellerBooks.size()).isEqualTo(10); + } + + @Test + void setBestSellerBooks() { + bestSellerBookService.setBestSellerBooks(); + } +} \ No newline at end of file diff --git a/src/test/java/kr/KWGraduate/BookPharmacy/service/OneLinePrescriptionServiceTest.java b/src/test/java/kr/KWGraduate/BookPharmacy/service/OneLinePrescriptionServiceTest.java index 010c149f..8315b12f 100644 --- a/src/test/java/kr/KWGraduate/BookPharmacy/service/OneLinePrescriptionServiceTest.java +++ b/src/test/java/kr/KWGraduate/BookPharmacy/service/OneLinePrescriptionServiceTest.java @@ -16,6 +16,8 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; import org.springframework.transaction.annotation.Transactional; import java.util.List; @@ -79,7 +81,9 @@ void updateOneLinePrescription() { Client client = clientRepository.findByLoginId("kw_lsh_3717").get(); ClientDetails userDetails = new ClientDetails(client); - OneLinePrescription oneLinePrescription = oneLinePrescriptionRepository.findByBookIsbn("1234").get(0); + PageRequest pageRequest = PageRequest.of(0, 8); + + OneLinePrescription oneLinePrescription = oneLinePrescriptionRepository.findByBookIsbn("1234", pageRequest).getContent().get(0); Long savedId = oneLinePrescription.getId(); em.clear(); @@ -91,12 +95,12 @@ void updateOneLinePrescription() { .description("이게 진짜임") .build(); - System.out.println("----------------------------"); + // then oneLinePrescriptionService.updateOneLinePrescription(savedId, oneLineUpdateDto, userDetails); em.flush(); - OneLinePrescription result = oneLinePrescriptionRepository.findByBookIsbn("0001").get(0); + OneLinePrescription result = oneLinePrescriptionRepository.findByBookIsbn("0001", pageRequest).getContent().get(0); assertThat(result.getTitle()).isEqualTo("컴공 4학년에게 추천"); assertThat(result.getDescription()).isEqualTo("이게 진짜임"); @@ -109,16 +113,18 @@ void deleteOneLinePrescription() { Client client = clientRepository.findByLoginId("kw_lsh_3717").get(); ClientDetails userDetails = new ClientDetails(client); - OneLinePrescription oneLinePrescription = oneLinePrescriptionRepository.findByBookIsbn("1234").get(0); + PageRequest pageRequest = PageRequest.of(0, 8); + + OneLinePrescription oneLinePrescription = oneLinePrescriptionRepository.findByBookIsbn("1234", pageRequest).getContent().get(0); Long id = oneLinePrescription.getId(); //when oneLinePrescriptionService.deleteOneLinePrescription(id, userDetails); em.flush(); - List result = oneLinePrescriptionRepository.findByBookIsbn("1234"); + List result = oneLinePrescriptionRepository.findByBookIsbn("1234", pageRequest).getContent(); // then assertThat(result.size()).isEqualTo(0); } -} \ No newline at end of file +} diff --git a/src/test/java/kr/KWGraduate/BookPharmacy/service/RecommendServiceTest.java b/src/test/java/kr/KWGraduate/BookPharmacy/service/RecommendServiceTest.java new file mode 100644 index 00000000..4504713b --- /dev/null +++ b/src/test/java/kr/KWGraduate/BookPharmacy/service/RecommendServiceTest.java @@ -0,0 +1,160 @@ +package kr.KWGraduate.BookPharmacy.service; + +import kr.KWGraduate.BookPharmacy.domain.board.domain.Board; +import kr.KWGraduate.BookPharmacy.domain.board.repository.BoardRepository; +import kr.KWGraduate.BookPharmacy.domain.book.domain.BoardRecommend; +import kr.KWGraduate.BookPharmacy.domain.book.domain.Book; +import kr.KWGraduate.BookPharmacy.domain.book.domain.BookRecommend; +import kr.KWGraduate.BookPharmacy.domain.book.domain.ClientRecommend; +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.BookRepository; +import kr.KWGraduate.BookPharmacy.domain.book.repository.ClientRecommendRepository; +import kr.KWGraduate.BookPharmacy.domain.book.service.RecommendService; +import kr.KWGraduate.BookPharmacy.domain.client.domain.Client; +import kr.KWGraduate.BookPharmacy.domain.client.repository.ClientRepository; +import kr.KWGraduate.BookPharmacy.global.security.auth.dto.ClientDetails; +import kr.KWGraduate.BookPharmacy.global.security.common.dto.AuthenticationAdapter; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.LongStream; + +@SpringBootTest +@Transactional +public class RecommendServiceTest { + @Autowired + private RecommendService recommendService; + + @Autowired + BookRepository bookRepository; + @Autowired + ClientRepository clientRepository; + @Autowired + BookRecommendRepository bookRecommendRepository; + @Autowired + BoardRecommendRepository boardRecommendRepository; + @Autowired + ClientRecommendRepository clientRecommendRepository; + @Autowired + BoardRepository boardRepository; + + @Test + @DisplayName("client관련 추천 테스트") + public void clientBasedRecommend(){ + + Client client = clientRepository.findById(1L).get(); + System.out.println(client); + + List books = LongStream.rangeClosed(2, 14) + .boxed() + .map(l -> bookRepository.findById(l).get()) + .collect(Collectors.toList()); + + int rank=0; + for(Book bookRecommend : books) { + ClientRecommend clientRecommend = ClientRecommend + .builder() + .client(client) + .book(bookRecommend) + .rank(rank++) + .build(); + + clientRecommendRepository.save(clientRecommend); + } + + ClientDetails userDetails = new ClientDetails(client); + + Assertions.assertThat(recommendService.getClientBasedAiPrescription(userDetails).size()).isEqualTo(3); + Assertions.assertThat(recommendService.getClientBasedRecommend(userDetails).size()).isEqualTo(10); + + } + @Test + @DisplayName("book관련 추천 테스트") + public void bookBasedRecommend(){ + + Book recommendedBook = bookRepository.findById(1L).get(); + String isbn = recommendedBook.getIsbn(); + + List books = LongStream.rangeClosed(2, 11) + .boxed() + .map(l -> bookRepository.findById(l).get()) + .collect(Collectors.toList()); + + for (Book recommendingBook : books) { + BookRecommend bookRecommend = BookRecommend.builder() + .recommendedBook(recommendedBook) + .recommendingBook(recommendingBook) + .build(); + bookRecommendRepository.save(bookRecommend); + } + + Assertions.assertThat(recommendService.getBookBasedRecommend(isbn).size()).isEqualTo(10); + + } + @Test + @DisplayName("board관련 추천 테스트") + public void boardBasedRecommend(){ + Board board1 = boardRepository.findById(167L).get(); + Board board2 = boardRepository.findById(168L).get(); + Board board3 = boardRepository.findById(169L).get(); + Board board4 = boardRepository.findById(170L).get(); + + Book book1 = bookRepository.findById(1L).get(); + Book book2 = bookRepository.findById(2L).get(); + + BoardRecommend boardRecommend1 = BoardRecommend + .builder() + .board(board1) + .book(book1) + .keywords("한국 영어 일본어") + .build(); + BoardRecommend save1 = boardRecommendRepository.save(boardRecommend1); + + + BoardRecommend boardRecommend2 = BoardRecommend + .builder() + .board(board2) + .book(book2) + .keywords("자바 연애 컴퓨터") + .build(); + BoardRecommend save2 = boardRecommendRepository.save(boardRecommend2); + + BoardRecommend boardRecommend3 = BoardRecommend + .builder() + .board(board3) + .book(book1) + .keywords("한국 영어 일본어") + .build(); + BoardRecommend save3 = boardRecommendRepository.save(boardRecommend3); + + BoardRecommend boardRecommend4 = BoardRecommend + .builder() + .board(board4) + .book(book2) + .keywords("자바 연애 컴퓨터") + .build(); + BoardRecommend save4 = boardRecommendRepository.save(boardRecommend4); + + BoardBasedRecommendDto dto1 = new BoardBasedRecommendDto(save1); + BoardBasedRecommendDto dto2 = new BoardBasedRecommendDto(save2); + BoardBasedRecommendDto dto3 = new BoardBasedRecommendDto(save3); + BoardBasedRecommendDto dto4 = new BoardBasedRecommendDto(save4); + + Assertions.assertThat(recommendService.getBoardBasedRecommend(167L)).isEqualTo(dto1); + Assertions.assertThat(recommendService.getBoardBasedRecommend(168L)).isEqualTo(dto2); + Assertions.assertThat(recommendService.getBoardBasedRecommend(169L)).isEqualTo(dto3); + Assertions.assertThat(recommendService.getBoardBasedRecommend(170L)).isEqualTo(dto4); + + } +}