7. 검색창 검색기능 (1) - Backend 부분

2021. 1. 11. 22:47프로젝트/Salle(살래) 중고거래 웹

728x90

검색하면 등록된 상품이 나오는 검색기능을 구현했습니다. 먼저 제가 원하는 검색 기능 스펙은 띄어쓰기가 틀려도 단어가 같으면 검색해주는 기능이었습니다. 그래서 시행착오 끝에 온전한 검색 + 띄어쓰기 없애는 가공을 거쳐 검색 기능을 SQL문 만으로 구현해냈습니다. 당근마켓은 다른 단어와 섞여있어도 검색이 되는데(ex.'자전거차' -> '자전거' 검색됨) 아마 Elasticsearch에 형태소 분석기 API도 사용한 것 같습니다. 제가 구현한 것은 교보문고 도서검색('자전거' 검색안됨) 기능과 유사합니다. 

 

Frontend에서 CSS로 원하는 검색창과 display 형태를 구현하는데 시간을 썼기 때문에 검색창 기능은 FE(Frontend)와 BE(Backend)로나눠서 업로드 하겠습니다.

 

검색 기능을 고도화 하기위해 Elasticsearch 라는 실시간 검색엔진 Java 기반 오픈소스를 사용할까 고민했지만 JSON 형태로 주고 받아야 되기 때문에 현재 기술 스텍(h2 DB, JSP, Spring boot, Mybatis)을 고려해 드랍하였습니다. 그리고 h2 DB + Java String API로 텍스트 가공을 통해 적정수준의 검색이 가능하기 때문에 이와 같은 스펙으로 진행했습니다.

 

H2 DB Product 테이블 구조

검색 기능 시 PR_TITLE의 띄어쓰기를 없앤 텍스트와도 비교해주기 위해 맨 끝 column PR_TITLE_ALIAS를 추가했습니다. 판매자가 정보를 등록할 때 Java String API replaceAll("\s", "")을 사용해 PR_TITLE의 space들을 모두 지워주고 저장해줍니다.

 

Mybatis Mapper.xml SQL문

<bind> 태그는 WHERE ... LIKE '%...%' 때문에 사용했습니다. Mybatis는 #{변수명} parameter를 JDBC PreparedStatement parameter로 전달해줍니다. 다만 '%검색어%'(검색어 앞뒤에 다른 문자가 들어와도 검색가능)에서 특수문자와 결합할 때 JDBC에서 인식오류가 발생합니다. 이를 해결하려면 escape character(\ -> backslash)를 사용하거나, <bind>태그를 사용해 String으로 concatenate 해준 변수를 parameter로 작성해주면 됩니다. 

1
2
3
4
5
6
7
8
9
    <select id="search" resultType="Product">
        <bind name="searchWordConcate" value="'%'+searchWord+'%'"></bind>
        <bind name="searchWordNoSpaceConcate" value="'%'+searchWordNoSpace+'%'"></bind>
        SELECT *
        FROM PRODUCT
        WHERE PR_TITLE LIKE #{searchWordConcate} OR PR_TITLE LIKE #{searchWordNoSpaceConcate}
        OR
        PR_TITLE_ALIAS LIKE #{searchWordConcate} OR PR_TITLE_ALIAS LIKE #{searchWordNoSpaceConcate};
    </select>
cs

 

검색기능 ProductInfoController.java 코드

검색어를 View로부터 전달 받기위해 @RequestParam 아노테이션을 사용했습니다. View의 <form action=""...>으로 HttpRequest를 Controller로 전송해주는 과정에서 <input> 태그 name이 아노테이션 value와 일치한다면 parameter로 전달해줍니다. (<input name="searchWord"...>) 

searchWordNoSpace는 사용자가 검색한 텍스트의 띄어쓰기를 없앤 값을 Product DB의 값과 비교해 검색 정확도를 높이기 위해서 만들어줬습니다. replaceAll() 메서드의 parameter "\(:backslash)s"는 정규식 표현(RegExp)에서 띄어쓰기를 뜻합니다. 정규식 표현은 문자열에 특수기호나 패턴을 찾거나 입력 하기위해 지정된 표현식(Expression)입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
    @RequestMapping(value = "/search/result", method = RequestMethod.GET) 
    public String searchGet(@RequestParam("searchWord"String searchWord, Model model) {
        String searchWordNoSpace = searchWord.replaceAll("\s""");
        
        if (productService.searchCount(searchWord, searchWordNoSpace) == 0) {
            model.addAttribute("searchWord",searchWord);
            return "product/searchResultZero";
        } else {
            List<Product> productList = productService.search(searchWord, searchWordNoSpace);
            model.addAttribute("searchProductList", productList);
            return "product/searchResult";
        }
    }
cs

 

다음글 7. 검색창 검색기능 (2) - Frontend 부분으로 이어집니다.