본문 바로가기

국비교육/국비교육

day71 - 1108

MyBatis를 이용한 복합 검색

- 하나의 <form>에 여러 <input>이 있으며 이중 일부만 사용하여 조건 검색을 구현

 

** 구현하려는 검색창의 최종 형태

 

 

product-mapper

조건 조회

- 기본적으로 전체 조회

- 번호가 존재한다면 해당 번호로 조회

<select id = "complex1" parameterType = "map" resultType = "ProductDto">
    select * from product
    <if test = "no != null">
        where no = #{no}
    </if>	
</select>

 

기본 검색 조회

- 기본적으로 전체 조회

- 검색 카테고리(type)과 검색어(keyword)가 존재한다면 검색 조회

- <c:if> 태그처럼 해당 조건을 만족할 때만 <if> 안의 내용 동작

<select id = "complex2" parameterType = "map" resultType = "ProductDto">
    select * from product
    <if test = "type != null and keyword != null">
        where instr(${type}, #{keyword}) > 0
    </if>
</select>

 

복합 조회 (1)

- 조건의 유무에 상관없이 여러 조건을 연결하여 한번에 쓰기 위해 where 1=1을 붙인다

<select id = "complex3" parameterType = "map" resultType = "ProductDto">
    select * from product where 1=1
    <if test = "no != null">
        and no = #{no}
    </if>	
    <if test = "name != null">
        and instr(name, #{name}) > 0
    </if>
</select>

 

복합 조회 (2)

- <where> 태그를 이용하여 복합 조회(1)을 개선한 방식

- <where> 태그가 자동으로 where 1=1의 역할을 한다

<select id = "complex3" parameterType = "map" resultType = "ProductDto">
	select * from product where 1=1
	<where>
		<if test = "no != null">
			and no = #{no}
		</if>	
		<if test = "name != null">
			and instr(name, #{name}) > 0
		</if>
	</where>
</select>

 

복합 조회 (3)

- xml에서 <. >, & 등의 기호는 사용할 수 없다

- <![CDATA[ ]]>의 [ ] 안에 해당 기호가 포함된 구문을 넣으면 SQL문으로 인식한다

- 선택한 checkbox의 값들이 type in ( ) 안에 반복문으로 들어가게 된다

<select id = "complex5" parameterType = "ProductSearchVO" resultType = "ProductDto">
	select * from product
	<where>
		<if test = "no != null">
			and no = #{no}
		</if>	
		
		<if test = "name != null">
			and instr(name, #{name}) > 0
		</if>
		
		<choose>
			<when test = "minPrice != null and maxPrice != null">
				and price between #{minPrice} and #{maxPrice}
			</when>
			<when test = "minPrice != null">
				<![CDATA[and price >= #{minPrice}]]>
			</when>
			<when test = "maxPrice != null">
				<![CDATA[and price <= #{maxPrice}]]>
			</when>
		</choose>
		 
		 <choose>
		 	<when test = "beginMade != null and endMade != null"> <!-- 시작일과 종료일이 모두 있으면 -->
		 		and made between 
		 				to_date(#{beginMade}||''||'00:00:00', 'YYYY-MM-DD HH24:MI:SS') 
	 				and
		 				to_date(#{endMade}||''||'23:59:59', 'YYYY-MM-DD HH24:MI:SS')
		 	</when>
		 	<when test = "beginMade != null"> <!-- 시작일이 있으면 -->
		 		<![CDATA[and made >= to_date(#{beginMade}||''||'00:00:00', 'YYYY-MM-DD HH24:MI:SS')]]>
		 	</when>
		 	<when test = "endMade != null"> <!-- 종료일이 있으면 -->
		 		<![CDATA[and made <= to_date(#{endMade}||''||'23:59:59', 'YYYY-MM-DD HH24:MI:SS')]]>
		 	</when>
		 </choose>
		 
		  <if test = "type != null">
				and type in (
					<foreach collection = "type" separator = "," item = "t">#{t}</foreach>
				)
		  </if>
	</where>
</select>

 

복합 조회 (4)

- 복합 정렬을 포함한 최종 구문

<select id = "complex7" parameterType = "ProductSearchVO" resultType = "ProductDto">
	select * from product
	<where>
		<if test = "no != null">
			and no = #{no}
		</if>	
		<if test = "name != null">
			and instr(name, #{name}) > 0
		</if>
		
		<choose>
			<when test = "minPrice != null and maxPrice != null">
				and price between #{minPrice} and #{maxPrice}
			</when>
			<when test = "minPrice != null">
				<![CDATA[and price >= #{minPrice}]]>
			</when>
			<when test = "maxPrice != null">
				<![CDATA[and price <= #{maxPrice}]]>
			</when>	
		</choose>
		 
		<choose>
			<when test = "beginMade != null and endMade != null"> <!-- 시작일과 종료일이 모두 있으면 -->
				and made between 
			 		to_date(#{beginMade}||''||'00:00:00', 'YYYY-MM-DD HH24:MI:SS') 
		 		and
					to_date(#{endMade}||''||'23:59:59', 'YYYY-MM-DD HH24:MI:SS')
			</when>
			<when test = "beginMade != null"> <!-- 시작일이 있으면 -->
				<![CDATA[and made >= to_date(#{beginMade}||''||'00:00:00', 'YYYY-MM-DD HH24:MI:SS')]]>
			</when>	
			<when test = "endMade != null"> <!-- 종료일이 있으면 -->
				<![CDATA[and made <= to_date(#{endMade}||''||'23:59:59', 'YYYY-MM-DD HH24:MI:SS')]]>
			</when>
		</choose>
		<if test = "type != null">
			and type in (
				<foreach collection = "type" separator = "," item = "t">#{t}</foreach>
			)
		</if>
	</where>
		
	<!-- 정렬할 내용이 있다면 -->
	<if test = "sort != null">
		order by
		<foreach collection = "sort" item = "s" separator = ",">
			${s}
		</foreach>
	</if>
</select>

 

ProductDto

@Data
public class ProductDto {

	private int no;
	private String name;
	private String type;
	private int price;
	private Date made;
	private Date expire;
}

 

ProductDAO

public interface ProductDao {

	// 추상 메소드 - 복합 조회
	List<ProductDto> complexSearch(ProductSearchVO productSearchVO);
}

 

ProductDaoImpl

@Repository
public class ProductDaoImpl implements ProductDao {

	// 의존성 주입
	@Autowired
	private SqlSession sqlSession;

	// 추상 메소드 오버라이딩 - 복합 조회
	@Override
	public List<ProductDto> complexSearch(ProductSearchVO productSearchVO) {
		
		return sqlSession.selectList("product.complex7", productSearchVO);
	}
}

 

list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<h1>복합 검색 예제</h1>

<!-- 검색창 -->
<form method="get" autocomplete="off" class="search-form">
	번호 : <input type="text" name="no" value = "${param.no}"><br><br>
	이름 : <input type="text" name="name" value = "${param.name}"><br><br>
	분류 : 
	<label><input type="checkbox" name="type" value="과자">과자</label>
	<label><input type="checkbox" name="type" value="사탕">사탕</label>
	<label><input type="checkbox" name="type" value="주류">주류</label>
	<label><input type="checkbox" name="type" value="아이스크림">아이스크림</label>
	<br><br>
	가격 : <input type="text" name="minPrice" value = "${param.minPrice}"> ~ <input type="text" name="maxPrice" value = "${param.maxPrice}">
	<br><br>
	제조일 : <input type="text" name="beginMade" value = "${param.beginMade}"> ~ <input type="text" name="endMade" value = "${param.endMade}">
	<br><br>
	
	<!-- 정렬 -->
	1차 정렬 : 
	<select name = "sort">
		<option value = "">선택하세요</option>
		<option value = "price desc">높은 가격순</option>
		<option value = "price asc">낮은 가격순</option>
		<option value = "no asc">번호순</option>
		<option value = "made desc">최근 제조순</option>
	</select>
	<br><br>
	
	2차 정렬 : 
	<select name = "sort">
		<option value = "">선택하세요</option>
		<option value = "price desc">높은 가격순</option>
		<option value = "price asc">낮은 가격순</option>
		<option value = "no asc">번호순</option>
		<option value = "made desc">최근 제조순</option>
	</select>
	<br><br>
	
	<button type="submit">검색</button>
</form>

<!-- 결과화면 -->
<table width = "600" align = "center">
	<thead>
		<tr>
			<th>no</th>
			<th>name</th>
			<th>type</th>
			<th>price</th>
			<th>made</th>
			<th>expire</th>
		</tr>
	</thead>
	<tbody>
		<c:forEach var = "dto" items = "${list}">
		<tr>
			<td>${dto.no}</td>
			<td>${dto.name}</td>
			<td>${dto.type}</td>
			<td>${dto.price}</td>
			<td>${dto.made}</td>
			<td>${dto.expire}</td>
		</tr>
		</c:forEach>
	</tbody>
</table>

 

TestController 생성

- list.jsp의 form에서 전달된 값을 받아 복합 조회 수행

- form의 input 값을 모두 전달할 수 있는 VO가 필요하다

@Controller
public class TestController {
	
	@Autowired
	private ProductDao productDao;

	@RequestMapping("/")
	public String home(@ModelAttribute ProductSearchVO vo, Model model) {
		List<ProductDto> list = productDao.complexSearch(vo);
		model.addAttribute("list", list);
		return "list";
	}
}

 

ProductSearchVO

- form의 input 값을 모두 전달할 수 있는 VO

@Data
public class ProductSearchVO {
	private Integer no;
	private String name;
	private List<String> type;
	private Integer minPrice;
	private Integer maxPrice;
	private String beginMade;
	private String endMade;
	
	// 정렬 관련
	private List<String> sort;
}

 

list.jsp에서 <form>에 입력된 값만 전송하기

방법 1) form을 새로 생성하여 입력된 값만 보내는 방법

<script>
	//목표 : .search-form 전송을 차단하고 신규 form을 만들어서 입력한것만 전송
	$(function(){
		$(".search-form").submit(function(e){
			e.preventDefault(); // 기본이벤트 차단
			
			// 전송 방식이 GET인 form 태그를 변수로 지정
			var form = $("<form>").attr("method", "get");

			// 기존 form 태그안에 name이 있는 각각의 태그(input 태그)에 대해
			$(this).find("[name]").each(function(){
				if($(this).attr("type") == "checkbox"){ // 해당 태그의 type이 checkbox라면
					if($(this).prop("checked")) { // 해당 태그의 속성이 checked(체크됨)라면
						// 해당 input 태그의 이름과 값을 갖는 input 태그를 form에 붙여넣기
						$("<input>").attr("type", "hidden")
								.attr("name", $(this).attr("name"))
								.val($(this).val())
								.appendTo(form);
					}
				}
				else { // 해당 태그의 type이 checkbox가 아니라면(일반 입력창)
					// 일반 입력창의 값을 지정
					var value = $(this).val();
					if(value.length > 0) { //해당 입력창에 값이 입력이 된 경우
						// 해당 input 태그의 이름과 값을 갖는 input 태그를 form에 붙여넣기
						$("<input>").attr("type", "hidden")
								.attr("name", $(this).attr("name"))
								.val($(this).val())
								.appendTo(form);
					}
				}
			});
			
			$("body").append(form); // body에 해당 form을 생성
			form.submit(); // 생성된 form의 값을 전송
		});
</script>

 

방법 2) form에서 입력되지 않은 입력창의 name을 제거한 후 전송

<script>
	//목표 : .search-form 전송을 차단하고 신규 form을 만들어서 입력한것만 전송
	$(function(){
		$(".search-form").submit(function(e){
			e.preventDefault(); // 기본 이벤트 차단

			// 기존 form 태그안에 name이 있는 각각의 태그(input 태그)에 대해
			$(this).find("[name]").each(function(){
				// 해당 태그의 값을 변수로 지정
				var value = $(this).val();
				if(value.length == 0){ // 값이 0인 경우(입력이 안된 경우)
					// 현재 입력창의 name을 제거
					$(this).removeAttr("name");
				}
			});			
			return true; // 전송
		});
	});
</script>

'국비교육 > 국비교육' 카테고리의 다른 글

day73 - 1110  (0) 2022.11.12
day72 - 1109  (0) 2022.11.12
day70 - 1107  (0) 2022.11.07
day45 - 0928  (0) 2022.09.28
day44 - 0927  (0) 2022.09.27