본문 바로가기
Java/└ Mybatis

Mybatis) 동적쿼리 - 심화된 검색 기능 1-1 (폼 초기화)

by 박채니 2022. 8. 10.

안녕하세요, 코린이의 코딩 학습기 채니 입니다.

 

개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.


심화된 검색 기능

검색타입 (사번, 사원명, 이메일, 전화번호)과 성별을 이용하여 원하는 사원들을 섬세하게 조회할 수 있습니다.

그렇다면 사용자는 검색타입을 이용하거나 성별만을 이용하거나 검색타입+성별을 이용하여 검색할 수 있을 겁니다.

 

select, input 태그등은 사용자가 입력값을 작성하지 않아도 '' 빈 문자열로 값이 넘어가게 됩니다.

성별만 검색했을 때

하지만 radio는 입력하지 않으면 값이 넘어가지 않습니다. (null)

검색타입만 검색했을 때

추후 mapping에서 분기처리 시 참고!!


Controller

EmpSearchController2

@Log4j
@RequiredArgsConstructor
public class EmpSearchController2 extends AbstractController {
	private final EmpService empService;
	
	@Override
	public String doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String searchType = request.getParameter("searchType"); // "검색어" | "" | null
		String searchKeyword = request.getParameter("searchKeyword"); // "검색어" | "" | null
		String gender = request.getParameter("gender");	// "성별" | null
		Map<String, Object> param = new HashMap<>();
		param.put("searchType", searchType);
		param.put("searchKeyword", searchKeyword);
		param.put("gender", gender);
		
		List<Map<String, Object>> list = empService.search2(param);
		log.debug("list = " + list);
		request.setAttribute("list", list);
		
		return "emp/search2";
	}
}

 

Service

EmpServiceImpl

(interface 생략)

@Override
public List<Map<String, Object>> search2(Map<String, Object> param) {
    try(SqlSession sqlSession = getSqlSession()) {
        return empDao.search2(sqlSession, param);			
    }
}

 

Dao

EmpDaoImpl

(interface 생략)

@Override
public List<Map<String, Object>> search2(SqlSession sqlSession, Map<String, Object> param) {
    return sqlSession.selectList("emp.search2", param);
}

 

emp-mapper.xml

<select id="search2" resultMap="empMap">
    select
        e.*
    from (
        select
            e.*,
            decode(substr(emp_no, 8, 1), '1', '남', '3', '남', '여') gender
        from
            emp e
    ) e
    where
        1 = 1
        <if test="searchType != null and searchType != '' and searchKeyword != null and searchKeyword != ''">
            and
            ${searchType} like '%' || #{searchKeyword} || '%'
        </if>
        <if test="gender != null">
            and
            gender = #{gender}
        </if>
</select>

<resultMap type="map" id="empMap">
    <id column="emp_id" property="empId"/>
    <result column="emp_name" property="empName"/>
    <result column="emp_no" property="empNo"/>
    <result column="gender" property="gender"/>
    <result column="email" property="email"/>
    <result column="phone" property="phone"/>
    <result column="dept_code" property="deptCode"/>
    <result column="job_code" property="jobCode"/>
    <result column="sal_level" property="salLevel"/>
    <result column="salary" property="salary"/>
    <result column="bonus" property="bonus"/>
    <result column="manager_id" property="managerId"/>
    <result column="hire_date" property="hireDate"/>
    <result column="quit_date" property="quitDate"/>
</resultMap>

(값이 넘어오는 유형에 따라 if문의 조건을 ' != null ', '' 등으로 분기처리 해줌!)

 

사용자 검색 유형에는 총 4가지로 나뉘게 됩니다.

① 검색타입 + 성별 모두 검색한 경우

② 검색타입만 검색한 경우

③ 성별만 검색한 경우

④ 검색하지 않은 경우

 

이러한 모든 상황을 고려하기 위해서 반드시 true를 리턴하는 1 = 1을 where절의 조건으로 넣어주었습니다.

그 후 if문을 통해 검색타입/검색어가 있는 경우 'and 검색타입 like %검색어%'가 조건식으로 추가 되도록 해주었고,

gender가 있는 경우 또한 'and gender = '성별''가 조건식으로 추가 되도록 해주었습니다.

 

만약 where절을 아래처럼 설정한다고 가정해보겠습니다.

where
    <if test="searchType != null and searchType != '' and searchKeyword != null and searchKeyword != ''">
        ${searchType} like '%' || #{searchKeyword} || '%'
    </if>
    <if test="gender != null">
        and
        gender = #{gender}
    </if>

① 검색타입 + 성별 모두 검색한 경우 → 문제 없음!

② 검색타입만 검색한 경우 → 문제 없음!

③ 성별만 검색한 경우 → where and gender = '성별'로 처리 되어 문법 오류

④ 검색하지 않은 경우 → select * from 어쩌고 where 로 처리 되어 문법 오류

 

