날아라쩡글이의 블로그입니다.
다이나믹쿼리 (resultMap) 본문
728x90
반응형
opt와value의 값이 하나도 안들어가면 where이 없도록 동적인 다이나믹쿼리를 해주는 것이 where태그이다.
where 태그를 이용해서 여러 값을 result해볼예정이다.
- pagination을 입력하자
요청 URL : localhost/book/list.do
localhost/book/list.do?page= ? 이러면 page가 값이 없을 때 error가 발생한다. - page가 null이거나 null이 아닐 때는 어떻게 해야할까?
- @GetMapping("/list.do")
public String list(@RequestParam(name = "page", defaultValue = "1", required = false) String page,
Criteria criteria ,Model model) { - @RequestParam(name="요청파라미터이름",required=필수요청파라미터의 여부, defultValue="기본값");
- name = 요청파라미터의 이름이다.
- required = 필수요청파라미터인지의 여부, true/false의 값만 가능하다. 기본값은 tru이다.
- @RequestParam의 설정없이 사용한 요청 파라미터용 매개변수는 전부 required가 true인 상태다.
- defaultValue = required가 false로 설정되어 있고, name에서 지정한 이름의 요청 파라미터가 존재하지 않을 때 변수에 대입한 기본값이다.
- <select id="searchBooks" parameterType="com.sample.form.Criteria" resultMap="BookResultMap">
select *
from (
select A.*, row_number() over(order by book_no desc) rn
from sample_spring_books A
<where>
<if test="opt != null and value != null">
<!-- 다이나믹 쿼리, 반응형 쿼리 -->
<choose>
<when test="opt == '제목'">
book_title like '%' || #{value} || '%'
</when>
<when test="opt == '저자'">
book_author = #{value}
</when>
<when test="opt == '출판사'">
book_publisher = #{value}
</when>
<when test="opt == '최소가격'">
book_price >= to_number(#{value})
</when>
<when test="opt == '최대가격'">
book_price < = to_number(#{value}) <!-- < -->
</when>
</choose>
</if>
</where>
)
where rn between #{beginIndex} and #{endIndex}
<!-- Criteria에 beginIndex과 endIndex가 있어야한다. -->
</select> - 이렇게 where절을 from바로 아래에 적어서 사용할 수 있다.
- 이부분은 pagination을 구하기 위하여 from절에 적어서 인라인뷰 쿼리로 where절을 사용할 수 있다.
- 만약 넘어오는 값이 없다면, where절은 없다고 인식이 된다.
- @GetMapping("/list.do")
- 이렇게 작성하다보면 select문이 여러개로 복잡화가 되는 것을 알 수 있다.
- 원래는 select문으로 전체적으로 작성하지만 resultMap으로 작성하면 좀 더 복잡성이 줄어들도록 작성할 수 있다.
- xml의 문서에는 20~30개의 select문이 존재한다. 그래서 resultMap을 도입을 하여, column과 property를 지정하여 쿼리가 반복적이니, 명시하지 않고 *으로 해결하도록 작성한것이다.
- ResultMap : mapping시켜놓고, 연결을 지어놓았다.
- ResultType : classType이나 기본자료형의 값이 작성이 되야한다.
- <resultMap id="BookResultMap" type="com.sample.vo.Book" >
<!-- primarykey는 id라고 적는다. -->
<id column="book_no" property="no"/>
<result column="book_title" property="title"/>
<result column="book_author" property="author"/>
<result column="book_publisher" property="publisher"/>
<result column="book_price" property="price"/>
<result column="book_discount_price" property="discountPrice"/>
<result column="book_pub_date" property="pubDate"/>
<result column="book_stock" property="stock"/>
<result column="book_updated_date" property="updatedDate"/>
<result column="book_created_date" property="createdDate"/>
</resultMap> - <select />태그에서 정의된 resultMap을 사용하기
- select id="searchBooks" parameterType="com.sample.form.Criteria" resultMap="BookResultMap">
<select id="getAllBooks" resultMap ="BookResultMap">
selct *
from sample_spring_books
</select> - resultMap은 select문으로 조회된 데이터의 컬럼명과 resultType에서 지정한 클래스의 프로퍼티명이 서로 다를 때 컬럼과 프로퍼티를 mapping시킨다.
- id 태그에는 primary key에 해당하는 컬럼을 정의한다.
- 조회결과를 담기 위해서 resultMap을 사용할 때는 반드시 resultMap에서 매핑하는 컬럼이 조회결과에 모두 포함되어 있어야한다.
- select를 현재 column이 10개니까 10개를 select할 때만 사용할 수 있다.
- mybatis는 정의된 BookResultMap을 참조해서 type에 명시된 com.sample.vo.Book객체를 생성한다.
- mybatis는 조회결과의 컬럼이름과 Book객체의 멤버변수에 저장해야할지를 <result />태그의 정보를 참조한다.
- select id="searchBooks" parameterType="com.sample.form.Criteria" resultMap="BookResultMap">
- 페이지네이션 입력하기
select *
from (
select A.*, row_number() over(order by book_no desc) rn
from sample_spring_books A
<where>
<if test="opt != null and value != null">
<!-- 다이나믹 쿼리, 반응형 쿼리 -->
<choose>
<when test="opt == '제목'">
book_title like '%' || #{value} || '%'
</when>
<when test="opt == '저자'">
book_author = #{value}
</when>
<when test="opt == '출판사'">
book_publisher = #{value}
</when>
<when test="opt == '최소가격'">
book_price >= to_number(#{value})
</when>
<when test="opt == '최대가격'">
book_price < = to_number(#{value}) <!-- < -->
</when>
</choose>
</if>
</where>
)
where rn between #{beginIndex} and #{endIndex}- 위에서 이렇게 설정한 것을 확인 할 수 있다.
- parameterType으로 온 com.sample.Criteria를 설정한다.
beginIndex와 endIndex을 넣고 setter/getter 를 지정한다. - pagination의 파일을 넣고, controller의 값을 정의한다.
- // 검색조건에 해당하는 총 데이터 갯수 조회
int totalRecords = bookService.getTotalRows(criteria);
//그래서 책의 조건의 총갯수를 찾을 때에도 opt&value의 값을 찾으러 들어간다.
// 현재 페이지 번호와 총 데이터 갯수를 전달해서 페이징 처리에 필요한 정보를 제공하는 pagination객체를 생성한다.
Pagination pagination = new Pagination(page, totalRecords);
//요청한 페이지에 대한 조회범위를 criteria에 저장
criteria.setBeginIndex(pagination.getBegin());
criteria.setEndIndex(pagination.getEnd());
//검색조건(opt, value)와 조회범위(beginIndex, endIndex)가 포함된 criteria를 서비스에 전달해서 데이터 조회
List<Book> books = bookService.searchBook(criteria);
model.addAttribute("books",books);
model.addAttribute("pagination", pagination);
- // 검색조건에 해당하는 총 데이터 갯수 조회
- Dao와 service에도 무조건 넣어준다.
- int getBookTotalRows(Criteria criteria); -->총 입력값에 대한 dao -> where의 설정에 따라서 값이 다르게 나오는데?! 이럴때 where태그를 생각하고 입력한다.
- <select id="getBookTotalRows" parameterType="com.sample.form.Criteria" resultType="int">
select count(*)
from sample_spring_books
<where>
<if test="opt != null and value != null">
<!-- 다이나믹 쿼리, 반응형 쿼리 -->
<choose>
<when test="opt == '제목'">
book_title like '%' || #{value} || '%'
</when>
<when test="opt == '저자'">
book_author = #{value}
</when>
<when test="opt == '출판사'">
book_publisher = #{value}
</when>
<when test="opt == '최소가격'">
book_price >= to_number(#{value})
</when>
<when test="opt == '최대가격'">
book_price < = to_number(#{value}) <!-- < -->
</when>
</choose>
</if>
</where>
<!-- 총 갯수에 대해서 다이나믹 쿼리를 짠다. -->
</select> - public int getTotalRows(Criteria criteria) {
return bookDao.getBookTotalRows(criteria);
} - criteria내의 시작과 끝페이지가 setter/getter로 들어가있는 것을 기억하자
- 그리고 list.jsp로와서 페이지네이션을 설정한다.
- <c:if test="${pagination.totalRecords gt 0 }">
<div class="row mb-3">
<div class="col">
<nav aria-label="Page navigation example">
<!-- pagin을 담아두었음 사용할 수 있다. -->
<ul class="pagination justify-content-center">
<!-- isExistPrev() 이전 블록 존재여부를 반환한다. -->
<li class="page-item">
<a class="page-link ${pagination.existPrev ? '' : 'disabled' }" href="list.do=${pagination.prevPage }" data-page=${pagination.prevPage }>이전</a></li>
<c:forEach var="num" begin="${pagination.beginPage }" end="${pagination.endPage }">
<li class="page-item ${pagination.pageNo eq num ? 'active' : '' } ">
<!-- pagination의 현재페이지를 출력하는데 num과 동일하면 active를 추가한다. -->
<a class="page-link" href="list.do?page=${num }" data-page=${num }>${num }</a></li>
</c:forEach>
<li class="page-item ${pagination.existNext ? '' : 'disabled' }">
<a class="page-link" href="list.do=${pagination.nextPage }" data-page=${pagination.nextPage }>다음</a></li>
</ul>
</nav>
</div>
</div>
</c:if> - 그리고 이벤트를 거는 것이다.
- 숫자를 클릭하면 opt와 value의 값이 함께 나오도록 submit이되도록 버튼을 입력하고 이전 버튼의 이벤트 핸들러 submit을 재정의한다.
- //페이지네이션의 링크를 클릭했을 때 실행될 이벤트 핸들러 함수를 등록한다.
$('.pagination a').click(function(event){
event.preventDefault(); //form태그와 a태그만 막을 수 있음. 이뤄지는 이벤트가 실행되지 않게 함
//클릭한 페이지내비게이션의 페이지번호 조회하기
var pageNo = $(this).attr("data-page");
//검색폼의 히든필드에 클릭한 페이지네비게이션의 페이지 번호 설정
$(':input[name=page]').val(pageNo);
//검색폼을 제출시키기 submit시키기
$('#form-search-book').trigger('submit');
}) - //검색버튼을 클릭했을 때 실행될 이벤트 핸들러 함수를 등록한다.
$("#btn-search-book").click(function(){
//검색옵션 값과 입력값을 조회한다.
var opt = $("select[name=opt]").val();
var value = $.trim($(":input[name=value]").val());
//검색옵션 값과 입력값이 모두 존재하면 페이지 번호를 1설정하고, 폼에서 onsubmit이벤트를 발생시켜서 폼입력값이 서버로 제출되게 한다.
if(opt && value) {
$(':input[name=page]').val("1");
$('#form-search-book').trigger('submit');
} else {
alert("검색조건 혹은 검색어를 입력하세요 ");
}
}); - 먼저 검색기능을 코딩하고, pagination의 코딩을 하지 않을 경우 변경을 해야하는 경우가 생긴다.
- 만능이 되는 함수를 만들지 많아야하며, 유지보수가 어렵기때문에
객체지향원칙중 단일책임의 원칙처럼 만능이 아닌 한가지에 책임이 될 수 있도록 쿼리를 작성해야한다.
반응형
'중앙 HTA (2106기) story > spring java framwork story' 카테고리의 다른 글
spring MVC가 jsp에서 실행되는 순서와 객체들 (0) | 2022.01.05 |
---|---|
Session어노테이션 & SessionUtils로 객체 담기 (0) | 2022.01.05 |
다이나믹 쿼리(select문 하나로 여러 쿼리를 조회하다.) (0) | 2022.01.04 |
RedirectAttributes,Model 의 차이점 (0) | 2022.01.02 |
Project Object Model.xml설정, 로그설정 (0) | 2021.12.31 |
Comments