관리 메뉴

거니의 velog

(4) 도서 쇼핑몰 만들기 4 본문

Java_Spring mini project 쇼핑몰

(4) 도서 쇼핑몰 만들기 4

Unlimited00 2023. 11. 24. 12:42

5. Ajax 이용해 검색 자동 완성 기능 구현하기

* 아마 여러분도 웹 사이트에서 검색하기 위해 키워드를 입력했을 때 관련 키워드를 자동으로 표시해 주는 '자동 완성 기능'을 자주 사용하고 있을 것이다.

* 이번에는 Ajax를 이용해 검색 자동 완성 기능을 구현해 보자.

1. 먼저 JSON을 사용하기 위해 pom.xml에 의존성(dependency)을 설정한다.

        <!-- json -->
        <dependency>
		    <groupId>net.sf.json-lib</groupId>
		    <artifactId>json-lib</artifactId>
		    <version>2.4</version>
		    <classifier>jdk15</classifier>    
		</dependency>

2. 키워드 검색을 위해 SQL 문에서 like 연산자를 사용한다.

[goods.xml]

	<!-- 검색창에 입력한 단어를 가져와 그 단어가 포함된 상품 제목을 조회한다. -->
    <select id="selectGoodsBySearchWord" resultMap="goodsResult"   parameterType="String"  >
     <![CDATA[
				select g.*,d.fileName from t_shopping_goods g, t_goods_detail_image d
		    where g.goods_id=d.goods_id
		    and d.filetype='main_image'
		    and g.goods_title like '%'|| #{searchWord} || '%'
		    order by g.goods_creDate desc
		]]>
	</select>	
	
	<!-- 검색창에 입력한 키워드를 가져와 그 키워드가 포함된 상품 제목을 조회한다. -->
	<select id="selectKeywordSearch" resultType="String"   parameterType="String"  >
	    <![CDATA[
        select goods_title from t_shopping_goods 
        where         
        goods_title like '%'|| #{keyword} || '%'
        order by goods_creDate desc
		]]>
	</select>

3. 브라우저에서 Ajax로 전송된 키워드를 가져와 그 키워드가 포함된 제목 목록을 JSON으로 만들어 다시 브라우저로 전송한다.

[GoodsControllerImpl.java]

	@RequestMapping(value = "/keywordSearch.do", method = RequestMethod.GET, 
					produces = "application/text; charset=utf8") // 브라우저로 전송하는 JSON 데이터의 한글 인코딩을 지정한다.
	public @ResponseBody String keywordSearch(@RequestParam("keyword") String keyword, // 검색할 키워드를 가져온다.
			HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		
		response.setContentType("text/html;charset=utf-8");
		response.setCharacterEncoding("utf-8");
		if (keyword == null || keyword.equals(""))
			return null;

		keyword = keyword.toUpperCase();
		List<String> keywordList = goodsService.keywordSearch(keyword); // 가져온 키워드가 포함된 상품 제목을 조회한다.

		JSONObject jsonObject = new JSONObject();
		jsonObject.put("keyword", keywordList);

		String jsonInfo = jsonObject.toString();
		return jsonInfo; // JSON을 문자열로 변환한 후 브라우저로 출력한다.
		
	}

	@RequestMapping(value = "/searchGoods.do", method = RequestMethod.GET)
	public ModelAndView searchGoods(@RequestParam("searchWord") String searchWord, 
			HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		
		String viewName = (String) request.getAttribute("viewName");
		List<GoodsVO> goodsList = goodsService.searchGoods(searchWord); // 검색창에서 가져온 단어가 포함된 상품 제목을 조회한다.
		ModelAndView mav = new ModelAndView(viewName);
		mav.addObject("goodsList", goodsList);
		return mav;

	}

4. 다음과 같이 JSP 파일을 준비한다.

5. 사용자가 검색창에 검색 키워드를 입력하면 Ajax 기능을 이용해 해당 키워드가 포함된 목록을 가져온다. 그런 다음 id가 suggest인 <div> 태그에 차례대로 표시한다. header.jsp에 이를 구현해 보자.

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"
    isELIgnored="false"
    %>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />

