spring/프로젝트

18. 검색 처리 (동적 쿼리)

yaha 2024. 1. 29. 21:00

페이징 처리에 사용했던 Criteria의 의도는 단순 pageNum과 amount라는 파라미터 수집을 하기 위해서 사용.

 

페이징 처리에 검색 조건 처리가 들어가면 Criteria 역시 변화가 필요.

 

검색 조건을 처리하기 위해서는 검색 조건(type)과 검색에 사용하는 키워드가 필요.

 

기존의 Criteria를 확장할 필요가 있음.

 

확장 하는 방법은 상속을 활용하거나 직접 Criteria 클래스를 수정하는 방식을 사용 가능.

 

일단 Criteria 클래스를 직접 수정하는 방법으로 진행.

 

Criteria 클래스를 수정.

 

검색에 필요한 type과 keyword를 추가.

 

검색 조건을 t, tc, tcw이런식으로 처리를 하려고 하면 

 

문자열이기 때문에 foreach문을 사용할 수 없음. 

 

배열이나 map 또는 set 같은게 필요함.

 

단순 문자열로는 처리할 수 없기에 배열로 만들어주는 작업이 필요.(변경)

 

그리고 Loop를 돌리기 위해서 배열이 필요하기에 처리하기위한 메서드를 생성.

 

public String[] getTypeArr() {
  return type == null? new String[] {}: type.split("");
}

 

type이 null이라면 빈 배열을 하나 만들어서 type을 split으로 쪼갠다. 가 대략적인 설명.

 

 

그리고 BoardMapper.xml에서 쿼리를 추가해줌.

 

<select id="getListWithPageing" resultType="org.zerock.domain.BoardVO">
    <![CDATA[
    select * from
    (
    select /*+ INDEX_DESC(tbl_board pk_board) */rownum rn, bno, title, writer,regdate, updateDate 
    from tbl_board 
    where
    ]]>

        <trim prefix="(" suffix=") AND" >
        <foreach collection="typeArr" item="type" separator="OR">
        <if test="type == 'T'.toString()">
            title like '%'||#{keyword}||'%'
        </if>
        <if test="type == 'C'.toString()">
            content like '%'||#{keyword}||'%'
        </if>
        <if test="type == 'W'.toString()">
            writer like '%'||#{keyword}||'%'
        </if>
        </foreach>

    <![CDATA[
     bno > 0 and rownum > 0 and rownum <= (#{pageNum} * #{amount})
    )
    where rn > ( #{pageNum} - 1 ) * #{amount}
    ]]>
</select>

 

검색 조건이 3가지이므로 총 6가지의 조합이 가능.

 

각 문자열을 이용해서 검색 조건을 결합하는 형태로 하면 3개의 동적 SQL 구문만으로 처리.

 

<foareach>를 이용해서 검색 조건들을 처리하는데 typeArr라는 속성을 이용.

 

MyBatis는 원하는 속성을 찾을 때 getTypeArr()과 같이 이름을 기반으로 두어서 검색하기 떄문에 Criteria에서 만들어둔 getTypeArr() 결과인 문자열 배열이 <foreach>의 대상이 됨.

 

동적 SQL을 이용해서 검색 조건을 처리하는 부분은 해당 데이터의 개수를 처리하는 부분에서도 동일하게 적용 되어야함.

 

가장 간단한 방법은 동적 SQL을 처리하는 부분을 그대로 복사해서 넣어줄 수 있지만, SQL을 수정하는 경우에는

매번 목록을 가져오는 SQL과 데이터 개수를 처리하는 SQL도 샅이 수정 해야함.

 

MyBatis는 <sql>이라는 태그를 이용해서 SQL의 일부를 별도로 보관하며, ㅍ필요한경우 include시킬 수 있음.

 

<sql id="criteria">
<trim prefix="(" suffix=") AND" >
    <foreach collection="typeArr" item="type" separator="OR">
        <if test="type == 'T'.toString()">
            title like '%'||#{keyword}||'%'
        </if>
        <if test="type == 'C'.toString()">
            content like '%'||#{keyword}||'%'
        </if>
        <if test="type == 'W'.toString()">
            writer like '%'||#{keyword}||'%'
        </if>
    </foreach>
</trim>
</sql>



--------------------------------

<select id="getListWithPageing" resultType="org.zerock.domain.BoardVO">
    <![CDATA[
    select * from
    (
    select /*+ INDEX_DESC(tbl_board pk_board) */rownum rn, bno, title, writer,regdate, updateDate 
    from tbl_board 
    where
    ]]>

    <include refid="criteria"></include>

    <![CDATA[
     bno > 0 and rownum > 0 and rownum <= (#{pageNum} * #{amount})
    )
    where rn > ( #{pageNum} - 1 ) * #{amount}
    ]]>
</select>

<select id="getTotalCount" resultType="int">
    select count(bno) from tbl_board where bno > 0
</select>

<select id="searchTest" resultType="org.zerock.domain.BoardVO">
<![CDATA[
    select * from tbl_board
    where
    ]]>
    <include refid="criteria"></include>
    <![CDATA[
    rownum < 10
    ]]>
</select>

 

 

이를 바탕으로 테스트 코드를 진행.

 

@Test
public void testSearchPaging() {
    Criteria cri = new Criteria();
    cri.setType("TCW");
    cri.setKeyword("Test");
    List<BoardVO> list = mapper.getListWithPageing(cri);

    list.forEach(b -> log.info(b));
}

실행된 SQL

TCW에 Test가 있는 단어를 10개씩 출력.