검색 처리
검색 기능 및 SQL
게시물 검색 기능
- 제목/내용/저자 같은 단일 항목 검색
- 제목 또는 내용, 제목 또는 저자, 내용 또는 저자, 제목 또는 내용 또는 저자와 같은 다중 항목 검색
검색 항목은 제목/내용/저자 등의 단일 항목을 검색하는 방법과 제목, 내용 등의 복합 항목을 검색하는 방법이 있습니다.

단일 주제에 대한 인라인 보기에서 필요한 데이터를 검색할 때 검색 조건을 적용해야 하므로 WHERE 문 뒤에 ROWNUM 조건이 오는 검색 조건을 추가하는 데 문제가 없습니다.
여러 항목 검색
두 개 이상의 조건이 첨부된 다중 항목 검색입니다.
예) 제목이나 내용에 문자열이 TEST인 게시물을 검색하고 싶다면 다음과 같이 작성한다.
select
*
from
(
select /*+INDEX_DESC(tbl_board pk_board) */
rownum rn, bno, title, content, writer, regdate, updatedate
from
tbl_board
where
title like '%Test%' or content like '%Test%'
and rownum <= 20
)
where rn > 10;
MyBatis의 동적 SQL
MyBatis의 동적 태그
MyBatis가 기존 iBatis에서 진화하면서 복잡한 동적 SQL을 생성하기 위해 많은 태그가 구성되었으므로 다음과 같이 사용되는 태그는 거의 없습니다.
- 만약에
- 선택하다 (언제, 그렇지 않으면)
- 트림 (여기서, 조정)
- 모든
검색 조건 처리 기준 변경
페이징 처리에 사용되는 기준의 의도는 단순히 pageNum 및 Amount라는 매개변수를 수집하는 것입니다. 검색 조건 처리가 페이징 처리로 전환되면 기준도 변경되어야 합니다.
검색 조건을 처리하기 위해서는 검색 조건(유형)과 검색에 사용된 키워드가 필요하므로 기존 기준을 확장해야 합니다.

기준 클래스 변경
// Criteria.java
package org.codehows.domain;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class Criteria {
private int pageNum;
private int amount;
private String type;
private String keyword;
public Criteria() {
this(1, 10);
}
public Criteria(int pageNum, int amount) {
this.pageNum = pageNum;
this.amount = amount;
}
public String() getTypeArr() {
return type == null? new String() {}: type.split("");
}
}
기준 클래스는 유형 및 키워드라는 변수를 추가합니다. getter/setter는 Lombok에 의해 생성되며 getTypeArr은 검색 조건이 각 문자(T, W, C)로 구성되어 있으므로 검색 조건을 배열로 변환하여 즉시 처리해야 합니다.
getTypeArr()을 사용하면 동적 MyBatis 태그를 사용할 수 있습니다.
BoardMapper.xml의 기준 처리
BoardMapper.xml은 기존 getListWithPaging()을 수정하여 동적 SQL을 처리합니다.
BoardMapper.xml에서 검색 및 페이징 처리
// BoardMapper.xml // getListWithPaging 부분 수정
... 생략 ...
<select id="getListWithPaging" resultType="org.codehows.domain.BoardVO">
<!(CDATA(
select
bno, title, content, writer, regdate, updatedate
from
(
select /*+INDEX_DESC(tbl_board pk_board) */
rownum rn, bno, title, content, writer, regdate, updatedate
from
tbl_board
where
))>
<trim prefix="(" suffix=") AND " prefixOverrides="OR">
<foreach item='type' collection="typeArr">
<trim prefix="OR">
<choose>
<when test="type == 'T'.toString()">
title like '%'||#{keyword}||'%'
</when>
<when test="type == 'C'.toString()">
title like '%'||#{keyword}||'%'
</when>
<when test="type == 'W'.toString()">
title like '%'||#{keyword}||'%'
</when>
</choose>
</trim>
</foreach>
</trim>
<!(CDATA(
rownum <= #{pageNum} * #{amount}
)
where rn > (#{pageNum} -1) * #{amount}
))>
</select>
... 생략 ...
테스트 코드를 작성합니다.

src/test/java에 있는 BoardMapperTests 클래스의 일부
// BoardMapperTests.java
... 생략 ...
@Test
public void testSearch() {
Criteria cri = new Criteria();
cri.setKeyword("새로");
cri.setType("TC");
List<BoardVO> list = mapper.getListWithPaging(cri);
list.forEach(board -> log.info(board));
}
testSearch()는 Criteria 객체의 유형과 키워드를 입력하여 원하는 SQL이 생성되고 있는지 확인하기 위한 것입니다.
MyBatis는 그것을 사용합니다
BoardMapper.xml에서 목록 및 데이터 수 처리
// BoardMapper.xml 부분 수정
<select id="getListWithPaging" resultType="org.codehows.domain.BoardVO">
<!(CDATA(
select
bno, title, content, writer, regdate, updatedate
from
(
select /*+INDEX_DESC(tbl_board pk_board) */
rownum rn, bno, title, content, writer, regdate, updatedate
from
tbl_board
where
))>
<include refid="criteria"></include>
<!(CDATA(
rownum <= #{pageNum} * #{amount}
)
where rn > (#{pageNum} -1) * #{amount}
))>
</select>
<select id="getTotalCount" resultType="int">
select count(*) from tbl_board
where
<include refid="criteria"></include>
bno > 0
</select>
그만큼
화면에서 검색 조건 편집
화면 검색은 다음을 위해 신중하게 설계되어야 합니다.
- 페이지 번호가 매개변수로 유지되었듯이 검색 조건과 키워드는 항상 화면 이동과 함께 전송되어야 합니다.
- 화면에서 검색 버튼을 클릭하면 새로운 검색을 하고 1페이지로 이동한다는 의미입니다.
- 한글의 경우 GET 방식으로 이동할 때 문제가 발생할 수 있으니 주의해야 합니다.
목록 화면에서 검색 처리
목록 화면인 list.jsp에서 검색 조건과 키워드를 입력할 수 있도록 HTML을 수정해야 합니다. views 폴더에서 list.jsp를 수정하고 page processing 바로 위에 다음 내용을 추가합니다.
list.jsp
// list.jsp
... 생략 ...
</c:forEach>
</table>
<div class="row">
<div class="col-lg-12">
<form id='searchForm' action="/board/list" method='get'>
<select name="type">
<option value="">--</option>
<option value="T">제목</option>
<option value="C">내용</option>
<option value="W">작성자</option>
<option value="TC">제목 or 내용</option>
<option value="TW">제목 or 작성자</option>
<option value="TWC">제목 or 내용 or 작성자</option>
</select>
<input type="text" name="keyword" />
<input type="hidden" name="pageNum" value="${pageMaker.cri.pageNum}">
<input type="hidden" name="amount" value="${pageMaker.cri.amount}">
<button class="btn btn-default">Search</button>
</form>
</div>
</div>
... 생략 ...
화면에는 다음과 같이 표시됩니다.

수정된 HTML을 보면