Collapse AllExpand All

4.9. 상세 검색

상세 검색 기능을 추가해보자. 상세 검색 기능에서는 키워드 외에 기간과 정렬 조건을 검색 조건에 추가할 수 있게 하였다. 상세 검색을 위한 폼을 아래와 같이 먼저 추가한다. (가독성을 위해 태그 및 태그 속성들은 생략했다.)

1.	…
2.	<a data-target="#detailed-search" role="button" 
      class="btn btn-link" data-toggle="collapse">
       <small>상세 검색</small>
    </a>
3.	…
4.	<form name="detailed-search-form" class="form-horizontal" 
         role="form">
5.	<div id="detailed-search" class="box box-bordered collapse">
6.	…
7.	<labe>키워드</label>
8.	<input type="text" name="query" class="form-control" />
9.	<label>기간</label>
10.	<label><input type="radio" name="date-range" value=""/> 
            전체</label>
11.	<label><input type="radio" name="date-range" value="d"/> 
            최근 1일</label>
12.	<label><input type="radio" name="date-range" value="w"/> 
            최근 1주</label>
13.	<label><input type="radio" name="date-range" value="m"/> 
            최근 1달</label>
14.	<label><input type="radio" name="date-range" value="y"/> 
            최근 1년</label>
15.	<label><input type="radio" name="date-range" value="r"/> 
           직접입력</label>
16.	<input type="text" name="date-from"/> - 
     <input type="text" name="date-to"/>
17.	<label>정렬</label>
18.	<label><input type="radio" name="sort" value=""/> 정확도</label>
19.	<label><input type="radio" name="sort" value="regdate desc"/> 
            최신순</label>
20.	<button type="submit" class="btn btn-primary">검색</button>
21.	<button type="reset" class="btn" id="reset">초기화</button>
22.	…
23.	</div>
24.	</form>
25.	…

결과

추가된 폼은 아래와 같이 표시된다.

그림 C.12. 상세 검색

상세 검색

"상세 검색" 앵커 클릭 시 "상세 검색" 폼이 보이게 하는 것은 bootstrap의 Collapse를 활용하였다.

상세 검색 후 페이지 이동 시 혹은 금칙어, 추천 검색어, 오타 교정 등의 처리를 위해 키워드 검색 폼(search-form)이 포함하는 p, original-query 등의 입력 필드 값들도 함께 서버로 전달되어야 한다. 이를 위해 상세 검색 폼(detailed-search-form)의 검색 버튼 클릭 시 상세 검색 폼을 제출하지 않고 사용자가 입력한 검색 조건들을 키워드 검색 폼에 복사 후 사용자 검색 폼을 제출한다.

아래와 같이 키워드 검색 폼에 상세 검색 폼의 검색 조건들을 추가한다. 페이지 이동 시 검색 조건이 유지될 수 있게 하기 위해 각 앨리먼트의 값들은 요청 파라미터 값들로 초기화한다.

1.	…
2.	<form name="search-form" method="post" class="form-inline" 
         role="form">
3.	…
<input type="hidden" id="date-range" name="date-range" 
       value="${param['date-range']}"/>
4.	<input type="hidden" id="date-from" name="date-from" 
          value="${param['date-from']}"/>
5.	<input type="hidden" id="date-to" name="date-to" 
          value="${param['date-to']}"/>
6.	<input type="hidden" id="sort" name="sort" 
          value="${param['sort']}"/>
7.	</form>
8.	…

이렇게 키워드 검색 폼에 상세 검색 폼의 검색 조건들을 복사하지 않고 페이지 이동 등을 처리하기 위해 세션 변수에 처음 검색 조건을 저장한 후, 페이지 이동 시 세션 변수에 저장된 검색 조건을 재사용할 수도 있다. (세션 변수를 너무 많이 사용하면 WAS가 사용할 수 있는 가용 메모리가 줄어들므로 가급적 세션 변수 사용은 자제하는 것이 바람직하다.)

