project code search 다시

별하·2024년 7월 8일

프로젝트2

목록 보기
7/10

1. 동적 Mybatis 쿼리

-동적(Dynamic)으로 변화되어야하는 SQL 쿼리를 작성할 수 있도록 도와주는 마이바티스 태그
-실행 시 조건에 따라 where절이 바뀌어 실행되는 쿼리문
-컴파일 시 SQL문을 확정할 수 없는 경우 사용
-select, insert, update, delete 안에서 사용한다.
-if, choose, trim, foreach 태그를 제공한다.

- if 태그

  • test 속성의 값을 이용하여 조건문을 지정한다.
  • test 속성의 값은 true / false 가 되도록 만들어야 한다.
  • test 속성의 값은 문자열로 처리된다.
  • true 나 false 가 아니면 true 로 취급되어 버린다.
  • 쿼리문이 이상하면 false 처리하는 것이 아니고 그대로 실행해버리는 현상이 발생할 수 있다
    조건의 결과에 따라 쿼리의 추가 여부가 결정된다.

- choose, when, otherwise 태그

  • if ~ else / if ~ else 구문과 비슷한 제어문 태그
  • choose 안에 when 태그로 조건문을 작성한다.
  • when 태그에 test 속성으로 조건문을 작성하여 else if 같은 역할을 한다.
  • when 태그 들의 마지막으로 otherwise 태그를 사용하여 else 같은 역할을 한다.
<choose>
  <when test="조건문1">

  </when>    

  <when test="조건문2">

  </when>

  <otherwise>

  </otherwise>
</choose>

- trim 태그

  • WHERE 절이나 UPDATE 의 SET 절에서 사용된다.
  • 동적쿼리가 전달파라미터에 따라 추가되지 않는 상황에서 AND 나 OR 같은 키워드가 충돌날 수 있는 상황에서 사용한다.
  • SET 절에서는 마지막 ',' 를 고려해서 사용한다.
  • trim 태그의 속성
    • prefix : 접두어 지정
    • prefixOverrides : 접두어로 설정한 값과 겹쳐지면 제거할 항목을 지정
    • suffix : 접미어 설정
    • suffixOverrides : 접미어로 설정한 값과 겹쳐지면 제거할 항목을 지정

- foreach 태그

  • 반복되는 구문을 동적으로 생성할 때 사용하는 태그
  • 배열이나 HashMap 타입의 파라미터를 처리할 때 유용하다.
  • 마이바티스의 전달파라미터는 HashMap 으로 처리하는 것이 좋다.
  • 배열이나 리스트는 해시맵에 put 하여 전달한다.
  • checkBox 선택 항목에 대한 조건 처리를 할 때 유용하다.

- where 태그

  • (AND || OR ) 뭐가 먼저 들어올지 모르는 매개변수 값에 where 문을 쓰면 된다.
  • 추가 쿼리 문의 내용을 where 문 안에 작성하면 첫 조건이 AND로 시작할지라도 WHERE로 치환해준다.
    • 동적쿼리 사용시 WHERE 1=1 (and, or처리하기위한 식) 위험성 : 파라미터가 모두 null로 전달이 된다면 해당 쿼리들은 모두 전체 조회가 됨, 데이터 양에 따라 어플리케이션 응답 지연 문제 등이 발생 가능
    • where태그(trim태그)를 사용하면 where 1=1은 사용하지 않을 수 있다. but, 파라미터를 세팅하지 못하고 모두 null로 넘어오게 된다면 where 1=1과 동일하게 전체 조회 쿼리가 된다.
    • 예방법 : trim 태그를 사용할 때 where는 직접 작성하고(prefix="where"사용x), prefixOverrides에 and만 작성하여 사용

- trim 태그

  • 동적태그를 이용하며 상황에 맞추어 코드를 추가하거나 삭제하는 태그이다.
  • -1. trim prefix="[trim태그 앞에 붙을 코드]"
    -2. subfix="[trim태그 뒤에 붙을 코드]"
    -3. prefixOverrides="[trim태그 속에 있는 코드 중 상황에 맞추어 제외하거나 존재하게 할 코드]"
  • bno가 null이거나 아닐 때 AND를 붙일지 붙이지 않을 지 자동 선택하게 하는 예시
