Blog

[Spring][MiniProject 6일차]61 검색 기능 구현

Author
Summary
간략한 검색 기능 구현
Category
Study
Tags
Spring
Favorite
Memory Date
2023/09/21
Cross Reference Study
Related Media
Related Thought
Related Lessons
tag
날짜
작성자
진행상황
진행 전
태그구분
6 more properties
해당 기능 구현에 대한 세부 로드맵
1.
검색 기능을 위한 데이터베이스 모델 설계:
가게 정보를 저장하는 데이터베이스 테이블을 설계해야 합니다. 이 테이블은 가게 이름, 위치, 메뉴, 등등의 정보를 포함
지금은 테이블 자체 컬럼명으로 하고있지만 챌린지로 넘어간다면
검색을 용이하게 하기 위해 인덱스를 활용 → 한다면 어떤 성능 차이가 있을지? 인덱스는 유용하게 하기 위한 자료구조다 라는 전제에서
2.
검색 기능 구현:
사용자가 키워드로 가게를 검색할 수 있는 검색 기능을 구현해야 함
Spring Boot에서는 JPA 또는 Hibernate를 사용하여 데이터베이스와 연동하고 검색 쿼리를 실행하는 것이 주 목적
a.
검색 기능 엔드포인트 추가:
검색 결과를 반환할 수 있는 API 엔드포인트를 추가
이 엔드포인트는 사용자가 키워드를 입력하고 검색을 요청할 때 호출
b.
검색 결과를 처리하는 비즈니스 로직 구현:
검색 결과를 처리하고 필요한 데이터를 데이터베이스에서 검색하는 비즈니스 로직을 구현
c.
검색 결과 반환:
검색된 가게 정보를 클라이언트에 반환
JSON 형식으로 결과를 제공하는 것이 목표
프론트에서는 ${storename}과 같이 뿌려지도록 해야하기 때문
3.
검색 관련 UI 구현 (프론트엔드)
검색 기능을 사용할 수 있는 사용자 인터페이스를 구현
이를 통해 사용자는 키워드를 입력하고 검색을 실행할 상세 페이지 필요
4.
검색 기능 테스트:
검색 기능을 테스트하여 예상대로 작동하는지 확인
검색어의 일치 여부, 정확성 및 성능을 확인
5.
보안 고려사항:
검색 기능에서는 입력 데이터의 검증과 SQL 인젝션 방지를 고려
추가적 연구 대상 : (미예정)
검색 기능을 구현할 때 검색 엔진을 사용하기 위해 Elasticsearch 또는 Solr와 같은 도구를 고려
검색과 관련된 기능을 빠르게 구현하는 데 도움이 될 수 있음.
→ 이것을 적용했을때 어떤 차이나, 그런것들이 예측
플로우 차트, 와이어 프레임 설계로부터 유저의 이동, 실질적인 사용 추측
원칙적으로는 유저 프로세스에 따라 플로우 차트를 구성하고, 와이어프레임으로 유저의 사용 이동을 추적하고 설계해야 한다.
이 과정은 시간을 조금 소모하기 때문에 우선 텍스트로 구도를 잡고 추후 플로우 차트와 와이어프레임으로 표현하는 것으로 일의 우선순위를 변경했다.
1. DB 모델 설계 여부 확인
우선 다른 기능들이 구현되어있는 상태로, 검색 기능은 “어떤 키워드로” + “어떤 내용을 조회할 것인가” 가 핵심인 상태이다.
나는 메뉴 이름 ex) 아메리카노, 카페라떼 라는 텍스트를 통해서
1.
이 메뉴를 가지고 있는(또는 포함하는) 카페이름을 조회 할 것
2.
이 메뉴의 이름과 동일한(또는 포함하는) 메뉴를 조회 할 것
이라는 두가지 목표를 세웠다.
각각 구현해보고 키워드를 통해 메뉴 또는 카페 이름을 통합검색하도록함
컨트롤러에서는 쿼리스트링으로 클라이언트의 입력값을 keyword를 받아오게 한다.
SearchController.java
@RestController @RequiredArgsConstructor @RequestMapping("/api") public class SearchController { private final SearchService searchService; // 통합버전 @GetMapping("/search/stores-and-menus") public List<SearchResponseDto> searchStoresAndMenusByKeyword(@RequestParam("keyword") String keyword) { return searchService.searchStoresAndMenusByKeyword(keyword); } }
Java
복사
서비스에서는 각 Repository로부터 정보를 받아온다. 현재는 목적상 키워드를 통해 “가게”를 찾는 것으로 집중되어 있다.(ex: 메뉴를 검색해도 그 메뉴가 있는 가게를 연결해주기 위함)
SearchService.java
@Service @RequiredArgsConstructor public class SearchService { private final MenuRepository menuRepository; private final StoreRepository storeRepository; @Transactional(readOnly = true) public List<SearchResponseDto> searchStoresAndMenusByKeyword(String keyword) { List<SearchResponseDto> responseDtos = new ArrayList<>(); // 메뉴 이름에 키워드를 포함하는 메뉴 검색 List<Menu> menus = menuRepository.findByMenuNameContaining(keyword); for (Menu menu : menus) { SearchResponseDto responseDto = new SearchResponseDto(); responseDto.setStoreName(menu.getStore().getStoreName()); responseDto.setStoreAddress(menu.getStore().getStoreAddress()); responseDto.setInformation(menu.getStore().getInformation()); responseDto.setType("menu"); responseDtos.add(responseDto); } // 가게 이름에 키워드를 포함하는 가게 검색 List<Store> stores = storeRepository.findByStoreNameContaining(keyword); for (Store store : stores) { SearchResponseDto responseDto = new SearchResponseDto(); responseDto.setStoreName(store.getStoreName()); responseDto.setStoreAddress(store.getStoreAddress()); responseDto.setInformation(store.getInformation()); responseDto.setType("store"); responseDtos.add(responseDto); } return responseDtos; } }
Java
복사
레포지토리는 각 항목의 주인 레포지토리를 사용하게 되므로, StoreRepository, MenuRepository에서 JPA 쿼리메소드를 통해 해당 정보를 DB에서 가져오게 된다.
StoreRepository.java
@Repository public interface StoreRepository extends JpaRepository<Store, Long> { List<Store> findByStoreNameContaining(String keyword); }
Java
복사
MenuRepository.java
@Repository public interface MenuRepository extends JpaRepository<Menu, Long> { ... List<Menu> findByMenuNameContaining(String keyword); }
Java
복사
마지막으로 가져온 정보는 SearchResponseDto를 통해 필요한 정보만 클라이언트로 반환하게 된다.
@Getter @Setter @NoArgsConstructor public class SearchResponseDto { private String storeName; // 가게 이름 private String storeAddress; // 가게 주소 private String information; // 가게 정보 private String type; // 결과의 유형 (예: "menu" 또는 "store") }
Java
복사
여기서 응답을 받는 프론트엔드가 정보를 분류해서 작업 할 수 있도록 type을 통해서 각각 검색된 결과의 출처(origin)을 알 수 있도록 분류해주었다.
아래와 같이 테스트 되었으며, cafe라는 하나의 키워드로
cafe라는 키워드가 가게이름에 포함된 가게
cafe라는 키워드가 메뉴이름에 포함된 가게
가 나타나고있으며, Key가 type인 부분에서 menu, store로 분류되고 있다.