서비스 프레임워크 설명서 |
검색 대상이 되는 sample 테이블은 카테고리 코드 (category_cd)와 카테고리명 (category_nm) 필드를 가지고 있다. 카테고리 코드 필드는 CATEGORY1부터 CATEGORY6까지의 값을 가지며 그에 해당하는 카테고리명 필드 값은 각각 "오늘", "사회", "정보과학", "연예스포츠", "정치경제", "기타"이다. 이제 검색 결과를 이 카테고리 코드로 그룹핑 하는 예제 페이지를 작성한다.
화면은 아래와 같이 각 카테고리가 탭으로 표시되는 형식이다. 탭 제목에 카테고리명과 각 카테고리에 속한 검색 레코드 개수가 함께 표시된다.
이를 위해서는 두 번의 검색이 필요하다. 먼저 카테고리 그룹별 건수를 구하기 위해 GROUP BY를 이용한 검색이 필요하고 다음 실제 키워드 등 검색 조건에 따른 검색이 필요하다.
GROUP BY를 이용한 검색과 실제 검색 모두 검색 조건은 같다. 따라서 검색 조건을 먼저 만들고 이 검색 조건을 이용하여 GROUP BY 및 실제 검색을 수행할 SearchQuery를 생성하도록 SearchQueryBuilder 를 수정한다.
1. <%!public static class SearchQueryBuilder { 2. private String query; 3. private QueryBuilder qb; // 검색 조건을 저장하기 위해 사용 4. 5. public SearchQueryBuilder(String query) { 6. this.query = query; 7. this.qb = new QueryBuilder(); 8. } 9. // 검색 조건을 구한다. 10. public void prepare(HttpServletRequest request) { 11. qb.whereColumnEquals("text_idx", query, "allwordthruindex"); 12. String dateRange = RequestUtils.getParameter (request, "date-range"); 13. if ("r".equals(dateRange)) { 14. qb.whereColumnInDateRange("regdate", 15. RequestUtils.getParameter(request, "date-from"), 16. RequestUtils.getParameter(request, "date-to")); 17. } else { 18. qb.whereColumnInDateRange("regdate", dateRange); 19. } 20. } 21. // GROUP BY 검색 시 사용할 쿼리를 구한다. 22. public SearchQuery getGroupByQuery() { 23. SearchQuery sq = new SearchQuery("sample", query); 24. sq.setWhereClause(qb.getWhereClause()); // GROUP BY 구문을 지정한다. 25. sq.setSortingClause("group by category_cd order by category_cd"); // GROUP BY 구문에 따라 그룹별 개수를 가져오도록 설정한다. 26. sq.setGroupBy(true); 27. return sq; 28. } 29. // 실제 검색에 사용할 쿼리를 구한다. 30. public SearchQuery getSearchQuery(HttpServletRequest request) { 31. SearchQuery sq = new SearchQuery("sample", query); 32. sq.setLimit(RequestUtils.getParameterInt(request, "rpp", 10)); 33. sq.setOffset(RequestUtils.getParameterInt(request, "p", 0) * sq.getLimit()); 34. sq.setWhereClause(qb.getWhereClause()); 35. qb.orderBy(RequestUtils.getParameterValues(request, "sort")); 36. sq.setSortingClause(qb.getSortingClause()); 37. return sq; 38. } 39. } 40. %>
이제 검색을 수행하는 JSP 코드를 수정하자.
1. … 2. CrzClient crzclient = new CrzClient("127.0.0.1", 9577); 3. SearchQueryBuilder builder = new SearchQueryBuilder(query); // 먼저 검색 조건을 구한다. 4. builder.prepare(request); // 다음 GROUP BY 검색을 수행하고 결과를 groups라는 세션 애트리뷰트에 저장한다. 5. SearchResultSet groups = crzclient.search(builder.getGroupByQuery()); 6. session.setAttribute("groups", groups); // 마지막으로 실제 검색을 수행한다. 7. SearchQuery sq = builder.getSearchQuery(request); 8. SearchResultSet srs = crzclient.search(sq); 9. pageContext.setAttribute("sq", sq); 10. pageContext.setAttribute("srs", srs); 11. …
Groups 애트리뷰트에 저장된 그룹 별 검색 개수를 표시하는 코드는 아래와 같다.
12. <c:if test="${not empty groups}"> 13. <ul id="categories" class="nav nav-tabs"> 14. <li class="active"><a href="#"> 15. 전체 (<fmt:formatNumber value="${groups.totalCount}" groupingUsed="true"/>) 16. </a></li> 17. <c:forEach var="group" items="${groups.rows}"> 18. <li><a href="#${group.key}"> 19. <fmt:message key="${group.key}"/> (<fmt:formatNumber value="${group.size}" groupingUsed="true"/>) 20. </a></li> 21. </c:forEach> 22. </ul> 23. </c:if>
각 그룹에 속한 검색 결과의 총합은 ${groups.totalCount}에 저장되며, 각 그룹의 대표 값과 그룹에 속한 검색 결과의 개수는 각각 ${group.key}와 ${group.size}로 구할 수 있다.
이제 각 그룹 탭을 누르면 해당 그룹에 속한 검색 결과만 필터링 하는 기능을 추가해보자. 그룹 탭을 클릭할 경우에는 그룹별 건수를 다시 구할 필요가 없고 category_cd 관련 검색 조건만 바꿔 새로 검색하면 된다. 이를 위해 categorize와 category라는 파라미터를 추가한다. Categorize 파라미터는 GROUP BY 검색을 수행할지 여부를 나타내고 category 파라미터는 검색할 카테고리를 나타낸다.
1. <form name="search-form" method="post" class="form-inline" role="form"> 2. .. 3. <input type="hidden" id="category" name="category" value="${param['category']}"/> 4. <input type="hidden" id="categorize" name="categorize" value="true"/> 5. </form>
이제 자바스크립트를 수정한다.
1. $("form[name=search-form]").submit(function(event) { // 새로 카테고리 그룹핑할 경우에는 전체 그룹을 대상으로 한다. 2. if ($("#categorize").val() == "true") $("#category").val(""); 3. … 4. } 5. … // 현재 필터링된 그룹탭을 선택한다. 6. $("#categories").find("a[href=#"+$("#category").val()+"]") .parent().addClass("active"); 7. $("#categories").on("click", "a", function() { // 카테고리 필터링 시에는 다시 그룹 별 건수를 구할 필요 없다. 8. $("#categorize").val(false); 9. $("#category").val($(this).attr("href").substring(1)); 10. $("form[name=search-form]").submit(); 11. }); 12. .. 13. $("#pagination").pagination(${srs.totalCount}, { 14. callback: function(p) { // 페이지 이동 시에도 다시 그룹 별 건수를 구할 필요 없다. 15. $("#categorize").val(false); 16. … 17. } 18. });
마지막으로 검색을 수행하는 JSP와 SearchQueryBuilder를 수정한다.
1. … 2. <%-- categorize 파라미터가 true일 경우에만 그룹 별 건수를 구한다. --%> if (RequestUtils.getParameterBool(request, "categorize", true)) { 3. SearchResultSet groups = crzclient.search(builder.getGroupByQuery()); 4. session.setAttribute("groups", groups); 5. } 6. .. 7. <%!public static class SearchQueryBuilder { 8. … 9. public SearchQuery getSearchQuery(HttpServletRequest request) { 10. … 11. String category = RequestUtils.getParameter(request, "category"); <%-- 카테고리 코드로 필터링하는 검색 조건을 추가한다. 전체일 경우 (category_cd가 “”일 경우에는 검색 조건에 추가되지 않는다.) --%> 12. qb.whereColumnEquals("category_cd", category); 13. sq.setWhereClause(qb.getWhereClause()); 14. … 15. } 16. } 17. %>
이제 그룹별 필터링 기능이 추가된 페이지를 실행해 보자. 아래의 예에서 "사회" 탭을 클릭 시 총 145건의 검색 결과 중 "사회" 카테고리로 필터링 된 2건의 검색 결과만 표시되는 것을 확인할 수 있다.