diff --git a/src/main/java/com/t3t/frontserver/elastic/client/ElasticClient.java b/src/main/java/com/t3t/frontserver/elastic/client/ElasticClient.java index 9f4eb02..9a0dd9d 100644 --- a/src/main/java/com/t3t/frontserver/elastic/client/ElasticClient.java +++ b/src/main/java/com/t3t/frontserver/elastic/client/ElasticClient.java @@ -10,6 +10,7 @@ import org.springframework.web.bind.annotation.RequestParam; import java.math.BigDecimal; +import java.util.List; @FeignClient(name = "ElasticAdaptor", url = "${t3t.feignClient.url}") public interface ElasticClient { @@ -43,8 +44,19 @@ public interface ElasticClient { @GetMapping("/t3t/bookstore/category/{categoryId}/search") ResponseEntity>> getCategorySearchPage(@RequestParam String query, - @RequestParam String searchType, - @RequestParam int pageNo, - @PathVariable(value = "categoryId",required = false) BigDecimal categoryId, - @RequestParam(value = "sortBy", defaultValue = "_score", required = false) String sortBy); + @RequestParam String searchType, + @RequestParam int pageNo, + @PathVariable(value = "categoryId",required = false) BigDecimal categoryId, + @RequestParam(value = "sortBy", defaultValue = "_score", required = false) String sortBy); + /** + * + * elasticsearch 기반 실시간 자동완성 + * + * @param prefix text 검색어 + * @return 서버의 데이터를 가지고 옴 + */ + @GetMapping("/t3t/bookstore/autocomplete") + ResponseEntity>> autocomplete(@RequestParam String prefix); } + + diff --git a/src/main/java/com/t3t/frontserver/elastic/controller/AutocompleteController.java b/src/main/java/com/t3t/frontserver/elastic/controller/AutocompleteController.java new file mode 100644 index 0000000..51258a7 --- /dev/null +++ b/src/main/java/com/t3t/frontserver/elastic/controller/AutocompleteController.java @@ -0,0 +1,29 @@ +package com.t3t.frontserver.elastic.controller; + +import com.t3t.frontserver.elastic.client.ElasticClient; +import com.t3t.frontserver.model.response.BaseResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +public class AutocompleteController { + private final ElasticClient elasticAdaptor; + /** + * + * elasticsearch 기반 실시간 자동완성 + * + * @param prefix text 검색어 + * @return 페이지로 정보를 가지고 이동 + */ + + @GetMapping("/autocomplete") + public ResponseEntity>> proxyAutocomplete(@RequestParam String prefix) { + return elasticAdaptor.autocomplete(prefix); + } +} \ No newline at end of file diff --git a/src/main/resources/static/assets/main/css/elastic.css b/src/main/resources/static/assets/main/css/elastic.css new file mode 100644 index 0000000..61b62ea --- /dev/null +++ b/src/main/resources/static/assets/main/css/elastic.css @@ -0,0 +1,30 @@ +.autocomplete-container { + position: relative; +} + +.autocomplete-items { + position: absolute; + border: 1px solid #d4d4d4; + border-bottom: none; + border-top: none; + z-index: 99; + top: 100%; + left: 0; + right: 0; + background-color: white; + overflow: hidden; + border-radius: 4px; + box-shadow: 0 4px 6px rgba(0,0,0,0.1); +} + +.autocomplete-items div { + padding: 10px; + cursor: pointer; + background-color: #fff; + border-bottom: 1px solid #d4d4d4; + font-size: 12px; +} + +.autocomplete-items div:hover { + background-color: #e9e9e9; +} diff --git a/src/main/resources/static/assets/main/js/elastic.js b/src/main/resources/static/assets/main/js/elastic.js new file mode 100644 index 0000000..817dd8e --- /dev/null +++ b/src/main/resources/static/assets/main/js/elastic.js @@ -0,0 +1,85 @@ +document.addEventListener('DOMContentLoaded', function() { + updateSearchTypeDisplay(); + updateSearchQueryDisplay(); + updateCategoryIdFromURL(); + + var searchInput = document.getElementById('searchQueryInput'); + var resultsContainer = document.getElementById('autocompleteResults'); + + searchInput.addEventListener('input', function() { + var query = this.value; + if (query.length > 1) { + fetch('/autocomplete?prefix=' + encodeURIComponent(query)) + .then(response => response.json()) + .then(response => { + if (response.data && response.data.length) { + resultsContainer.innerHTML = ''; + response.data.forEach(item => { + var resultItem = document.createElement('div'); + resultItem.textContent = item; + resultItem.addEventListener('click', function() { + searchInput.value = this.textContent; + resultsContainer.innerHTML = ''; + resultsContainer.style.display = 'none'; + }); + resultsContainer.appendChild(resultItem); + }); + resultsContainer.style.display = 'block'; + } else { + resultsContainer.innerHTML = ''; + resultsContainer.style.display = 'none'; + } + }) + .catch(error => console.error('Error fetching autocomplete suggestions:', error)); + } else { + resultsContainer.innerHTML = ''; + resultsContainer.style.display = 'none'; + } + }); + + document.addEventListener('click', function(event) { + if (!searchInput.contains(event.target) && !resultsContainer.contains(event.target)) { + resultsContainer.style.display = 'none'; + } + }); + + searchInput.addEventListener('focus', function() { + if (resultsContainer.innerHTML !== '') { + resultsContainer.style.display = 'block'; + } + }); +}); + +function updateCategoryIdFromURL() { + const path = window.location.pathname; + const categoryPattern = /\/category\/(\d+)/; // '/category/' 다음에 오는 숫자를 찾는 정규 표현식 + const match = path.match(categoryPattern); + + if (match && match[1]) { + document.getElementById('categoryIdInput').value = match[1]; + } else { + document.getElementById('categoryIdInput').parentNode.removeChild(document.getElementById('categoryIdInput')); + } +} +function setSearchType(type) { + var typeNames = { + 'all': '통합검색', + 'book_name': '책 이름', + 'publisher_name': '출판사', + 'participant_name': '참여자' + }; + document.getElementById('searchTypeInput').value = type; + document.getElementById('dropdownMenuButton').textContent = typeNames[type]; +} +function updateSearchTypeDisplay() { + var searchParams = new URLSearchParams(window.location.search); + var currentType = searchParams.get('searchType') || 'all'; + setSearchType(currentType); +} +function updateSearchQueryDisplay() { + var searchParams = new URLSearchParams(window.location.search); + var currentQuery = searchParams.get('query'); + if (currentQuery) { + document.getElementById('searchQueryInput').value = currentQuery; + } +} \ No newline at end of file diff --git a/src/main/resources/templates/main/fragment/searchbar.html b/src/main/resources/templates/main/fragment/searchbar.html index b2e1962..53a9af6 100644 --- a/src/main/resources/templates/main/fragment/searchbar.html +++ b/src/main/resources/templates/main/fragment/searchbar.html @@ -34,7 +34,8 @@
찾고 싶으신 도서가 있으신가요?
- + +
@@ -47,46 +48,7 @@
찾고 싶으신 도서가 있으신가요?
- + + - + \ No newline at end of file diff --git a/src/main/resources/templates/main/page/elasticSearch.html b/src/main/resources/templates/main/page/elasticSearch.html index b63f73d..7a8fdb4 100644 --- a/src/main/resources/templates/main/page/elasticSearch.html +++ b/src/main/resources/templates/main/page/elasticSearch.html @@ -98,7 +98,7 @@

검색 결과가 없습니다..