Skip to content

Commit

Permalink
[BE] 게시글 검색 Elasticsearch 적용 (#266)
Browse files Browse the repository at this point in the history
* feat: Spring Data Elasticsearch 의존성 추가

* feat: 설정 파일에 elasticsearch 엔드포인트 추가 (application.yml)

* chore: 직렬화 문제로 DTO에 @NoArgsConstructor 추가

* feat: ElasticsearchConfig 작성

* feat: PostDocument 작성

* feat: PostElasticsearchRepository 작성

* feat: 게시글 리스트 조회(findAllPosts)시 ES 사용하도록 변경

* chore: 사용하지 않는 클래스 삭제 (QuerydslPredicate, QuerydslRepository)

* feat: 개별 게시글 조회시 ES 사용하도록 변경

* feat: 게시글 추가시 ES에도 반영

* feat: 게시글 수정시 ES에도 반영

* feat: 게시글 삭제시 ES에도 반영

* feat: self-injection 방식으로 내부 호출 문제 해결 방식 변경

<문제 상황>
findAllPosts()에서 getPostPage()를 내부 호출하기 때문에 getPostPage()의 @Cacheable 작동하지 않음

<기존 해결 방식>
별도 클래스에 getPostPage() 구현하여 findAllPosts()에서 호출

<기존 방식 문제점>
불필요하게 클래스 수 증가

<수정된 해결 방식>
PostService 에서 자기 자신을 주입하도록 하여 내부 호출시에도 @Cacheable 작동 되도록 함
  • Loading branch information
Jinwook94 committed Nov 4, 2023
1 parent 3192bd8 commit 5f73b74
Show file tree
Hide file tree
Showing 20 changed files with 453 additions and 265 deletions.
3 changes: 2 additions & 1 deletion backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
Expand All @@ -43,7 +44,7 @@ dependencies {
implementation 'com.auth0:jwks-rsa:0.21.1'
implementation 'com.google.api-client:google-api-client:1.32.1'
implementation 'com.google.http-client:google-http-client-jackson2:1.31.0'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.0'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.15.3'
implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.5'
implementation 'net.rakugakibox.spring.boot:logback-access-spring-boot-starter:2.7.1'
implementation 'net.logstash.logback:logstash-logback-encoder:7.3'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ private List<PostResponse> mapPostBookmarksToPostResponse(List<PostBookmark> pos
.map(postBookmark -> {
Post post = postBookmark.getPost();
boolean isViewed = viewedPosts.contains(post.getId());
PostResponse postResponse = PostResponse.of(post, true, isViewed);
PostResponse postResponse = PostResponse.fromPost(post, true, isViewed);
updateVoteStatusForPost(postBookmark.getBookmark().getMember().getId(), post, postResponse);
return postResponse;
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package com.bootme.comment.dto;

import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

import javax.annotation.Nullable;

@Getter
@AllArgsConstructor
@NoArgsConstructor
public class CommentRequest {

@Nullable
Expand Down
26 changes: 26 additions & 0 deletions backend/src/main/java/com/bootme/config/ElasticsearchConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.bootme.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;

@Configuration
@EnableElasticsearchRepositories(basePackages = "com.bootme.post.repository")
public class ElasticsearchConfig extends ElasticsearchConfiguration {

@Value("${elasticsearch.host:10.0.6.174}")
private String elasticsearchHost;

@Value("${elasticsearch.port:9200}")
private int elasticsearchPort;

@Override
public ClientConfiguration clientConfiguration() {
return ClientConfiguration.builder()
.connectedTo(elasticsearchHost + ":" + elasticsearchPort)
.build();
}

}
130 changes: 130 additions & 0 deletions backend/src/main/java/com/bootme/post/domain/PostDocument.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package com.bootme.post.domain;

import com.bootme.post.dto.PostRequest;
import jakarta.persistence.Id;
import lombok.Builder;
import lombok.Data;
import org.springframework.data.elasticsearch.annotations.*;

import java.util.HashMap;
import java.util.Map;

import static com.bootme.common.util.TimeConverter.*;

@Data
@Document(indexName = "post")
public class PostDocument {

@Id
private String id;

@Field(type = FieldType.Long, name = "postId")
private Long postId;

@Field(type = FieldType.Long, name = "memberId")
private Long writerId;

@Field(type = FieldType.Text, name = "writerNickname")
private String writerNickname;

@Field(type = FieldType.Text, name = "writerProfileImage")
private String writerProfileImage;

@Field(type = FieldType.Text, name = "topic")
private String topic;

@Field(type = FieldType.Text, name = "title")
private String title;

@Field(type = FieldType.Text, name = "content")
private String content;

@Field(type = FieldType.Integer, name = "commentCount")
private int commentCount;

@Field(type = FieldType.Integer, name = "likes")
private int likes;

@Field(type = FieldType.Integer, name = "clicks")
private int clicks;

@Field(type = FieldType.Integer, name = "bookmarks")
private int bookmarks;

@Field(type = FieldType.Keyword, name = "status")
private String status;

@Field(type = FieldType.Long, name = "createdAt")
private long createdAt;

@Field(type = FieldType.Long, name = "modifiedAt")
private long modifiedAt;

@Builder
public PostDocument(String id, Long postId, Long writerId, String writerNickname, String writerProfileImage, String topic,
String title, String content, int commentCount, int likes, int clicks, int bookmarks,
String status, long createdAt, long modifiedAt) {
this.id = id;
this.postId = postId;
this.writerId = writerId;
this.writerNickname = writerNickname;
this.writerProfileImage = writerProfileImage;
this.topic = topic;
this.title = title;
this.content = content;
this.commentCount = commentCount;
this.likes = likes;
this.clicks = clicks;
this.bookmarks = bookmarks;
this.status = status;
this.createdAt = createdAt;
this.modifiedAt = modifiedAt;
}

public static PostDocument fromPost(Post post) {
return PostDocument.builder()
.postId(post.getId())
.writerId(post.getMember().getId())
.writerNickname(post.getWriterNickname())
.writerProfileImage(post.getMember().getProfileImage())
.topic(post.getTopic())
.title(post.getTitle().getValue())
.content(post.getContent().getValue())
.commentCount(post.getComments().size())
.likes(post.getLikes())
.clicks(post.getClicks())
.bookmarks(post.getBookmarks())
.status(post.getStatus().name())
.createdAt(convertLocalDateTimeToLong(post.getCreatedAt()))
.modifiedAt(convertLocalDateTimeToLong(post.getModifiedAt()))
.build();
}

public Map<String, Object> toMap() {
Map<String, Object> map = new HashMap<>();
map.put("id", this.id);
map.put("postId", this.postId);
map.put("writerId", this.writerId);
map.put("writerNickname", this.writerNickname);
map.put("writerProfileImage", this.writerProfileImage);
map.put("topic", this.topic);
map.put("title", this.title);
map.put("content", this.content);
map.put("commentCount", this.commentCount);
map.put("likes", this.likes);
map.put("clicks", this.clicks);
map.put("bookmarks", this.bookmarks);
map.put("status", this.status);
map.put("createdAt", this.createdAt);
map.put("modifiedAt", this.modifiedAt);
return map;
}

public void updateFromRequest(PostRequest postRequest) {
this.setTopic(postRequest.getTopic());
this.setTitle(postRequest.getTitle());
this.setContent(postRequest.getContent());
this.setModifiedAt(System.currentTimeMillis());
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.bootme.post.dto;

import com.bootme.post.domain.Post;
import com.bootme.post.domain.PostDocument;
import com.bootme.vote.dto.VotableResponse;
import lombok.Builder;
import lombok.Getter;
Expand Down Expand Up @@ -54,7 +55,7 @@ public PostDetailResponse(Long id, Long writerId, String writerNickname, String
this.isBookmarked = isBookmarked;
}

public static PostDetailResponse of(Post post, boolean isBookmarked){
public static PostDetailResponse fromPost(Post post, boolean isBookmarked){
return PostDetailResponse.builder()
.id(post.getId())
.writerId(post.getMember().getId())
Expand All @@ -74,4 +75,24 @@ public static PostDetailResponse of(Post post, boolean isBookmarked){
.build();
}

public static PostDetailResponse fromPostDocument(PostDocument postDocument, boolean isBookmarked) {
return PostDetailResponse.builder()
.id(postDocument.getPostId())
.writerId(postDocument.getWriterId())
.writerNickname(postDocument.getWriterNickname())
.writerProfileImage(postDocument.getWriterProfileImage())
.topic(postDocument.getTopic())
.title(postDocument.getTitle())
.content(postDocument.getContent())
.likes(postDocument.getLikes())
.clicks(postDocument.getClicks())
.bookmarks(postDocument.getBookmarks())
.status(postDocument.getStatus())
.createdAt(postDocument.getCreatedAt())
.modifiedAt(postDocument.getModifiedAt())
.commentCount(postDocument.getCommentCount())
.isBookmarked(isBookmarked)
.build();
}

}
26 changes: 25 additions & 1 deletion backend/src/main/java/com/bootme/post/dto/PostResponse.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.bootme.post.dto;

import com.bootme.post.domain.Post;
import com.bootme.post.domain.PostDocument;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

import static com.bootme.common.util.TimeConverter.convertLocalDateTimeToLong;
import static com.bootme.vote.domain.VoteType.NONE;

@Getter
@Setter
Expand Down Expand Up @@ -56,7 +58,7 @@ public PostResponse(Long id, Long writerId, String writerNickname, String writer
this.isViewed = isViewed;
}

public static PostResponse of(Post post, boolean isBookmarked, boolean isViewed){
public static PostResponse fromPost(Post post, boolean isBookmarked, boolean isViewed){
return PostResponse.builder()
.id(post.getId())
.writerId(post.getMember().getId())
Expand All @@ -77,4 +79,26 @@ public static PostResponse of(Post post, boolean isBookmarked, boolean isViewed)
.build();
}

public static PostResponse fromPostDocument(PostDocument postDocument) {
return PostResponse.builder()
.id(postDocument.getPostId())
.writerId(postDocument.getWriterId())
.writerNickname(postDocument.getWriterNickname())
.writerProfileImage(postDocument.getWriterProfileImage())
.topic(postDocument.getTopic())
.title(postDocument.getTitle())
.contentExcerpt(postDocument.getContent())
.commentCount(postDocument.getCommentCount())
.likes(postDocument.getLikes())
.clicks(postDocument.getClicks())
.bookmarks(postDocument.getBookmarks())
.status(postDocument.getStatus())
.createdAt(postDocument.getCreatedAt())
.modifiedAt(postDocument.getModifiedAt())
.voted(NONE.toString())
.isBookmarked(false)
.isViewed(false)
.build();
}

}
Loading

0 comments on commit 5f73b74

Please sign in to comment.