- 이 문서는 구루비에서 작성하였습니다.
- 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
- 출처 : http://wiki.gurubee.net/pages/viewpage.action?pageId=26741425&
- 구루비 지식창고의 모든 문서는 크리에이티브 커먼즈의 저작자표시-비영리-동일조건변경허락(BY-NC-SA) 라이선스에 따라 자유롭게 사용할 수 있습니다.
Dynamic Query의 사용
1. Dynamic Query의 이해
1.1 Dynamic Query란
- Parameter 값에 의해 쿼리를 동적으로 변환 해주는 기능이다.
- <dynamic> 태그를 사용하여 구현 할 수 있지만 생략이 가능하다.
- <dynamic> 태그를 사용하면, prepend, open, close 등의 속성을 사용 할 수 있다.
- prepend : 값이 있는 경우 맨 앞에 Append 된다. (추가적인 SQL 문장)
- open : 시작 값, prepend 다음에 붙음
- end : 종료 값
- ex) prepend="WHERE" open="(" end=")"
1.2 이항연산 요소
- 대표적으로 비교연산이 있다.
연산종류 | 설 명 | 예제 |
---|---|---|
<isEqual> | 프로퍼티와 값 또는 다른 프로퍼티와 같은지 비교 | #property# = compareValue |
<isNotEqual> | 프로퍼티와 값 또는 다른 프로퍼티와 같지 않은지 비교 | #property# <> compareValue |
<isGreaterThan> | 프로퍼티와 값 또는 다른 프로퍼티보다 큰지 비교 | #property# > compareValue |
<isGreaterEqual> | 프로퍼티와 값 또는 다른 프로퍼티보다 크거나 같은지 비교 | #property# >= compareValue |
<isLessThan> | 프로퍼티와 값 또는 다른 프로퍼티보다 작은지 비교 | #property# < compareValue |
<isLessEqual> | 프로퍼티와 값 또는 다른 프로퍼티보다 작거나 같은지 비교 | #property# <= compareValue |
이항연산 속성
- prepend : 값이 있는 경우 맨 앞에 Append 된다. (추가적인 SQL 문장) (옵션)
- property : 비교되는 프로퍼티 (필수)
- compareProperty : 비교되는 다른 프로퍼티 (필수 또는 compareValue)
- compareValue : 비교되는 값 (필수 또는 compareProperty)
- open : 시작부분에 넣을 문자. prepend 다음에 붙음.
- close : 끝에 넣을 문자
1.3 단항연산 요소
- 대표적으로 널값 체크연산이 있다
연산종류 | 설 명 |
---|---|
<isNull> | 프로퍼티가 null인지 체크 |
<isNotNull> | 프로퍼티가 null이 아닌지 체크 |
<isEmpty> | Collection, 문자열 또는 String.valueOf() 프로퍼티가 null이거나 empty("" or size() < 1)인지 체크 |
<isNotEmpty> | Collection, 문자열 또는 String.valueOf() 프라퍼티가 null이 아니거나 empty("" or size() < 1)가 아닌지 체크. |
단항연산 속성
- prepend : 값이 있는 경우 맨 앞에 Append 된다. (추가적인 SQL 문장) (옵션)
- property : 비교되는 프로퍼티 (필수)
- open : 시작부분에 넣을 문자. prepend 다음에 붙음.
- close : 끝에 넣을 문자
1.4 <iterate>
- Collection을 반복한다.
- 주로 IN연산을 하기 위해 사용한다.
Iterate 속성
- prepend : 값이 있는 경우 맨 앞에 Append 된다. (추가적인 SQL 문장) (옵션)
- property : 반복되기 위한 java.util.List타입의 프라퍼티(필수)
- open : 반복의 전체를 열기 위한 문자열, 괄호를 위해 유용하다. (옵션)
- close : 반복의 전체를 닫기 위한 문자열, 괄호를 위해 유용하다. (옵션)
- conjunction : 각각의 반복 사이에 적용되기 위한 문자열, IN 연산시 콤마(,) (옵션)
Iterate 예
<iterate prepend="AND" property="deptList" open="(" close=")" conjunction=","> #deptList[]# </iterate>
2. Dynamic Query 실습
2.1 검색용 모델객체(EmpSearch.java) 생성
- 부서번호, 이름, 직업으로 검색 할 때 사용하는 EmpSearch.java 객체를 생성한다.
com.oracleclub.study.mvc.model.EmpSearch.java
package com.oracleclub.study.mvc.model; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; /** * * @author oramaster */ public class EmpSearch { private int deptno; private String searchKey; private String searchValue; public int getDeptno() { return deptno; } public void setDeptno(int deptno) { this.deptno = deptno; } public String getSearchKey() { return searchKey; } public void setSearchKey(String searchKey) { this.searchKey = searchKey; } public String getSearchValue() { return searchValue; } public void setSearchValue(String searchValue) { this.searchValue = searchValue; } public String toString() { return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); } }
2.2 사원목록 조회 SQL 문 수정
- 사원목록 조회시 조건에 맞는 검색을 지원할 수 있도록 Dynamic Query를 사용하여 수정한다.
- 검색용 모델객체인 EmpSearch 객체를 typeAlias로 등록한다.
- selectEmpList에 parameterClass로 EmpSearch 객체를 전달 받는다.
- selectEmpList에 검색 조건절을 추가한다.
/src/main/resources/sqlmap/Emp.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap namespace="emp"> <typeAlias alias="emp" type="com.oracleclub.study.mvc.model.Emp"/> <typeAlias alias="empSearch" type="com.oracleclub.study.mvc.model.EmpSearch"/> <select id="selectEmpList" resultClass="emp" parameterClass="empSearch" cacheModel="cachemodel.empCache" > <![CDATA[ SELECT empno, ename, job, sal, NVL(mgr,0) mgr FROM emp WHERE empno > 0 ]]> <isNotEqual property="deptno" compareValue="0" > AND deptno = #deptno# </isNotEqual> <isNotEmpty property="searchValue"> <isEqual property="searchKey" compareValue="ename"> AND ename LIKE '%'||#searchValue#||'%' </isEqual> <isEqual property="searchKey" compareValue="job"> AND job LIKE '%'||#searchValue#||'%' </isEqual> </isNotEmpty> </select> <select id="selectEmp" resultClass="emp" parameterClass="int" > SELECT empno, ename, job, sal, NVL(mgr,0) mgr, deptno FROM emp WHERE empno = #empno# </select> <insert id="insertEmp" parameterClass="emp" > INSERT INTO emp (empno, ename, job, sal, mgr, hiredate, deptno) VALUES (#empno#, #ename#, #job#, #sal#, 0, #hiredate#, #deptno#) </insert> </sqlMap>
2.3 EmpDAO.java 수정
- selectEmpList 메소드에서 EmpSearch를 전달하도록 수정하였다.
com.oracleclub.study.mvc.dao.EmpDAO.java
... /** * 사원목록 정보 조회 * @return */ @SuppressWarnings("unchecked") public List<Emp> selectEmpList(EmpSearch search) { return (List<Emp>)getSqlMapClientTemplate().queryForList(NAMESPACE + "selectEmpList", search); } ...
2.4 EmpDAOTest.java 수정
- selectEmpList 메소드의 아규먼트가 변경되어 테스트케이스에서 컴파일 오류가 발생한다.
- 아래와 같이 EmpSearch 객체를 임의로 생성해서 테스트를 다시 해보자
com.oracleclub.study.mvc.dao.EmpDAOTest.java
... @Test public void testSelectEmpList() { EmpSearch search = new EmpSearch(); search.setDeptno(10); Assert.assertTrue(empDAO.selectEmpList(search).size() > 0); } ...
2.5 EmpBO.java 수정
- getEmpList 메소드에서 EmpSearch를 DAO에 전달하도록 수정하였다.
com.oracleclub.study.mvc.bo.EmpBO.java
... /** * 사원목록 조회 * * @return */ public List<Emp> getEmpList(EmpSearch search) { return empDAO.selectEmpList(search); } ...
2.6 EmpListController.java 수정
- 검색용 모델객체인 EmpSearch를 @ModelAttribute를 이용하여 jsp로부터 전달받는다.
- empBO.getEmpList()를 호출할 때 empSearch를 전달한다.
com.oracleclub.study.mvc.controller.EmpListController.java
package com.oracleclub.study.mvc.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.oracleclub.study.mvc.bo.EmpBO; import com.oracleclub.study.mvc.model.EmpSearch; /** * 사원목록 조회 * * @author : gurubee * */ @Controller public class EmpListController { @Autowired private EmpBO empBO; @RequestMapping(value = "/emp/list") public ModelAndView list(@ModelAttribute EmpSearch empSearch) { ModelAndView mv = new ModelAndView(); // 사원정보 조회 추가 mv.addObject("empList", empBO.getEmpList(empSearch)); // View 지정 // mvc-dispatcher-servlet.xml 파일의 viewResolver를 사용 mv.setViewName("emp/list"); return mv; } }
2.7 list.jsp 검색기능 추가
- 부서번호, 이름, 직업으로 검색할 수 있는 콤보박스, 텍스트박스를 추가하였다.
/WEB-INF/pages/emp/list.jsp
<%@ page language="java" contentType="text/html;charset=utf-8" pageEncoding="utf-8" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html lang="ko"> <head> <meta http-equiv="Content-type" content="text/html; charset=UTF-8"> <style> .error { color: #ff0000; } .errorblock{ color: #000; background-color: #ffEEEE; border: 3px solid #ff0000; padding:8px; margin:16px; } </style> <script type="text/javascript" language="JavaScript"> function showMessage(msg){ if(msg != ''){ alert(msg); } } function runRegisterForm(){ location.href = "/emp/form"; } function runDelete(){ if(isChecked(document.getElementsByName("empno"))){ if(confirm('정말 삭제하시겠습니까?')){ document.form.action = '/emp/remove'; document.form.submit(); }else{ return; } }else{ alert('삭제할 사원을 선택해 주세요!'); } } function isChecked(chkbox){ var flag = false; for(var i=0 ; i<chkbox.length ; i++){ if(chkbox[i].checked){ flag = true; break; } } return flag; } </script> </head> <body onload="showMessage('${msg}');"> <form name="sform" method="post" action="/emp/list"> <table width="50%" border="0"> <tr> <td width="100%" align="right"> <select name="deptno" class="combobox"> <option value="0" >부서</option> <option value="10" <c:if test="${empSearch.deptno==10}">selected</c:if>>10</option> <option value="20" <c:if test="${empSearch.deptno==20}">selected</c:if>>20</option> <option value="30" <c:if test="${empSearch.deptno==30}">selected</c:if>>30</option> </select> <select name="searchKey" class="combobox"> <option value="ename" <c:if test="${empSearch.searchKey=='ename'}">selected</c:if>>이름</option> <option value="job" <c:if test="${empSearch.searchKey=='job'}">selected</c:if>>직업</option> </select> <input type="text" name="searchValue" value="${empSearch.searchValue}" class="txtbox" size="25" /> <input type="submit" value="검색" /> <input type="button" value="등록" onclick="runRegisterForm();"/> <input type="button" value="삭제" onclick="runDelete();"/> </td> </tr> </table> <table width="50%" border="1"> <tr> <th>선택</th> <th>empno</th> <th>ename</th> <th>job</th> <th>sal</th> <th>mgr</th> <th>deptno</th> </tr> <c:forEach var="emp" items="${empList}" varStatus="c"> <tr > <td><input type="radio" name="empno" value="${emp.empno}" /></td> <td>${emp.empno}</td> <td><a href="/emp/view/${emp.empno}">${emp.ename}</a></td> <td>${emp.job}</td> <td><fmt:formatNumber value="${emp.sal}" type="number" /></td> <td>${emp.mgr}</td> <td>${emp.deptno}</td> </tr> </c:forEach> </table> </form> </body> </html>
2.8 테스트
- 사원목록 조회 화면에서 검색 기능을 테스트 해보자
- http://study.spring.com/emp/list
문서정보
- 이 문서는 구루비에서 작성하였습니다.
- 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
- 출처 : http://wiki.gurubee.net/pages/viewpage.action?pageId=26741425&
- 구루비 지식창고의 모든 문서는 크리에이티브 커먼즈의 저작자표시-비영리-동일조건변경허락(BY-NC-SA) 라이선스에 따라 자유롭게 사용할 수 있습니다.