Skip to content

Commit 1e9a234

Browse files
authored
Merge pull request #156 from prgrms-web-devcourse/feature/book-recent-search
[#155]์ตœ๊ทผ ๋„์„œ ๊ฒ€์ƒ‰์–ด ๊ธฐ๋Šฅ ๊ตฌํ˜„
2 parents 5d4fba9 + 911f514 commit 1e9a234

26 files changed

+445
-100
lines changed

โ€Žsrc/docs/asciidoc/index.adoc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,29 @@ include::{snippets}/book-controller-slice-test/find-book_success/http-response.a
451451

452452
include::{snippets}/book-controller-slice-test/find-book_success/response-fields.adoc[]
453453

454+
=== ์ตœ๊ทผ ์ฑ… ๊ฒ€์ƒ‰์–ด
455+
456+
==== Request
457+
458+
include::{snippets}/book-controller-slice-test/test-find-recent-query/http-request.adoc[]
459+
460+
==== Request Param
461+
462+
include::{snippets}/book-controller-slice-test/test-find-recent-query/request-parameters.adoc[]
463+
464+
==== Request Header
465+
466+
include::{snippets}/book-controller-slice-test/test-find-recent-query/request-headers.adoc[]
467+
468+
==== Response
469+
470+
include::{snippets}/book-controller-slice-test/test-find-recent-query/http-response.adoc[]
471+
472+
==== Response fields
473+
474+
include::{snippets}/book-controller-slice-test/test-find-recent-query/response-fields.adoc[]
475+
476+
454477
=== ์ฑ… ์ƒ์„ธ ์ •๋ณด
455478

456479
==== Request

โ€Žsrc/main/java/com/dadok/gaerval/domain/book/api/BookController.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
1919

2020
import com.dadok.gaerval.domain.book.dto.request.BookCreateRequest;
21+
import com.dadok.gaerval.domain.book.dto.request.BookRecentSearchRequest;
2122
import com.dadok.gaerval.domain.book.dto.request.BookSearchRequest;
2223
import com.dadok.gaerval.domain.book.dto.request.SuggestionsBookFindRequest;
2324
import com.dadok.gaerval.domain.book.dto.response.BookIdResponse;
25+
import com.dadok.gaerval.domain.book.dto.response.BookRecentSearchResponses;
2426
import com.dadok.gaerval.domain.book.dto.response.BookResponse;
2527
import com.dadok.gaerval.domain.book.dto.response.BookResponses;
2628
import com.dadok.gaerval.domain.book.dto.response.SuggestionsBookFindResponses;
@@ -52,8 +54,27 @@ public class BookController {
5254
@GetMapping(produces = APPLICATION_JSON_VALUE)
5355
@PreAuthorize(value = "hasAnyRole('ROLE_ADMIN', 'ROLE_USER','ROLE_ANONYMOUS')")
5456
@LogHttpRequests
55-
public ResponseEntity<BookResponses> findBooksByQuery(@ModelAttribute @Valid BookSearchRequest bookSearchRequest) {
56-
return ResponseEntity.ok().body(bookService.findAllByKeyword(bookSearchRequest));
57+
public ResponseEntity<BookResponses> findBooksByQuery(@ModelAttribute @Valid BookSearchRequest bookSearchRequest,
58+
@CurrentUserPrincipal UserPrincipal userPrincipal) {
59+
return ResponseEntity.ok().body(bookService.findAllByKeyword(bookSearchRequest, userPrincipal.getUserId()));
60+
}
61+
62+
/**
63+
* <pre>
64+
* ์‚ฌ์šฉ์ž์˜ ์ตœ๊ทผ ๊ฒ€์ƒ‰์–ด ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜จ๋‹ค.
65+
* </pre>
66+
*
67+
* @param bookRecentSearchRequest ๊ฐ€์ ธ์˜ฌ ๊ฒ€์ƒ‰์–ด ๊ฐœ์ˆ˜
68+
* @return status : ok
69+
*/
70+
@GetMapping(value = "/recent-searches", produces = APPLICATION_JSON_VALUE)
71+
@PreAuthorize(value = "hasAnyRole('ROLE_ADMIN', 'ROLE_USER','ROLE_ANONYMOUS')")
72+
@LogHttpRequests
73+
public ResponseEntity<BookRecentSearchResponses> findRecentQuery(
74+
@ModelAttribute @Valid BookRecentSearchRequest bookRecentSearchRequest,
75+
@CurrentUserPrincipal UserPrincipal userPrincipal) {
76+
return ResponseEntity.ok()
77+
.body(bookService.findKeywordsByUserId(userPrincipal.getUserId(), bookRecentSearchRequest.limit()));
5778
}
5879

5980
/**

โ€Žsrc/main/java/com/dadok/gaerval/domain/book/converter/BookMapper.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
import org.mapstruct.ReportingPolicy;
66

77
import com.dadok.gaerval.domain.book.dto.request.BookCreateRequest;
8+
import com.dadok.gaerval.domain.book.dto.response.BookRecentSearchResponse;
89
import com.dadok.gaerval.domain.book.dto.response.BookResponse;
910
import com.dadok.gaerval.domain.book.dto.response.SearchBookResponse;
1011
import com.dadok.gaerval.domain.book.entity.Book;
12+
import com.dadok.gaerval.domain.book.entity.BookRecentSearch;
1113
import com.dadok.gaerval.global.common.JacocoExcludeGenerated;
1214

1315
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
@@ -25,4 +27,5 @@ default Book createBookRequestToEntity(BookCreateRequest bookCreateRequest) {
2527
bookCreateRequest.apiProvider(), bookCreateRequest.publisher());
2628
}
2729

30+
BookRecentSearchResponse entityToBookRecentSearchResponse(BookRecentSearch bookRecentSearch);
2831
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.dadok.gaerval.domain.book.dto.request;
2+
3+
import javax.validation.constraints.Max;
4+
import javax.validation.constraints.Min;
5+
6+
public record BookRecentSearchRequest(
7+
@Min(value = 1, message = "Limit must be at least 1")
8+
@Max(value = 100, message = "Limit cannot exceed 100") Long limit
9+
) {
10+
11+
public BookRecentSearchRequest(Long limit) {
12+
this.limit = limit == null ? 10L : limit;
13+
}
14+
}

โ€Žsrc/main/java/com/dadok/gaerval/domain/book/dto/request/SearchTarget.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@
77
@RequiredArgsConstructor
88
public enum SearchTarget implements EnumType {
99

10-
TITLE("title","์ฑ… ์ œ๋ชฉ"),
10+
TITLE("title", "์ฑ… ์ œ๋ชฉ"),
1111
PERSON("person", "์ธ๋ช…"),
12-
PUBLISHER("publisher","์ถœํŒ์‚ฌ"),
13-
ISBN("isbn","isbn");
12+
PUBLISHER("publisher", "์ถœํŒ์‚ฌ"),
13+
ISBN("isbn", "isbn");
1414

1515
private final String name;
1616
private final String description;
1717

18-
1918
@Override
2019
public String getName() {
2120
return this.name;

โ€Žsrc/main/java/com/dadok/gaerval/domain/book/dto/request/SortingPolicy.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
@RequiredArgsConstructor
88
public enum SortingPolicy implements EnumType {
99

10-
ACCURACY("accuracy","์ •ํ™•๋„ ์ˆœ"),
11-
LATEST("latest","์ตœ์‹ ์ˆœ");
10+
ACCURACY("accuracy", "์ •ํ™•๋„ ์ˆœ"),
11+
LATEST("latest", "์ตœ์‹ ์ˆœ");
1212

1313
private final String name;
1414
private final String description;

โ€Žsrc/main/java/com/dadok/gaerval/domain/book/dto/request/SuggestionsBookFindRequest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ public record SuggestionsBookFindRequest(
2020
SortDirection sortDirection
2121
) {
2222

23-
public SuggestionsBookFindRequest(JobGroup jobGroup, Integer pageSize, Long bookCursorId, SortDirection sortDirection) {
23+
public SuggestionsBookFindRequest(JobGroup jobGroup, Integer pageSize, Long bookCursorId,
24+
SortDirection sortDirection) {
2425
this.jobGroup = jobGroup;
2526
this.pageSize = pageSize == null ? 10 : pageSize;
2627
this.bookCursorId = bookCursorId;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.dadok.gaerval.domain.book.dto.response;
2+
3+
import java.time.LocalDateTime;
4+
5+
import com.fasterxml.jackson.annotation.JsonFormat;
6+
7+
public record BookRecentSearchResponse(
8+
String keyword,
9+
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
10+
LocalDateTime createdAt
11+
) {
12+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.dadok.gaerval.domain.book.dto.response;
2+
3+
import java.util.List;
4+
5+
public record BookRecentSearchResponses(
6+
int count, // ๊ฒฐ๊ณผ ์ด ๊ฐฏ์ˆ˜
7+
boolean isEmpty, // ๋ฐ˜ํ™˜ ๊ฐ’์ด 0๊ฐœ์ธ๊ฐ€
8+
List<BookRecentSearchResponse> bookRecentSearchResponses
9+
) {
10+
public BookRecentSearchResponses(List<BookRecentSearchResponse> bookRecentSearchResponses) {
11+
this(bookRecentSearchResponses.size(), bookRecentSearchResponses.isEmpty(), bookRecentSearchResponses);
12+
}
13+
}

โ€Žsrc/main/java/com/dadok/gaerval/domain/book/dto/response/BookResponses.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import java.util.List;
44

5-
public record BookResponses (
5+
public record BookResponses(
66
Integer requestedPageNumber,
77
Integer requestedPageSize,
88
Boolean isLast,

โ€Žsrc/main/java/com/dadok/gaerval/domain/book/dto/response/OriginalBookData.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ public record OriginalBookData(
1515
String url,
1616
String[] authors,
1717
String[] translators
18-
) {
18+
) {
1919

2020
@Override
2121
public boolean equals(Object o) {
22-
if (this == o) return true;
23-
if (o == null || getClass() != o.getClass()) return false;
24-
OriginalBookData that = (OriginalBookData) o;
22+
if (this == o)
23+
return true;
24+
if (o == null || getClass() != o.getClass())
25+
return false;
26+
OriginalBookData that = (OriginalBookData)o;
2527
return Objects.equals(contents, that.contents) &&
2628
Objects.equals(datetime, that.datetime) &&
2729
Objects.equals(isbn, that.isbn) &&

โ€Žsrc/main/java/com/dadok/gaerval/domain/book/dto/response/SuggestionsBookFindResponses.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
import com.dadok.gaerval.domain.job.entity.JobGroup;
88

9-
109
public record SuggestionsBookFindResponses(
1110

1211
boolean isFirst, // ์ฒซ๋ฒˆ์งธ๋ƒ

โ€Žsrc/main/java/com/dadok/gaerval/domain/book/entity/BookComment.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class BookComment extends BaseTimeColumn {
3434
private Long id;
3535

3636
@ManyToOne(fetch = FetchType.LAZY)
37-
@JoinColumn(name= "user_id", nullable = false)
37+
@JoinColumn(name = "user_id", nullable = false)
3838
private User user;
3939

4040
@ManyToOne(fetch = FetchType.LAZY)
@@ -44,7 +44,6 @@ public class BookComment extends BaseTimeColumn {
4444
@Column(name = "comment", nullable = false, length = 500)
4545
private String comment;
4646

47-
4847
protected BookComment(User user, Book book, String comment) {
4948
this.user = user;
5049
this.book = book;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.dadok.gaerval.domain.book.entity;
2+
3+
import javax.persistence.Column;
4+
import javax.persistence.Entity;
5+
import javax.persistence.FetchType;
6+
import javax.persistence.GeneratedValue;
7+
import javax.persistence.GenerationType;
8+
import javax.persistence.Id;
9+
import javax.persistence.JoinColumn;
10+
import javax.persistence.ManyToOne;
11+
import javax.persistence.Table;
12+
import javax.validation.constraints.Size;
13+
14+
import com.dadok.gaerval.domain.user.entity.User;
15+
import com.dadok.gaerval.global.common.entity.BaseTimeColumn;
16+
import com.dadok.gaerval.global.util.CommonValidator;
17+
18+
import lombok.AccessLevel;
19+
import lombok.Getter;
20+
import lombok.NoArgsConstructor;
21+
22+
@Entity
23+
@Table(name = "book_recent_searches")
24+
@Getter
25+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
26+
public class BookRecentSearch extends BaseTimeColumn {
27+
28+
@Id
29+
@GeneratedValue(strategy = GenerationType.IDENTITY)
30+
private Long id;
31+
32+
@ManyToOne(fetch = FetchType.LAZY)
33+
@JoinColumn(name = "user_id", nullable = false)
34+
private User user;
35+
36+
@Column(nullable = false)
37+
@Size(min = 1)
38+
private String keyword;
39+
40+
protected BookRecentSearch(User user, String keyword) {
41+
this.user = user;
42+
this.keyword = keyword;
43+
CommonValidator.validateLengthGraterThen(keyword, 1, "๊ฒ€์ƒ‰์–ด๋Š” ํ•œ๊ธ€์ž ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.");
44+
}
45+
46+
public static BookRecentSearch create(User user, String keyword) {
47+
return new BookRecentSearch(user, keyword);
48+
}
49+
50+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.dadok.gaerval.domain.book.repository;
2+
3+
import org.springframework.data.jpa.repository.JpaRepository;
4+
5+
import com.dadok.gaerval.domain.book.entity.BookRecentSearch;
6+
7+
public interface BookRecentSearchRepository extends JpaRepository<BookRecentSearch, Long>, BookRecentSearchSupport {
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.dadok.gaerval.domain.book.repository;
2+
3+
import com.dadok.gaerval.domain.book.dto.response.BookRecentSearchResponses;
4+
5+
public interface BookRecentSearchSupport {
6+
BookRecentSearchResponses findRecentSearches(Long userId, Long limit);
7+
}
8+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.dadok.gaerval.domain.book.repository;
2+
3+
import static com.dadok.gaerval.domain.book.entity.QBookRecentSearch.*;
4+
import static com.dadok.gaerval.domain.user.entity.QUser.*;
5+
6+
import java.util.List;
7+
8+
import com.dadok.gaerval.domain.book.dto.response.BookRecentSearchResponse;
9+
import com.dadok.gaerval.domain.book.dto.response.BookRecentSearchResponses;
10+
import com.querydsl.core.types.Projections;
11+
import com.querydsl.jpa.impl.JPAQueryFactory;
12+
13+
import lombok.RequiredArgsConstructor;
14+
15+
@RequiredArgsConstructor
16+
public class BookRecentSearchSupportImpl implements BookRecentSearchSupport {
17+
18+
private final JPAQueryFactory query;
19+
20+
@Override
21+
public BookRecentSearchResponses findRecentSearches(Long userId, Long limit) {
22+
List<BookRecentSearchResponse> bookRecentSearchResponseList = query.select(
23+
Projections.constructor(BookRecentSearchResponse.class,
24+
bookRecentSearch.keyword.as("keyword"),
25+
bookRecentSearch.createdAt.as("createdAt")
26+
)
27+
)
28+
.from(bookRecentSearch)
29+
.innerJoin(user).on(user.id.eq(bookRecentSearch.user.id))
30+
.orderBy(bookRecentSearch.createdAt.desc())
31+
.limit(limit)
32+
.fetch();
33+
34+
return new BookRecentSearchResponses(bookRecentSearchResponseList);
35+
}
36+
}

โ€Žsrc/main/java/com/dadok/gaerval/domain/book/service/BookService.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.dadok.gaerval.domain.book.dto.request.BookCreateRequest;
66
import com.dadok.gaerval.domain.book.dto.request.BookSearchRequest;
77
import com.dadok.gaerval.domain.book.dto.request.SuggestionsBookFindRequest;
8+
import com.dadok.gaerval.domain.book.dto.response.BookRecentSearchResponses;
89
import com.dadok.gaerval.domain.book.dto.response.BookResponse;
910
import com.dadok.gaerval.domain.book.dto.response.BookResponses;
1011
import com.dadok.gaerval.domain.book.dto.response.SuggestionsBookFindResponses;
@@ -13,7 +14,7 @@
1314

1415
public interface BookService {
1516

16-
BookResponses findAllByKeyword(BookSearchRequest bookSearchRequest);
17+
BookResponses findAllByKeyword(BookSearchRequest bookSearchRequest, Long userId);
1718

1819
Long createBookAndReturnId(BookCreateRequest bookCreateRequest);
1920

@@ -28,4 +29,6 @@ public interface BookService {
2829
SuggestionsBookFindResponses findSuggestionBooks(SuggestionsBookFindRequest request);
2930

3031
UserByBookResponses findUserByBookId(Long bookId, Long userId);
32+
33+
BookRecentSearchResponses findKeywordsByUserId(Long userId, Long limit);
3134
}

โ€Žsrc/main/java/com/dadok/gaerval/domain/book/service/DefaultBookCommentService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public Long createBookComment(Long bookId, Long userId, BookCommentCreateRequest
4646
boolean existsComment = bookCommentRepository.existsByBookIdAndUserId(bookId, userId);
4747
boolean existsBookmark = bookshelfService.existsByUserIdAndBookId(userId, bookId);
4848

49-
if(!existsBookmark) {
49+
if (!existsBookmark) {
5050
throw new NotMarkedBookException(ErrorCode.INVALID_COMMENT_NOT_BOOKMARK);
5151
}
5252
if (existsComment) {
@@ -82,7 +82,7 @@ public BookCommentResponse updateBookComment(Long bookId, Long userId,
8282
BookCommentUpdateRequest bookCommentUpdateRequest) {
8383
boolean existsBookmark = bookshelfService.existsByUserIdAndBookId(userId, bookId);
8484

85-
if(!existsBookmark) {
85+
if (!existsBookmark) {
8686
throw new NotMarkedBookException(ErrorCode.INVALID_COMMENT_NOT_BOOKMARK);
8787
}
8888
return bookCommentRepository.updateBookComment(bookId, userId, bookCommentUpdateRequest);

0 commit comments

Comments
ย (0)