Day 75 : 스프링과 MyBatis 연동
1. 라이브러리 내려받기
: 스프링과 MyBatis의 연동을 위해 org.mybatis.spring.SqlSessionFactoryBean과 org.mybatis.spring.SqlSessionTemplate 클래스를 이용
- pom.xml 파일 수정 (<dependency> 추가)
<!-- Mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.3.1</version>
</dependency>
<!-- Mybatis Spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.4</version>
</dependency>
2. Mybatis 설정 파일 작성
- sql-map-config.xml 작성
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- Alias 설정 -->
<typeAliases>
<typeAlias type="com.springbook.biz.board.BoardVO" alias="board"/>
</typeAliases>
<!-- SQL Mapper 설정 -->
<mappers>
<mapper resource="mappings/board-mapping.xml"/>
</mappers>
</configuration>
- board-mappings.xml 작성
<?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 : 루트 엘리먼트 -->
<mapper namespace="BoardDAO">
<resultMap id="boardResult" type="board">
<id property="seq" column="SEQ" />
<result property="title" column="TITLE" />
<result property="writer" column="WRITER" />
<result property="content" column="CONTENT" />
<result property="regDate" column="REGDATE" />
<result property="cnt" column="CNT" />
</resultMap>
<insert id="insertBoard" parameterType="board">
<![CDATA[
INSERT INTO BOARD(SEQ, TITLE, WRITER, CONTENT)
VALUES((SELECT NVL(MAX(SEQ), 0)+1 FROM BOARD), #{title}, #{writer}, #{content})
]]>
</insert>
<update id="updateBoard" parameterType="board">
<![CDATA[
UPDATE BOARD SET TITLE = #{title}, CONTENT = #{content} WHERE SEQ = #{seq}
]]>
</update>
<delete id="deleteBoard" parameterType="board">
<![CDATA[
DELETE BOARD WHERE SEQ = #{seq}
]]>
</delete>
<select id="getBoard" parameterType="board" resultMap="boardResult">
<![CDATA[
SELECT * FROM BOARD WHERE SEQ = #{seq}
]]>
</select>
<select id="getBoardList" parameterType="board" resultMap="boardResult">
<![CDATA[
SELECT * FROM BOARD
WHERE TITLE LIKE '%'||#{searchKeyword}||'%'
ORDER BY SEQ DESC
]]>
</select>
</mapper>
3. 스프링 연동 설정
: 스프링 설정 파일에 SqlSessionFactoryBean 클래스를 <bean> 등록
: Mybatis를 이용하려면 ①SqlSession 객체가 필요한데, SqlSession 객체는 ②SqlSessionFactoryBean 클래스로 SqlSessionFactory 객체를 생성(SqlSessionFactoryBuilder 클래스의 build() 메소드 이용)한 후 ③SqlSessionFactory 객체의 openSession() 메소드를 이용하여 얻을 수 있음
→ SqlSessionFactoryBean 클래스는 Mybatis에서 제공하므로 별도의 작성은 필요 없고, 스프링 설정 파일에서 <bean> 등록만 해주면 됨
- 스프링 설정 파일 (applicationContext.xml)
<!-- Mybatis 연동을 위한 SqlSessionFactoryBean 클래스 등록 -->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:sql-map-config.xml" />
</bean>
4. DAO 클래스 구현 - 방법1 : SqlSessionDaoSupport 클래스 구현
package com.springbook.biz.board.impl;
import java.util.List;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.springbook.biz.board.BoardVO;
@Repository //데이터베이스 연동을 처리하는 DAO 클래스
public class BoardDAOMybatis extends SqlSessionDaoSupport {
@Autowired
//스프링 컨테이너가 해당 메소드 자동 호출 (스프링 설정 파일에 <bean> 등록된 SqlSessionFactoryBean 객체를 인자로 받음)
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
super.setSqlSessionFactory(sqlSessionFactory);
}
public void insertBoard(BoardVO vo) {
System.out.println("===> Mybatis로 insertBoard() 기능 처리");
getSqlSession().insert("BoardDAO.insertBoard", vo);
}
public void updateBoard(BoardVO vo) {
System.out.println("===> Mybatis로 updateBoard() 기능 처리");
getSqlSession().update("BoardDAO.updateBoard", vo);
}
public void deleteBoard(BoardVO vo) {
System.out.println("===> Mybatis로 deleteBoard() 기능 처리");
getSqlSession().delete("BoardDAO.deleteBoard", vo);
}
public BoardVO getBoard(BoardVO vo) {
System.out.println("===> Mybatis로 getBoard() 기능 처리");
return (BoardVO) getSqlSession().selectOne("BoardDAO.getBoard", vo);
}
public List<BoardVO> getBoardList(BoardVO vo) {
System.out.println("===> Mybatis로 getBoardList() 기능 처리");
return getSqlSession().selectList("BoardDAO.getBoardList", vo);
}
}
5. DAO 클래스 구현 - 방법2 : SqlSessionTemplate 클래스를 <bean> 등록하여 사용
- 스프링 설정 파일 (applicationContext.xml) 수정
<!-- Mybatis 연동을 위한 SqlSessionFactoryBean 클래스 등록 -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:sql-map-config.xml" />
</bean>
<bean class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSession"></constructor-arg>
</bean>
→ SqlSessionTemplate 클래스는 Setter 메소드가 없어서 Setter 인젝션할 수 없음. 따라서 생성자 메소드를 이용한 Constructor 주입으로 처리해야 함. 또한 DAO 클래스 구현시 @Autowired 어노테이션을 이용하여 SqlSessionTemplate 객체를 의존성 주입 처리해야 함
- DAO 클래스
package com.springbook.biz.board.impl;
import java.util.List;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.springbook.biz.board.BoardVO;
@Repository //데이터베이스 연동을 처리하는 DAO 클래스
public class BoardDAOMybatis {
@Autowired
//스프링 컨테이너가 해당 객체 자동 호출
private SqlSessionTemplate mybatis;
public void insertBoard(BoardVO vo) {
System.out.println("===> Mybatis로 insertBoard() 기능 처리");
mybatis.insert("BoardDAO.insertBoard", vo);
}
public void updateBoard(BoardVO vo) {
System.out.println("===> Mybatis로 updateBoard() 기능 처리");
mybatis.update("BoardDAO.updateBoard", vo);
}
public void deleteBoard(BoardVO vo) {
System.out.println("===> Mybatis로 deleteBoard() 기능 처리");
mybatis.delete("BoardDAO.deleteBoard", vo);
}
public BoardVO getBoard(BoardVO vo) {
System.out.println("===> Mybatis로 getBoard() 기능 처리");
return (BoardVO) mybatis.selectOne("BoardDAO.getBoard", vo);
}
public List<BoardVO> getBoardList(BoardVO vo) {
System.out.println("===> Mybatis로 getBoardList() 기능 처리");
return mybatis.selectList("BoardDAO.getBoardList", vo);
}
}
6. Mybatis가 지원하는 Dynamic SQL로 검색 처리
- Dynamic SQL 적용 전 - 두 개의 쿼리 존재, 쿼리문의 개수 만큼 분기 처리 로직 추가 필요 - 유지보수 용이X
private final String BOARD_LIST_T = "select * from board where title like '%'||?||'%' order by seq desc";
private final String BOARD_LIST_C = "select * from board where content like '%'||?||'%' order by seq desc";
public List<BoardVO> getBoardList(BoardVO vo) {
System.out.println("===> JDBC로 getBoardList() 기능 처리");
//"제목"으로 검색 시
if(vo.getSearchCondition().equals("TITLE")) {
stmt = conn.prepareStatement(BOARD_LIST_T);
//"내용"으로 검색 시
} else if(vo.getSearchCondition().equals("CONTENT")) {
stmt = conn.prepareStatement(BOARD_LIST_C);
}
}
▼
- board-mapping.xml 수정 - <if> 조건에 따른 분기 처리 - 유지보수 용이
~ 생략 ~
<select id="getBoardList" parameterType="board" resultMap="boardResult">
SELECT * FROM BOARD WHERE 1=1
<if test="searchCondition == 'TITLE'">
AND TITLE LIKE '%'||#{searchKeyword}||'%'
</if>
<if test="searchCondition == 'CONTENT'">
AND CONTENT LIKE '%'||#{searchKeyword}||'%'
</if>
ORDER BY SEQ DESC
</select>
~ 생략 ~