<script type="text/javascript">
    var loopSearch = true; // 제시된 키워드를 클릭하면 keywordSearch() 함수의 실행을 중지시킨다.

    function keywordSearch() {
        if (loopSearch == false)
            return;
        var value = document.frmSearch.searchWord.value;
        $.ajax({
            type: "get",
            async: true, //false인 경우 동기식으로 처리한다.
            url: "${contextPath}/goods/keywordSearch.do",
            data: {
                keyword: value
            },
            success: function(data, textStatus) {
                var jsonInfo = JSON.parse(data); // 전송된 데이터를 JSON으로 파싱한다.
                displayResult(jsonInfo); // 전송된 JSON 데이터를 표시한다.
            },
            error: function(data, textStatus) {
                alert("에러가 발생했습니다." + data);
            },
            complete: function(data, textStatus) {
                //alert("작업을완료 했습니다");

            }
        }); //end ajax	
    }

    function displayResult(jsonInfo) {
        var count = jsonInfo.keyword.length; // JSON의 데이터 개수를 구한다.
        if (count > 0) {
            var html = '';
            for (var i in jsonInfo.keyword) {
                html += "<a href=\"javascript:select('" + jsonInfo.keyword[i] + "')\">" + jsonInfo.keyword[i] + "</a><br/>";
            } // JSON 데이터를 차례대로 <a> 태그를 이용해 키워드 목록을 만든다.
            var listView = document.getElementById("suggestList");
            listView.innerHTML = html;
            show('suggest'); // <a> 태그로 만든 키워드 목록을 <div> 태그에 차례대로 표시한다.
        } else {
            hide('suggest');
        }
    }

    function select(selectedKeyword) {
        document.frmSearch.searchWord.value = selectedKeyword;
        loopSearch = false;
        hide('suggest');
    }

    function show(elementId) {
        var element = document.getElementById(elementId);
        if (element) {
            element.style.display = 'block';
        }
    }

    function hide(elementId) {
        var element = document.getElementById(elementId);
        if (element) {
            element.style.display = 'none';
        }
    }
</script>

<body>
    <div id="logo">
        <a href="${contextPath}/main/main.do">
            <img width="176" height="80" alt="booktopia" src="${contextPath}/resources/image/Booktopia_Logo.jpg">
        </a>
    </div>
    <div id="head_link">
        <ul>
            <c:choose>
                <c:when test="${isLogOn==true and not empty memberInfo }">
                    <li><a href="${contextPath}/member/logout.do">로그아웃</a></li>
                    <li><a href="${contextPath}/mypage/myPageMain.do">마이페이지</a></li>
                    <li><a href="${contextPath}/cart/myCartList.do">장바구니</a></li>
                    <li><a href="#">주문배송</a></li>
                </c:when>
                <c:otherwise>
                    <li><a href="${contextPath}/member/loginForm.do">로그인</a></li>
                    <li><a href="${contextPath}/member/memberForm.do">회원가입</a></li>
                </c:otherwise>
            </c:choose>
            <li><a href="#">고객센터</a></li>
            <c:if test="${isLogOn==true and memberInfo.member_id =='admin' }">
                <li class="no_line"><a href="${contextPath}/admin/goods/adminGoodsMain.do">관리자</a></li>
            </c:if>

        </ul>
    </div>
    <br>
    <div id="search">
        <form name="frmSearch" action="${contextPath}/goods/searchGoods.do">
            <input name="searchWord" class="main_input" type="text" onKeyUp="keywordSearch()">
            <input type="submit" name="search" class="btn1" value="검 색">
        </form>
    </div>
    <div id="suggest">
        <div id="suggestList"></div>
    </div>
</body>

</html>

6. searchGoods.jsp에서는 키워드 검색이나 검색창에서 단어 검색 결과를 표시하는 기능을 구현한다.

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"
    isELIgnored="false"
    %>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<%
     //치환 변수 선언합니다.
      pageContext.setAttribute("crcn", "\r\n"); //Space, Enter
      pageContext.setAttribute("br", "<br/>"); //br 태그
%>

<head>
    <title>검색 도서 목록 페이지</title>
</head>

