Spring – Part 3 – 기본 웹 포스트 관리 09(검색 처리)

검색 처리

검색 기능 및 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는 그것을 사용합니다 SQL의 일부를 별도로 저장하는 태그이며 필요한 경우 임베딩 형태로 사용할 수 있습니다.

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>

그만큼 -Tag는 id라는 속성을 사용하여 필요한 경우 동일한 SQL의 일부를 재사용합니다.

화면에서 검색 조건 편집

화면 검색은 다음을 위해 신중하게 설계되어야 합니다.

  • 페이지 번호가 매개변수로 유지되었듯이 검색 조건과 키워드는 항상 화면 이동과 함께 전송되어야 합니다.
  • 화면에서 검색 버튼을 클릭하면 새로운 검색을 하고 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을 보면 -페이징 처리를 위해 생성된 태그

태그가 추가되었습니다.

기본 동작이기 때문에