관리 메뉴

거니의 velog

(7) 마이바티스 사용하기 본문

Java_Spring Boot

(7) 마이바티스 사용하기

Unlimited00 2023. 11. 28. 12:40

* 이번에는 스프링 부트에서 마이바티스 기능을 사용해 보자.


(1) 마이바티스 적용해 회원 기능 구현하기

* 먼저 마이바티스를 적용하여 회원 조회 기능을 구현해 보자.

1. 새 프로젝트 myboot03을 생성할 때 MyBatis 항목의 체크박스에 체크한다.

2. 프로젝트 루트 디렉터리에 libs 폴더를 만들고 마이바티스에서 연동할 오라클 데이터베이스 드라이버인 ojdbc6.jar를 복사해 붙여 넣는다.

3. build.gradle에서는 로컬에 위치하는 오라클 드라이버를 로컬 리포지토리에 추가하는 설정을 한다. 그리고 반드시 프로젝트 이름 위에서 마우스 오른쪽 버튼을 클릭한 후 Gradle > Refresh Gradle Project를 선택한다.

buildscript {
	ext {
		springBootVersion = '2.0.6.RELEASE'
	}
	repositories {
		mavenCentral()
	}
	dependencies {
		classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
	}
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'com.myboot03'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
	mavenCentral()
}

dependencies {

	implementation('org.springframework.boot:spring-boot-starter-jdbc')
	implementation('org.springframework.boot:spring-boot-starter-web')
	implementation('org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.2')
	implementation('org.apache.tomcat.embed:tomcat-embed-jasper') // JSP를 사용하기 위해 반드시 추가한다.
    implementation('javax.servlet:jstl:1.2') // JSP를 사용하기 위해 반드시 추가한다.
	implementation fileTree(dir: 'libs', include: ['*.jar']) // 프로젝트 루트 디렉터리의 libs 디렉터리의 jar 파일을 읽어 들인다.
    implementation files('libs/ojdbc6.jar') // 오라클 드라이버를 로컬 리포지토리에 추가한다.
    implementation('org.apache.tiles:tiles-jsp:3.0.4')
    
	runtimeOnly('com.h2database:h2')
	testImplementation('org.springframework.boot:spring-boot-starter-test')

}

4. application.properties에서는 데이터베이스 연결 정보와 마이바티스 설정 파일 위치를 지정한다. 그리고 마이바티스 매퍼 파일에 사용할 alias 클래스의 패키지 이름을 지정한다. 그러면 해당 패키지에 있는 클래스는 자동으로 alias로 변환된다.

#Server
server.port=8090
server.session.timeout=360000

#Spring MVC
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

#Database config
#데이터베이스 연결 정보를 설정한다.
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:XE
spring.datasource.username=scott
spring.datasource.password=tiger
spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver

#mybatis config
#마이바티스 설정 파일 위치를 지정한다.
mybatis.config=classpath:mybatis-config.xml

#매퍼 파일에서 alias를 쓰기위한 패키지 지정
mybatis.type-aliases-package=com.myboot03.member.vo

#한글 인코딩 설정
server.servlet.encoding.charset=UTF-8  
server.servlet.encoding.enabled=true  
server.servlet.encoding.force=true

5. 다음으로 마이바티스 설정 파일을 구현하기 위해 src/main/resources 폴더에 mybatis.mappers 폴더를 만든 후 member.xml 파일을 생성한다.

6. 마이바티스 설정 파일인 mybatis-config.xml을 src/main/resources 폴더에 추가한 후 다음과 같이 매퍼 파일의 위치를 지정한다.

<?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>

	<mappers>
	
		<!-- src/main/resources 에 위치한 매퍼 파일을 지정한다. -->
		<mapper resource="mybatis/mappers/member.xml" />
		
		<!-- 다른 매퍼 파일을 지정한다. -->
		<!-- 
			<mapper resource="mybatis/mappers/board.xml"/> 
		-->
		
	</mappers>
	
</configuration>

7. 회원 관련 SQL문을 설정하는 매퍼 파일은 이전에 실습한 member.xml을 수정하여 사용한다. 달라진 점은 namespace에 DAO 인터페이스 이름을 패키지 이름까지 포함해서 지정했다는 것이다. 각 SQL문의 id는 DAO 인터페이스에 선언된 추상 메서드 이름과 일치해야 한다.