이제 상세 검색과 관련된 자바스크립트를 작성해 보자. 먼저 상세 검색 폼의 각 검색 조건을 키워드 검색 폼에 초기화된 값들로 일치시켜 상세 검색 폼을 보여줄 때 현재 검색 조건을 확인할 수 있게 한다.

1.	$(function() {
2.	…
3.	$f = $("form[name=detailed-search-form]");
4.	$f.find("input[name=query]").val($("#query").val());
5.	$f.find("input[name=date-range]").filter("[value="+
      $("#date-range").val() + "]").prop("checked",true);
6.	$f.find("input[name=date-from]").val($("#date-from").val());
7.	$f.find("input[name=date-to]").val($("#date-to").val());
8.	$f.find("input[name=sort]").filter("[value=\""+
      $("#sort").val()+"\"]").prop("checked",true);
9.	});

다음 상세 검색 폼 제출 시 검색 조건들을 키워드 검색 폼으로 복사하고 키워드 검색 폼을 대신 제출한다.

10.	$f.on("submit", function(e) {
  // 상세 검색 폼이 제출되지 못하도록 디폴트 핸들러 실행을 막는다.
11.	  e.preventDefault();
  // 검색 조건들을 키워드 검색 폼으로 복사한다.
12.	  $("#date-range").val($f.find("input[name=date-range]:checked")
                             .val());
13.	  $("#date-from").val($f.find("input[name=date-from]").val());
14.	  $("#date-to").val($f.find("input[name=date-to]").val());
15.	  $("#sort").val($f.find("input[name=sort]:checked").val());
16.	  $("#query").val($f.find("input[name=query]").val());
  // 키워드 검색 폼을 제출한다.
17.	  $("form[name=search-form]").submit();
18.	});

상세 검색의 경우 검색 조건이 복잡해졌다. 검색 조건으로부터 SearchQuery 객체를 만드는 클래스를 아래와 같이 SearchQueryBuilder 라는 이름으로 구현한다.

1.	<%!public static class SearchQueryBuilder {
2.	  private String query;
3.	
4.	  public SearchQueryBuilder(String query) {
5.	    this.query = query;
6.	  }
7.	  
8.	  public SearchQuery getSearchQuery(HttpServletRequest request) {
9.		QueryBuilder qb = new QueryBuilder();
    // 키워드 검색 조건
10.	    qb.whereColumnEquals("text_idx", query, "allwordthruindex");
11.	    String dateRange = RequestUtils.getParameter
                           (request, "date-range");
12.	    if ("r".equals(dateRange)) {
      // 기간이 직접 입력일 경우
13.	      qb.whereColumnInDateRange("regdate", 
          RequestUtils.getParameter(request, "date-from"), 
          RequestUtils.getParameter(request, "date-to"));
14.	    } else {
     // 기간이 전체, 최근1일, 최근1주, 최근1달, 최근1년일 경우
15.	      qb.whereColumnInDateRange("regdate", dateRange);
16.	    }
    // 정렬 기준
17.	    qb.orderBy(RequestUtils.getParameterValues(request, "sort"));
18.	    
19.	    SearchQuery sq = new SearchQuery("sample", query);
20.	    sq.setLimit(RequestUtils.getParameterInt(request, "rpp", 10));
21.	    sq.setOffset(RequestUtils.getParameterInt(request, "p", 0) 
                                  * sq.getLimit());
22.	    sq.setWhereClause(qb.getWhereClause());
23.	    sq.setSortingClause(qb.getSortingClause());
24.	    return sq;
25.	  }
26.	}
27.	%>

이제 SearchQueryBuilder를 이용해서 검색 결과를 구하도록 JSP 스크립트를 변경한다.

1.	…
2.	CrzClient crzclient = new CrzClient("127.0.0.1", 9577);
3.	SearchQueryBuilder builder = new SearchQueryBuilder(query);
4.	SearchQuery sq = builder.getSearchQuery(request);
5.	SearchResultSet srs = crzclient.search(sq);
6.	…