서비스 프레임워크 설명서 |
검색 대상이 되는 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건의 검색 결과만 표시되는 것을 확인할 수 있다.