Skip to content

Commit d68640b

Browse files
committed
feat/OPS-392: 검색 기능 추가 & ElasticSearch 구현 & 일부 도메인 오류 수정.
1 parent 860d3c3 commit d68640b

File tree

16 files changed

+301
-3
lines changed

16 files changed

+301
-3
lines changed

.github/workflows/prod-server.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ jobs:
109109
-e JWT_ACCESS_TOKEN_VALIDITY="${{secrets.JWT_ACCESS_TOKEN_VALIDITY}}" \
110110
-e JWT_REFRESH_TOKEN_VALIDITY="${{secrets.JWT_REFRESH_TOKEN_VALIDITY}}" \
111111
-e FRONT_REDIRECT_DOMAIN="${{secrets.FRONT_REDIRECT_DOMAIN}}" \
112+
-e ELASTIC_HOST="${{secrets.PROD_ELASTIC_HOST}}" \
112113
ghcr.io/${{ github.repository }}/zoopzoop:latest
113114
114115

.github/workflows/test-server-cd.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ jobs:
8686
-e JWT_ACCESS_TOKEN_VALIDITY="${{secrets.JWT_ACCESS_TOKEN_VALIDITY}}" \
8787
-e JWT_REFRESH_TOKEN_VALIDITY="${{secrets.JWT_REFRESH_TOKEN_VALIDITY}}" \
8888
-e FRONT_REDIRECT_DOMAIN="${{secrets.FRONT_REDIRECT_DOMAIN}}" \
89+
-e ELASTIC_HOST="${{secrets.TEST_ELASTIC_HOST}}" \
8990
ghcr.io/${{ github.repository }}/zoopzoop:latest
9091
9192
# 헬스체크

build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ dependencies {
125125

126126
// Awaitility (비동기 테스트 지원)
127127
testImplementation 'org.awaitility:awaitility:4.2.0'
128+
129+
// Elastic Search
130+
implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
128131
}
129132

