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 |