<body>
    <hgroup>
        <h1>컴퓨터와 인터넷</h1>
        <h2>오늘의 책</h2>
    </hgroup>
    <section id="new_book">
        <h3>새로나온 책</h3>
        <div id="left_scroll">
            <a href='javascript:slide("left");'><img src="${contextPath}/resources/image/left.gif"></a>
        </div>
        <div id="carousel_inner">
            <ul id="carousel_ul">
                <c:choose>
                    <c:when test="${ empty goodsList  }">
                        <li>
                            <div id="book">
                                <a>
                                    <h1>제품이없습니다.</h1>
                                </a>
                            </div>
                        </li>
                    </c:when>
                    <c:otherwise>
                        <c:forEach var="item" items="${goodsList }">
                            <li>
                                <div id="book">
                                    <a href="${contextPath}/goods/goodsDetail.do?goods_id=${item.goods_id}">
                                        <img width="75" alt="" src="${contextPath}/thumbnails.do?goods_id=${item.goods_id}&fileName=${item.goods_fileName}">
                                    </a>
                                    <div class="sort">[컴퓨터 인터넷]</div>
                                    <div class="title">
                                        <a href="${contextPath}/goods/goodsDetail.do?goods_id=${item.goods_id }">
                                            ${item.goods_title}
                                        </a>
                                    </div>
                                    <div class="writer">${item.goods_writer} | ${item.goods_publisher}</div>
                                    <div class="price">
                                        <span>
                                            <fmt:formatNumber value="${item.goods_price}" type="number" var="goods_price" />
                                            ${goods_price}원
                                        </span> <br>
                                        <fmt:formatNumber value="${item.goods_price*0.9}" type="number" var="discounted_price" />
                                        ${discounted_price}원(10%할인)
                                    </div>
                                </div>
                            </li>
                        </c:forEach>
                        <li>
                        </li>
                    </c:otherwise>
                </c:choose>

            </ul>
        </div>
        <div id="right_scroll">
            <a href='javascript:slide("right");'><img src="${contextPath}/resources/image/right.gif"></a>
        </div>
        <input id="hidden_auto_slide_seconds" type="hidden" value="0">

        <div class="clear"></div>
    </section>
    <div class="clear"></div>
    <div id="sorting">
        <ul>
            <li><a class="active" href="#">베스트 셀러</a></li>
            <li><a href="#">최신 출간</a></li>
            <li><a style="border: currentColor; border-image: none;" href="#">최근 등록</a></li>
        </ul>
    </div>
    <table id="list_view">
        <tbody>
            <c:forEach var="item" items="${goodsList }">
                <tr>
                    <td class="goods_image">
                        <a href="${contextPath}/goods/goodsDetail.do?goods_id=${item.goods_id}">
                            <img width="75" alt="" src="${contextPath}/thumbnails.do?goods_id=${item.goods_id}&fileName=${item.goods_fileName}">
                        </a>
                    </td>
                    <td class="goods_description">
                        <h2>
                            <a href="${contextPath}/goods/goodsDetail.do?goods_id=${item.goods_id }">${item.goods_title }</a>
                        </h2>
                        <c:set var="goods_pub_date" value="${item.goods_published_date }" />
                        <c:set var="arr" value="${fn:split(goods_pub_date,' ')}" />
                        <div class="writer_press">${item.goods_writer }저
                            |${item.goods_publisher }|
                            <c:out value="${arr[0]}" />
                        </div>
                    </td>
                    <td class="price"><span>${item.goods_price }원</span><br>
                        <strong>
                            <fmt:formatNumber value="${item.goods_price*0.9}" type="number" var="discounted_price" />
                            ${discounted_price}원
                        </strong><br>(10% 할인)
                    </td>
                    <td><input type="checkbox" value=""></td>
                    <td class="buy_btns">
                        <UL>
                            <li><a href="#">장바구니</a></li>
                            <li><a href="#">구매하기</a></li>
                            <li><a href="#">비교하기</a></li>
                        </UL>
                    </td>
                </tr>
            </c:forEach>
        </tbody>
    </table>
    <div class="clear"></div>
    <div id="page_wrap">
        <ul id="page_control">
            <li><a class="no_border" href="#">Prev</a></li>
            <c:set var="page_num" value="0" />
            <c:forEach var="count" begin="1" end="10" step="1">
                <c:choose>
                    <c:when test="${count==1 }">
                        <li><a class="page_contrl_active" href="#">${count+page_num*10 }</a></li>
                    </c:when>
                    <c:otherwise>
                        <li><a href="#">${count+page_num*10 }</a></li>
                    </c:otherwise>
                </c:choose>
            </c:forEach>
            <li><a class="no_border" href="#">Next</a></li>
        </ul>
    </div>

7. 실행 결과에서 검색창에 '자'를 입력하면 '자'가 들어간 키워드 목록이 표시된다.

- http://localhost/bookshop01/main/main.do

8. 이번에는 검색창에 '자바'를 입력한 후 검색을 클릭해 보자.

9. '자바'가 포함된 도서가 다음과 같이 결과 페이지에 표시된다.