SELECT * FROM TBL_BOARD
<where>
	<if test="bno != null">]
    	BNO = #{bno}
    </if>
    <trim prefixOverrides="AND">
    	AND ROWNUm = 1
    </trim>
</where>

2. [jstl] fn:contains 포함되는 문자열 찾기

- fn:contains

  • 포함되는 문자열이 있으면 true를 반환한다.
<c:set var = "testStr" value = "test string"/>

<c:if test = "${fn:contains(testStr, 'test')}">
	<span>문자열 포함</span>
</c:if>

<c:if test = "${fn:contains(testStr, 'hello')}">
	<span>문자열 미포함</span>
</c:if>

3. search mapper.xml 수정

<select id="getStoreInfo" resultMap="mainMap">
	SELECT si.*
	FROM store_info si
	LEFT JOIN store_menu sm ON sm.store_id = si.store_id
	WHERE
	<trim prefixOverrides="AND|OR">
		<if test="params.keyword != null and params.keyword != ''">
			<choose>
				<when test="params.searchType == 'menu_name'">
					AND si.store_name LIKE '%' || #{params.keyword} || '%'
				</when>
				<when test="params.searchType == 'menu_category'">
					AND si.store_category LIKE '%' || #{params.keyword} || '%'
				</when>
				<otherwise>
					AND (si.store_name LIKE '%' || #{params.keyword} || '%'
					OR si.store_category LIKE '%' || #{params.keyword} || '%')
				</otherwise>
			</choose>
		</if>
		<if test="params.category != null and params.category != ''">
			AND store_category LIKE '%' || #{params.category} ||'%'
		</if>
	</trim>
</select>

- 해석

  • left join절 : store_info테이블의 모든 행을 포함시키고, store_menu테이블에서 일치하는 행이 있으면 그 데이터를 포함, 일치하지 않으면 store_menum의 데이터는 null
  • trim prefixOverrides : where절에서 동적 조건문을 작성할때 불필요한 and 또는 or를 제거
  • otherwise : params.searchType이 다른 값이거나 null경우, si.store_name 또는 si.store_category에서 키워드 검색

4. search jstl 수정

<c:if test="${not empty store.store_category}">
<span>카테고리 : 
<c:set var="seenCategories" value="" />
			                        
<!-- 특정 카테고리로 검색 시 -->
<c:forEach var="category" items="${fn:split(store.store_category, '/')}">
  <c:if test="${fn:contains(category, param.keyword)}">
    <c:if test="${not fn:contains(seenCategories, category)}">
      <c:if test="${!empty seenCategories}">
      	 /
      </c:if>
      ${category}
      <c:set var="seenCategories" value="${seenCategories}${category}/" />
    </c:if>
  </c:if>
</c:forEach>
			                        
<!-- "ALL" 또는  메뉴 이름으로 검색 시 모든 카테고리 출력 -->
<c:if test="${param.searchType == 'menu_name' || param.searchType == 'all' || param.searchType == null}">
  <c:forEach var="category" items="${fn:split(store.store_category, '/')}">
    <c:if test="${not fn:contains(seenCategories, category)}">
      <c:if test="${!empty seenCategories}">
      	/
      </c:if>
      ${category}
      <c:set var="seenCategories" value="${seenCategories}${category}/" />
    </c:if>
  </c:forEach>
</c:if>
</span><br>
</c:if>

- 해석

  • <c:set var="seenCategories" value="" /> : seenCategories변수를 빈 문자열로 초기화. 이는 이미 출력된 카테고리들을 추적하는데 사용
  • <c:if test="${not fn:contains(seenCategories, category)}"> : seenCategories에 해당 카테고리가 포함되지 않은 경우에만 카테고리를 출력
  • <c:if test="${!empty seenCategories}"> / ~~: seenCategoris가 비어있지 않다면 /를 출력하여 카테고리 간의 구분자를 추가, 현재 카테고리를 출력하고 seenCategories에 추가
  • 정리 : store.store_category문자열을 /로 분할하여 특정 검색 키워드('param.keyword')가 포함된 카테고리나 모든 카테고리를 출력한다. 이미 출력된 카테고리는 seenCategories 변수를 사용하여 중복 출력을 방지하며, 카테고리 간에는 /로 구분하여 출력한다.

0개의 댓글