130133
dependencyManagement {

src/main/java/org/tuna/zoopzoop/backend/domain/auth/handler/OAuth2SuccessHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
9191
// 확장 프로그램에서 로그인 했을 경우.
9292
if ("extension".equals(source)) {
9393
authResult.put(customState, accessToken, sessionId);
94-
response.sendRedirect(redirect_domain + "/extension/success");
94+
response.sendRedirect("https://" + redirect_domain + "/extension/success");
9595
response.flushBuffer();
9696
return;
9797
}
@@ -132,7 +132,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
132132

133133
// 로그인 성공 후 리다이렉트.
134134
// 배포 시에 프론트엔드와 조율이 필요한 부분일 듯 함.
135-
response.sendRedirect(redirect_domain + "/api/auth/callback");
135+
response.sendRedirect("https://" + redirect_domain + "/api/auth/callback");
136136
}
137137
// 보안을 좀 더 강화하고자 한다면 CSRF 토큰 같은 걸 생각해볼 수 있겠으나,
138138
// 일단은 구현하지 않음.(개발 과정 중에 번거로워질 수 있을 듯 함.)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package org.tuna.zoopzoop.backend.domain.member.controller;
2+
3+
import lombok.RequiredArgsConstructor;
4+
import org.springframework.http.HttpStatus;
5+
import org.springframework.http.ResponseEntity;
6+
import org.springframework.web.bind.annotation.GetMapping;
7+
import org.springframework.web.bind.annotation.RequestMapping;
8+
import org.springframework.web.bind.annotation.RequestParam;
9+
import org.springframework.web.bind.annotation.RestController;
10+
import org.tuna.zoopzoop.backend.domain.member.dto.res.ResBodyForSearchMember;
11+
import org.tuna.zoopzoop.backend.domain.member.entity.MemberDocument;
12+
import org.tuna.zoopzoop.backend.domain.member.service.MemberSearchService;
13+
import org.tuna.zoopzoop.backend.domain.member.service.MemberService;
14+
import org.tuna.zoopzoop.backend.global.rsData.RsData;
15+
16+
import java.util.List;
17+
18+
@RestController
19+
@RequiredArgsConstructor
20+
@RequestMapping("api/v1/member")
21+
public class ApiV1MemberSearchController {
22+
private final MemberSearchService memberSearchService;
23+
private final MemberService memberService;
24+
25+
@GetMapping("/search")
26+
public ResponseEntity<RsData<List<ResBodyForSearchMember>>> searchMembers(
27+
@RequestParam String keyword
28+
) {
29+
List<MemberDocument> memberDocuments = memberSearchService.searchByName(keyword);
30+
List<ResBodyForSearchMember> memberDtos = memberDocuments.stream()
31+
.map(ResBodyForSearchMember::new)
32+
.toList();
33+
return ResponseEntity
34+
.status(HttpStatus.OK)
35+
.body(
36+
new RsData<>(
37+
"200",
38+
"검색 조건에 맞는 사용자들을 조회 했습니다.",
39+
memberDtos
40+
)
41+
);
42+
}
43+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.tuna.zoopzoop.backend.domain.member.dto.res;
2+
3+
import org.tuna.zoopzoop.backend.domain.member.entity.MemberDocument;
4+
5+
public record ResBodyForSearchMember(
6+
int id,
7+
String name
8+
) {
9+
public ResBodyForSearchMember(int id, String name) {
10+
this.id = id;
11+
this.name = name;
12+
}
13+
public ResBodyForSearchMember(MemberDocument memberDocument){
14+
this(memberDocument.getId(), memberDocument.getName());
15+
}
16+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.tuna.zoopzoop.backend.domain.member.entity;
2+
3+
import jakarta.persistence.Id;
4+
import lombok.Getter;
5+
import lombok.Setter;
6+
import org.springframework.data.elasticsearch.annotations.Document;
7+
import org.springframework.data.elasticsearch.annotations.Field;
8+
import org.springframework.data.elasticsearch.annotations.FieldType;
9+
import org.springframework.data.elasticsearch.annotations.Setting;
10+
11+
@Document(indexName = "member")
12+
@Setting(settingPath = "ngram.json")
13+
@Getter
14+
@Setter
15+
public class MemberDocument {
16+
@Id
17+
private int id;
18+
19+
@Field(type = FieldType.Text, analyzer = "ngram_analyzer", searchAnalyzer = "standard")
20+
private String name;
21+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.tuna.zoopzoop.backend.domain.member.repository;
2+
3+
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
4+
import org.tuna.zoopzoop.backend.domain.member.entity.MemberDocument;
5+
6+
import java.util.List;
7+
8+
public interface MemberSearchRepository extends ElasticsearchRepository<MemberDocument, Integer> {
9+
List<MemberDocument> findByNameContaining(String name);
10+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.tuna.zoopzoop.backend.domain.member.service;
2+
3+
import lombok.RequiredArgsConstructor;
4+
import org.springframework.stereotype.Service;
5+
import org.tuna.zoopzoop.backend.domain.member.entity.MemberDocument;
6+
import org.tuna.zoopzoop.backend.domain.member.repository.MemberSearchRepository;
7+
8+
import java.util.List;
9+
10+
@Service
11+
@RequiredArgsConstructor
12+
public class MemberSearchService {
13+
private final MemberSearchRepository memberSearchRepository;
14+
15+
public List<MemberDocument> searchByName(String name) {
16+
return memberSearchRepository.findByNameContaining(name);
17+
}
18+
}

src/main/java/org/tuna/zoopzoop/backend/domain/member/service/MemberService.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
import org.tuna.zoopzoop.backend.domain.datasource.repository.DataSourceRepository;
1111
import org.tuna.zoopzoop.backend.domain.datasource.repository.TagRepository;
1212
import org.tuna.zoopzoop.backend.domain.member.entity.Member;
13+
import org.tuna.zoopzoop.backend.domain.member.entity.MemberDocument;
1314
import org.tuna.zoopzoop.backend.domain.member.enums.Provider;
1415
import org.tuna.zoopzoop.backend.domain.member.repository.MemberRepository;
16+
import org.tuna.zoopzoop.backend.domain.member.repository.MemberSearchRepository;
1517
import org.tuna.zoopzoop.backend.global.aws.S3Service;
1618

1719
import java.io.IOException;
@@ -23,6 +25,7 @@
2325
@RequiredArgsConstructor
2426
public class MemberService {
2527
private final MemberRepository memberRepository;
28+
private final MemberSearchRepository memberSearchRepository;
2629
private final S3Service s3Service;
2730
private final TagRepository tagRepository;
2831
private final DataSourceRepository dataSourceRepository;
@@ -83,7 +86,16 @@ public Member createMember(String name, String profileUrl, String key, Provider
8386
.providerKey(key)
8487
.provider(provider)
8588
.build();
86-
return memberRepository.save(member);
89+
90+
Member saved = memberRepository.save(member);
91+
92+
// ElasticSearch용 document 생성.
93+
MemberDocument doc = new MemberDocument();
94+
doc.setId(saved.getId());
95+
doc.setName(saved.getName());
96+
memberSearchRepository.save(doc);
97+
98+
return saved;
8799
}
88100

89101
//사용자 이름 수정
@@ -94,6 +106,11 @@ public void updateMemberName(Member member, String newName){
94106
}
95107
member.updateName(generateUniqueUserNameTag(newName));
96108
memberRepository.save(member);
109+
110+
MemberDocument doc = new MemberDocument();
111+
doc.setId(member.getId());
112+
doc.setName(member.getName());
113+
memberSearchRepository.save(doc);
97114
}
98115

99116
@Transactional

0 commit comments

Comments
 (0)