따라서 반드시 true를 리턴하는 1 = 1를 조건으로 대입해주어 이러한 상황들을 대비해줄 수 있습니다.

 

search2.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Mybatis실습</title>
<style>
div#emp-container{text-align:center;}
table.tbl-emp{
	margin:0 auto;
	border:1px solid; 
	border-collapse:collapse;
}
table.tbl-emp th, table.tbl-emp td{
	border:1px solid;
	padding:5px;
}
div#search-container{
	padding:15px 0;
}
table#tbl-search { margin:0 auto; }
table#tbl-search th,table#tbl-search td {padding:5px 15px; font-weight: normal; }
table#tbl-search td {text-align:left;}
</style>
</head>
<body>
<div id="emp-container">
	<h2>사원정보 </h2>
	<div id="search-container">
		<form name="empSearchFrm">
			<table id="tbl-search">
				<tr>
					<th colspan="2">
						<select name="searchType">
							<option value="">검색타입</option>
							<!-- required여부를 판단할 value="" 반드시 있어야함.-->
						    <option value="emp_id" ${param.searchType eq 'emp_id' ? 'selected' : ''}>사번</option>
			                <option value="emp_name" ${param.searchType eq 'emp_name' ? 'selected' : ''}>사원명</option>
			                <option value="email" ${param.searchType eq 'email' ? 'selected' : ''}>이메일</option>
			                <option value="phone" ${param.searchType eq 'phone' ? 'selected' : ''}>전화번호</option>
						</select>
						<input type="search" name="searchKeyword" value="${param.searchKeyword}" />
					</th>
				</tr>
				<tr>
					<th>성별</th>
					<td>
						<input type="radio" name="gender" id="gender1" value="남" ${param.gender eq '남' ? 'checked' : ''}/>
						<label for="gender1">남</label>
						<input type="radio" name="gender" id="gender2" value="여" ${param.gender eq '여' ? 'checked' : ''}/>
						<label for="gender2">여</label>
					</td>
				</tr>
				<tr>
					<th colspan="2">
						<input type="submit" value="검색" />
						<input type="reset" value="초기화" />
					</th>
				</tr>
			</table>
			
			
			
		</form>
	</div>
	
	<table class="tbl-emp">
		<tr>
			<th></th><!-- 1부터 넘버링 처리 -->
			<th>사번</th>
			<th>사원명</th>
			<th>주민번호</th><!--뒷6자리는 ******처리-->
			<th>성별</th>
			<th>이메일</th>
			<th>전화번호</th>
			<th>부서코드</th>
			<th>직급코드</th>
			<th>급여레벨</th>
			<th>급여</th><!--원화기호, 세자리마다 콤마표시-->
			<th>보너스율</th><!--percent로 표시-->
			<th>매니져 사번</th>
			<th>입사일</th><!--날짜형식 yyyy/MM/dd-->
			<th>퇴사여부</th>
		</tr>
		<!-- 조회된 데이터가 있는 경우와 없는 경우를 분기처리 하세요 -->
		<c:if test="${empty list}">
			<tr>
				<td colspan="14">조회된 정보가 없습니다.</td>
			</tr>
		</c:if>
		<c:if test="${!empty list}">
			<c:forEach items="${list}" var="emp" varStatus="vs">
				<tr>
					<td>${vs.count}</td>
					<td>${emp.empId}</td>
					<td>${emp.empName}</td>
					<td>
						${fn:substring(emp.empNo, 0, 8)}******
					</td>
					<td>${emp.gender}</td>
					<td>${emp.email}</td>
					<td>${emp.phone}</td>
					<td>${emp.deptCode}</td>
					<td>${emp.jobCode}</td>
					<td>${emp.salLevel}</td>
					<td>
						<fmt:formatNumber value="${emp.salary}" type="currency"/>
					</td>
					<td>
						<fmt:formatNumber value="${emp.bonus}" type="percent"/>
					</td>
					<td>${emp.managerId}</td>
					<td>
						<fmt:formatDate value="${emp.hireDate}" pattern="yyyy/MM/dd"/>
					</td>
					<td><fmt:formatDate value="${emp.quitDate}" pattern="yyyy/MM/dd" /></td>
				</tr>
			</c:forEach>
		</c:if>
	</table>
</div>

</body>
</html>

 


폼 초기화 (reset)

검색 후 폼을 초기화 하기 위하여 type="reset"인 초기화 버튼을 눌러도 검색타입, 검색어가 비어있는 상태로 돌아가지 않는 것을 확인할 수 있습니다.

 

이는 reset의 의미가 사용자의 생각과 다르기 때문입니다.

폼의 reset은 서버로부터 전달받은 html상태로 돌아감을 의미합니다.

 

따라서 초기화 버튼을 누르면, 검색타입과 검색어가 비어있는 상태로 만들기 위해서 아래와 같이 해결해주겠습니다.

<input type="button" onclick="location.href='${pageContext.request.contextPath}/emp/search2.do'" value="초기화" />