Dynamic Query
검색 기능을 구현하기 위해 클래스와 메서드 등을 추가로 적지 않아도 되는 Query
MyBatis에서 지원하는 DynamicQuery 사용
*Mapper.xml에 sql 태그를 활용
조건문을 활용하여 특정 조건에 실행되는 sql을 구성
적용하고 싶은 sql에 <include refid=”sql태그 id”>를 활용해서 사전에 정의한 쿼리를 넣은 sql태그를 넣어줌
<!-- 동적 쿼리 -->
<!-- 중복되는 동적 SQL문을 미리 선언해 놓고 삽입하는 방식
<include refid="sql id" />을 통해 삽입해서 사용
-->
<sql id="search">
<if test="condition == 'title'">
<!-- 검색조건이 title이라면 -->
WEHER title LIKE '%'||#{keyword}||'%'
</if>
<if test="condition == 'writer'">
<!-- 검색조건이 writer라면 -->
WEHER writer LIKE '%'||#{keyword}||'%'
</if>
<if test="condition == 'content'">
<!-- 검색조건이 content라면 -->
WEHER content LIKE '%'||#{keyword}||'%'
</if>
<if test="condition == 'titleContent'">
<!-- 검색조건이titleContent라면 -->
WEHER title LIKE '%'||#{keyword}||'%'
OR content LIKE '%'||#{keyword}||'%'
</if>
</sql>
<select id="getArticleList" resultMap="BoardMap">
<!-- getArticleList는 Paging을 하기 위해서는 PageVO객체가 무조건 필요 -->
SELECT * FROM
(SELECT ROWNUM as rn, tbl.* FROM
(SELECT * FROM mvc_board
<include refid="search" />
<!-- sql태그에서 맞춰진 조건에 따라 WHERE 실행 -->
ORDER BY board_no DESC)
tbl)
<![CDATA[
WHERE rn > (#{page} -1) * #{cpp}
AND rn <= #{page} * #{cpp}
]]>
<!-- 해당 select에 전달되는 것이 PageVO객체이므로 해당 변수를 사용 -->
<!-- 부등호 <, >는 xml에서는 태그를 연다고 생각함으로 대체할 수 있는 문자(>(>), <(<))를 사용하거나
<![CDATA[]]>을 사용하면 부등호 사용가능-->
</select>
```
<br>
Mybatis
Mybatis는 매개변수(파라미터)를 2개 이상 보낼 때 추가 작업 필요
@Param을 이용해서 이름 지정
InterfaceMapper에서 특정 메소드의 매개변수들에 @Param(”xml에서 사용할 이름”)을 이용해서 붙여줌
xml파일에서 해당 값을 지목할 수 있는 이름 지정
List<BoardVO> getArticleList(@Param("paging") PageVO paging,
@Param("condition") String condition,
@Param("keyword") String keyword);
Map으로 포장
매개변수가 2개 이상 있는 메서드는 Mapper에게 데이터를 전달하기 위해 Map객체 활용해야함
key : xml에서 활용할 이름, value : 실제 값
InterfaceMapper에 매개변수로 Map객체를 활용
Sevice
@Override
public List<BoardVO> getArticleList(PageVO paging, String condition, String keyword) {
// Mapper에게 전달한 Map 데이터 생성
// key -> xml에서 활용할 이름, value -> 실제 값
Map<String, Object> data = new HashMap<>();
// 매개변수의 타입이 달라서 모두 담을 수 있도록 Object로 선언
data.put("paging", paging);
data.put("condition", condition);
data.put("keyword", keyword);
// List<BoardVO> listBoard = mapper.getArticleList(paging, condition, keyword);
List<BoardVO> listBoard = mapper.getArticleList(data);
}
클래스 디자인
클래스를 디자인 해서 객체에 모든 값을 넣어 하나의 객체를 매개 값으로 보내는 방법
클래스 안에는 keyword와 condition, PageVO에 대한 정보 모두 가지고 있음
Class
package com.spring.mvc.board.commons;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class SearchVO extends PageVO {
// pageVO에 상속을 받으면 SearchVO에 변수를 작성할 필요가 없음
private String keyword;
private String condition;
}
Service
@Override
public List<BoardVO> getArticleList(SearchVO search) {
// Mapper에게 전달한 Map 데이터 생성
// key -> xml에서 활용할 이름, value -> 실제 값
Map<String, Object> data = new HashMap<>();
// 매개변수의 타입이 달라서 모두 담을 수 있도록 Object로 선언
data.put("paging", search.getPage());
data.put("condition", search.getCondition());
data.put("keyword", search.getKeyword());
//List<BoardVO> listBoard = mapper.getArticleList(paging, condition, keyword);
List<BoardVO> listBoard = mapper.getArticleList(search);
return listBoard;
}
Mapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.spring.mvc.board.repository.IBoardMapper">
<!-- DB와 VO객체 간의 변수명이 다를 수 있으므로 해당 변수명 맞춰주는 작업
property는 VO 객체의 변수명 column은 DB 변수명 -->
<resultMap type="com.spring.mvc.board.model.BoardVO" id="BoardMap">
<id property="boardNo" column="board_no" />
<!-- pk라서 id 태그로 작성 -->
<result property="regDate" column="reg_date"/>
<result property="viewCnt" column="view_cnt"/>
<!-- pk가 아닌 데이터는 result 태그로 진행 -->
</resultMap>
<!-- 동적 쿼리 -->
<!-- 중복되는 동적 SQL문을 미리 선언해 놓고 삽입하는 방식
<include refid="sql id" />을 통해 삽입해서 사용
-->
<sql id="search">
<if test="condition == 'title'">
<!-- 검색조건이 title이라면 -->
WHERE title LIKE '%'||#{keyword}||'%'
</if>
<if test="condition == 'writer'">
<!-- 검색조건이 writer라면 -->
WHERE writer LIKE '%'||#{keyword}||'%'
</if>
<if test="condition == 'content'">
<!-- 검색조건이 content라면 -->
WHERE content LIKE '%'||#{keyword}||'%'
</if>
<if test="condition == 'titleContent'">
<!-- 검색조건이titleContent라면 -->
WHERE title LIKE '%'||#{keyword}||'%'
OR content LIKE '%'||#{keyword}||'%'
</if>
</sql>
<insert id="insert">
<!-- IBoardMapper와 연동하여 DB접근하여 DML 수행 -->
INSERT INTO mvc_board
(board_no, title, content, writer)
VALUES(board_seq.NEXTVAL, #{title}, #{content}, #{writer})
</insert>
<!-- 쿼리문을 작성할 때 '<', '>', '&' 등의 기호를 사용할 경우
XML파일에서 이를 그냥 사용할 경우, 태그로 인식되는 경우가 종종 있으므로
해당 기호가 태그가 아니라는 것을 표현하기 위해 <![CDATA[쿼리문]]>을 사용하면 쿼리 내용의 괄호나
특수문자를 마크업 언어로 인식하지 않고 문자열로 인식
-->
<select id="getArticleList" resultMap="BoardMap">
<!-- getArticleList는 Paging을 하기 위해서는 PageVO객체가 무조건 필요 -->
<!-- list에 표시하기 위해 keyword, condition, PageVO객체의 정보가 모두 필요함
그래서 interface에서 매개값으로 해당 정보가 모두 들어있는 SearchVO 객체를 넣어줌 -->
SELECT * FROM
(SELECT ROWNUM as rn, tbl.* FROM
(SELECT * FROM mvc_board
<include refid="search" />
<!-- sql태그에서 맞춰진 조건에 따라 WHERE 실행 -->
ORDER BY board_no DESC)
tbl)
<![CDATA[
WHERE rn > (#{page} -1) * #{cpp}
AND rn <= #{page} * #{cpp}
]]>
<!-- 해당 select에 전달되는 것이 PageVO객체이므로 해당 변수를 사용 -->
<!-- 부등호 <, >는 xml에서는 태그를 연다고 생각함으로 대체할 수 있는 문자(>(>), <(<))를 사용하거나
<![CDATA[]]>을 사용하면 부등호 사용가능-->
<!-- interface에서 @Param이라는 annotation을 지정하면서 이름도 붙였기 때문에 이름도 사용(paging.page 등등) -->
</select>
<select id="getArticle" resultMap="BoardMap">
SELECT * FROM mvc_board WHERE board_no = #{num}
</select>
<select id="countArticles" resultType="int">
<!-- 게시물 숫자가 리턴되므로 resultType 지정 -->
SELECT count(*) FROM mvc_board
<include refid="search" />
<!-- paging을 하기 위한 sql인데 검색 조건에 따라서 게시물 수가 달라지므로 배치 -->
</select>
<update id="updateArticle">
UPDATE mvc_board SET title = #{title}, content = #{content} WHERE board_no = #{boardNo}
</update>
<delete id="deleteArticle">
DELETE FROM mvc_board WHERE board_no = #{boardNo}
</delete>
</mapper>