<?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">

<!--  
	namespace의 값을 SQL문 호출 시 사용하는 MemberDAO 인터페이스 이름으로 수정한다.
-->
<mapper namespace="com.myboot03.member.dao.MemberDAO">

	<resultMap id="memResult" type="memberVO">
		<result property="id" column="id" />
		<result property="pwd" column="pwd" />
		<result property="name" column="name" />
		<result property="email" column="email" />
		<result property="joinDate" column="joinDate" />
	</resultMap>

	<select id="selectAllMemberList" resultMap="memResult">
      <![CDATA[
        select * from t_member order by joinDate desc			
      ]]>
	</select>

	<insert id="insertMember" parameterType="memberVO">
		<![CDATA[
		 insert into t_member(id,pwd, name, email)
		 values(#{id}, #{pwd}, #{name}, #{email})
		]]>
	</insert>

	<update id="updateMember" parameterType="memberVO">
	     <![CDATA[
		     update t_member
		     set pwd=#{pwd}, name=#{name}, email=#{email}
		     where
		     id=#{id}
	      ]]>
	</update>

	<delete id="deleteMember" parameterType="String">
		<![CDATA[
		   delete from  t_member
		   where
		   id=#{id}
		]]>
	</delete>
	
	<select id="loginById" resultType="memberVO" parameterType="memberVO">
		<![CDATA[
			select * from t_member	
			where id=#{id} and pwd=#{pwd}		
		]]>
	</select>

</mapper>

8. 자바 클래스들은 이전에 실습한 파일을 사용한다. 다음과 같이 src/main/java 패키지 하위에 복사해서 붙여 넣는다. JSP 파일은 src/main 폴더 하위에 webapp/WEB-INF/views 폴더를 만든 후 이전에 실습한 JSP 파일을 복사해 붙여 넣는다.

9. 아직 인터셉터를 적용하기 전이므로 컨트롤러 클래스 ModelAndView에 뷰이름을 직접 지정한다.

[MemberControllerImpl.java]

package com.myboot03.member.controller;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.myboot03.member.service.MemberService;
import com.myboot03.member.vo.MemberVO;

@Controller("memberController")
public class MemberControllerImpl implements MemberController {
	
	@Autowired
	private MemberService memberService;

	@Autowired
	private MemberVO memberVO;

	@Override
	@RequestMapping(value = "/member/listMembers.do", method = RequestMethod.GET)
	public ModelAndView listMembers(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// public String listMembers(HttpServletRequest request, HttpServletResponse
		// response) throws Exception {
		// String viewName = (String)request.getAttribute("viewName");
		List membersList = memberService.listMembers();
		// ModelAndView mav = new ModelAndView(viewName);
		ModelAndView mav = new ModelAndView("/member/listMembers"); // 뷰이름을 직접 지정한다.

		mav.addObject("membersList", membersList);
		return mav;
	}

	@Override
	@RequestMapping(value = "/member/addMember.do", method = RequestMethod.POST)
	public ModelAndView addMember(@ModelAttribute("member") MemberVO member, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		request.setCharacterEncoding("utf-8");
		int result = 0;
		result = memberService.addMember(member);
		ModelAndView mav = new ModelAndView("redirect:/member/listMembers.do");
		return mav;
	}

	@Override
	@RequestMapping(value = "/member/removeMember.do", method = RequestMethod.GET)
	public ModelAndView removeMember(@RequestParam("id") String id, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		request.setCharacterEncoding("utf-8");
		memberService.removeMember(id);
		ModelAndView mav = new ModelAndView("redirect:/member/listMembers.do");
		return mav;
	}

	@Override
	@RequestMapping(value = "/member/login.do", method = RequestMethod.POST)
	public ModelAndView login(@ModelAttribute("member") MemberVO member, RedirectAttributes rAttr,
			HttpServletRequest request, HttpServletResponse response) throws Exception {
		ModelAndView mav = new ModelAndView();
		memberVO = memberService.login(member);
		if (memberVO != null) {
			HttpSession session = request.getSession();
			session.setAttribute("member", memberVO);
			session.setAttribute("isLogOn", true);

			String action = (String) session.getAttribute("action");
			session.removeAttribute("action");
			if (action != null) {
				mav.setViewName("redirect:" + action);
			} else {
				mav.setViewName("redirect:/member/listMembers.do");
			}

		} else {
			rAttr.addAttribute("result", "loginFailed");
			mav.setViewName("redirect:/member/loginForm.do");
		}

		return mav;
	}

	@Override
	@RequestMapping(value = "/member/logout.do", method = RequestMethod.GET)
	public ModelAndView logout(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpSession session = request.getSession();
		session.removeAttribute("member");
		session.setAttribute("isLogOn", false);

		ModelAndView mav = new ModelAndView();
		mav.setViewName("redirect:/member/listMembers.do");
		return mav;
	}

	@RequestMapping(value = "/member/*Form.do", method = RequestMethod.GET)
	private ModelAndView form(@RequestParam(value = "result", required = false) String result,
			@RequestParam(value = "action", required = false) String action, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		String viewName = (String) request.getAttribute("viewName");
		HttpSession session = request.getSession();
		session.setAttribute("action", action);

		ModelAndView mav = new ModelAndView();
		mav.addObject("result", result);
		mav.setViewName(viewName);
		return mav;
	}

	@RequestMapping(value = { "/", "/main.do" }, method = RequestMethod.GET)
	private ModelAndView main(HttpServletRequest request, HttpServletResponse response) {
		String viewName = (String) request.getAttribute("viewName");
		ModelAndView mav = new ModelAndView();
		mav.setViewName(viewName);
		return mav;
	}
	
}

10. MemberDAO 인터페이스를 다음과 같이 작성한다. 인터페이스에 @Mapper를 적용해 실핼 시 매퍼 파일을 읽어 들이고, 인터페이스에 @Repository를 적용한다. 이 때 반드시 추상 메서드 이름과 매퍼 파일에 있는 SQL문의 id는 같아야 한다.

이제까지의 실습에서 사용한 마이바티스는 DAO 인터페이스에 추상 메서드를 선언한 후 인터페이스 구현 클래스에서
SqlSession 클래스로 매퍼 파일의 SQL문에 접근해서 실행했다.
하지만 스프링 부트에서는 구현 클래스가 없어지고 서비스 클래스에서 DAO 인터페이스의 추상 메서드를 호출하면
인터페이스에서는 매퍼 파일에서 호출된 메서드 이름과 동일한 id의 SQL문을 바로 사용할 수 있다.
따라서 DAO 패키지의 MemberDAOImpl.java 클래스는 삭제한다(앞에서 사용한 마이바티스 기능과 비교해 보자)

[MemberDAO.java]

package com.myboot03.member.dao;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Repository;

import com.myboot03.member.vo.MemberVO;

@Mapper // 실행 시 인터페이스에서 매퍼 파일을 읽어 들이도록 지정한다.
@Repository("memberDAO")
public interface MemberDAO {
	public List selectAllMemberList() throws DataAccessException; // 매퍼 파일의 id가 selectAllMemberList인 SQL문을 호출한다.

	public int insertMember(MemberVO memberVO) throws DataAccessException; // 매퍼 파일의 id가 insertMember인 SQL문을 호출한다.

	public int deleteMember(String id) throws DataAccessException; // 매퍼 파일의 id가 deleteMember인 SQL문을 호출한다.

	public MemberVO loginById(MemberVO memberVO) throws DataAccessException; // 매퍼 파일의 id가 loginById인 SQL문을 호출한다.
}

11. 프로젝트를 실행한 후 브라우저에서 다음의 주소로 요청하여 결과를 확인한다.

- http://localhost:8090/member/listMembers.do

* 회원 가입 기능은 직접 구현해 보기 바란다.


* build.gradle 에 추가할 라이브러리를 찾는 방법

1. mvnrepository.org에 접속해 검색창에서 MyBatis Spring Boot Starter를 검색한다.

2. 조회 결과에서 MyBatis Spring Boot Starter를 선택한다.

3. 추가할 버전 중 1.3.2 버전을 선택한다.

4. Gradle 탭을 클릭하고 내용을 복사해 build.gradle에 붙여 넣는다.

5. 프로젝트에서 마우스 오른쪽 버튼을 클릭한 후 Gradle > Refresh Gradle Project 를 선택해 추가한 라이브러리를 설치한다.