티스토리 뷰

Spring

[Spring]MyBatis 연동하기

dev23 2024. 8. 17. 16:24
반응형

- 스프링 기반 웹 애플리케이션을 개발할 때 마이바티스는 DB 연동 기능을 담당하기 때문에 스프링에서는 간단한 설정만으로 쉽게 마이바티스를 사용할 수 있다.
- 스프링과 마이바티스를연동하기 위해 XML 파일을 설정해야 한다.
 
- 실습 시 사용하는 스프링 버전은 3.0.1이고 호환되는 마이바티스 라이브러리는 myBatis-3.0.5.jar다.

필요 라이브러리

 

* WebContent/WEB-INF/web.xml

- 애플리케이션 실행 시 여러 설정 파일들을 /WEB-INF/config 폴더에서 읽어 들이도록 한다.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>
	
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			/WEB-INF/config/action-mybatis.xml <!-- mybatis 설정 파일을 읽어들인다. -->
			/WEB-INF/config/action-service.xml
		</param-value>
	</context-param>
	
	<servlet>
		<servlet-name>action</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>action</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
</web-app>

 

* WebContent/WEB-INF/action-servlet.xml

- 뷰 관련 빈과 각 URL 요청명에 대해 호출할 메서드들을 설정한다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans   
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<!-- 컨트롤러에서ModelAndView 인자로 뷰이름이 반환되면 InternalResourceViewResolver의 프로퍼티 prefix 속성에 지정된 /test 폴더에서
	ModelAndView 인자로넘어온 뷰이름에 해당되는 JSP를 선택해 DispatcherServlet으로 보낸다. -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
	<property name="prefix" value="/views/member" />
	<property name="suffix" value=".jsp" />
</bean>

<!-- memberController 빈에 methodNameResolver 빈과 memberResolver 빈을 주입한다. -->
<bean id="memberController" class="com.spring.member.controller.MemberControllerImpl">
	<property name="methodNameResolver">
		<ref local="memberMethodNameResolver" />
	</property> 
	<property name="memberService" ref="memberService" />
</bean>

<bean id="memberMethodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
	<property name="mappings">
		<props>
			<prop key="/member/listMembers.do">listMembers</prop>
			<prop key="/member/addMember.do">addMember</prop>
			<prop key="/member/memberForm.do">memberForm</prop>
			<prop key="/member/memberDetail.do">memberDetail</prop>
		</props>
	</property>
</bean>

<bean id="memberUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	<property name="mappings">
		<props>
			<prop key="/member/*.do">memberController</prop>
		</props>
	</property>
</bean>
</beans>

 

* WebContent/WEB-INF/config/action-mybatis.xml

 - 스프링에서는 마이바티스 관련 클래스들을 설정 파일에서 설정하여 빈들을 자동으로 생성한다.
- 따라서 action-mybatis.xml에서는 스프링의 SqlSessionFactoryBean 클래스 빈을 생성하면서 매퍼 파일인 mebmer.xml과
빈 생성 설정 파일인 modelConfig.xml 을 읽어 들인다. 또한 스프링의 sqlSession 빈을 생성하면서
sqlSessionFactoryBean 빈을 주입하고, 다시 memberDAO 빈을 생성하면서sqlSession 빈을 주입한다.

<?xml version="1.0" encoding="UTF-8"?>
<beans
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
 xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans">
	
	<!-- DB 설정 관련 정보를 jdbc.properties 파일에서 읽어 들인다. -->
	<bean id="propertyPlaceholderConfigurer"
	class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="locations">
	<value>/WEB-INF/config/jdbc.properties</value>
	</property>
	</bean>

	<!-- 마이바티스에서 제공하는 PooledDataSource 클래스를 이용해 dataSource 빈을 생성한다. -->
 	<bean id="dataSource" class="org.apache.ibatis.datasource.pooled.PooledDataSource">
		<property name="driver" value="${jdbc.driverClassName}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
	</bean>
	
	<!-- SqlSessionFactoryBean을 이용해 dataSource 속성에 dataSource 빈을 설정한다. -->
	<bean id="sqlSessionFactory"
		class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="configLocation"
			value="classpath:mybatis/model/modelConfig.xml" />
		<property name="mapperLocations" value="classpath:mybatis/mappers/*.xml" />
	</bean>

	<bean id="sqlSession"
		class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
	</bean>


	<bean id="memberDAO"
		class="com.spring.member.dao.MemberDAOImpl">
		<property name="sqlSession" ref="sqlSession"></property>
	</bean>

</beans>

 

* WebContent/WEB-INF/config/action-service.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans   
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

	<!-- memberService 빈의 memberDAO 속성에 memberDAO 빈을 주입한다. -->
	<bean id="memberService" class="com.spring.member.service.MemberServiceImpl">
		<property name="memberDAO" ref="memberDAO" />
	</bean>
</beans>

 

* WebContent/WEB-INF/config/jdbc.properties

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/java_web
jdbc.username=root
jdbc.password=pwd

 

마이바티스 관련 XML 파일 설정

* src/mybatis/mappers/member.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 namespace = "mapper.member">
	<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>
	
	
	<!-- 조회한 레코드를 지정한 컬럼 이름을 key, 값을 value로 해서 저장한다. -->
<!-- 	<resultMap id="memResult" type="java.util.HashMap">
		<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> -->
	
	<!-- 조회한 회원 정보를 HashMap에 저장한다. -->
	
	<!-- 공통 SQL문의 refid를 'a'로 지정한다. -->
	<sql id="a">
		<![CDATA[
			select * from t_member
		]]>
	</sql>
	
	<select id="selectAllMemberList" resultMap="memResult">
		<include refid="a"/>
	</select>
	
	<select id="selectMemberById" resultType="memberVO" parameterType="String">
		<include refid="a"/>
			where id=#{id}
	</select>
	
	<select id="selectMemberByPwd" resultMap="memResult" parameterType="String">
		<![CDATA[
			select * from t_member
			where pwd=#{pwd}
		]]>
	</select>
	
	<insert id="insertMember" parameterType="memberVO">
		<![CDATA[
			insert into t_member (id, pwd, name, email) values(#{id}, #{pwd}, #{name}, #{email})
		]]>
	</insert>
	
	<insert id="insertMember2" parameterType="java.util.HashMap">
		<![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>
	
	<!-- if를 이용한 동적 SQL 문 -->
	<!-- <select id="searchMember" parameterType="memberVO" resultMap="memResult">
		<![CDATA[
			select * from t_member
		]]>
		<where>
			<if test="name != '' and name != null">
				name = #{name} 
			</if>
			<if test=" email !='' and email != null">
				and email=#{email}
			</if>
		</where>
		order by joinDate desc
	</select> -->
	
	<!-- choose를 이용한 동적 SQL문 -->
	<select id="searchMember" parameterType="memberVO" resultMap="memResult">
		<![CDATA[
			select * from t_member
		]]>
		<where>
			<choose>
				<!-- name과 email 속성 값이 모두 있는 경우를 추가한다. -->
				<when test="name != null and name != '' and email != '' and email != null">
					name=#{name} and email=#{email}
				</when>
				<when test="name != '' and name != null">
					name=#{name}
				</when>
				<when test="email != '' and email != null">
					email=${email}
				</when>
			</choose>
		</where>
		order by joinDate desc
	</select>
	
	<select id="foreachSelect" resultMap="memResult" parameterType="java.util.Map">
		<![CDATA[
			select * from t_member
		]]>
		where name in
		<foreach item="item" collection="list" open="(" separator="," close=")">
			#{item}
		</foreach>
		order by joinDate desc
	</select>
	
	<!-- 오라클에서는 insert문을 반복해서 사용하면 오류가 발생한다. -->
	<!-- <insert id="foreachInsert" parameterType="java.util.Map">
		INSERT INTO t_member(id, pwd, name, email) VALUES
		<foreach item="item" collection="list" >
		(#{item.id},
		#{item.pwd},
		#{item.name},
		#{item.email})
		</foreach>
	</insert> -->
	
	<insert id="foreachInsert" parameterType="java.util.Map">
		<foreach item="item" collection="list" open="insert all" separator=" " close="select * from dual">
			into t_member(id,pwd,name,email) values
			(#{item.id},
			#{item.pwd},
			#{item.name},
			#{item.email})
		</foreach>
	</insert>
</mapper>

 

* src/mybatis/model/modelConfig.xml

 - <typeAlias> 태그를 이용해 매퍼 파일에서 긴 이름의 클래스를 별칭으로 사용할 수 있게 설정한다.

<?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>
	<typeAliases>
		<typeAlias type="com.spring.member.vo.MemberVO"  alias="memberVO" />
	</typeAliases>
</configuration>

 

* MemberController.java

 - MultiActionController 클래스에서 제공하는 bind() 메서드를 이용해 회원 가입창에서 전송된 매개변수들을 편리하게
MemberVO 속성에 설정할 수 있다.
 - ModelAndView를 뷰리졸버로 반환할 때 viewname을 redirect:/member/listMembers.do로 설정해 회원 목록창으로
리다이렉트되도록 한다.

package com.spring.member.controller;

import java.util.List;

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

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;

import com.spring.member.service.MemberServiceImpl;
import com.spring.member.vo.MemberVO;

public class MemberControllerImpl extends MultiActionController{
	private MemberServiceImpl service;
	public void setMemberService (MemberServiceImpl service) {
		this.service = service;
	}
	
	public ModelAndView listMembers(HttpServletRequest request, HttpServletResponse response ) throws Exception{
		String viewName = getViewName(request);
		List membersList = service.listMembers();
		ModelAndView mav = new ModelAndView(viewName);
		mav.addObject("membersList",membersList);
		return mav;
	}
	
	public ModelAndView addMember(HttpServletRequest request, HttpServletResponse response) throws Exception {
		request.setCharacterEncoding("utf-8");
		MemberVO memberVO = new MemberVO();
		/*
		String id=request.getParameter("id");
		String pwd=request.getParameter("pwd");
		String name=request.getParameter("name");
		String email = request.getParameter("email");
		memberVO.setId(id);
		memberVO.setPwd(pwd);
		memberVO.setName(name);
		memberVO.setEmail(email);
		 */
		// 회원가입창에서 전송된 회원 정보를 bind() 메서드를 이용해 memberVO 해당 속성에 자동으로 설정한다.
		bind(request, memberVO);
		int result = 0;
		result = service.addMember(memberVO);
		// 회원 정보 추가 후 ModelAndView 클래스의 redirect 속성을 이용해 /member/listMembers.do로 리다이렉트한다.
		ModelAndView mav = new ModelAndView("redirect:/member/listMembers.do");
		return mav;
	}
	
	public ModelAndView removeMember(HttpServletRequest request, HttpServletResponse response) throws Exception{
		request.setCharacterEncoding("utf-8");
		String id=request.getParameter("id");
		service.removeMember(id);
		ModelAndView mav = new ModelAndView("redirect:/member/listMembers.do");
		return mav;
	}
	
	public ModelAndView memberForm(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String viewName = getViewName(request);
		ModelAndView mav = new ModelAndView();
		mav.setViewName(viewName);
		return mav;
	}
	
	private  String getViewName(HttpServletRequest request) throws Exception {
	      String contextPath = request.getContextPath();
	      String uri = (String)request.getAttribute("javax.servlet.include.request_uri");
	      if(uri == null || uri.trim().equals("")) {
	         uri = request.getRequestURI();
	      }
	      
	      //http://localhost:port/member/listMember.do로 요청시
	      int begin = 0;  //
	      if(!((contextPath==null)||("".equals(contextPath)))){
	         begin = contextPath.length();  // 전체 요청명 의 길이를 구함
	      }

	      int end;
	      if(uri.indexOf(";")!=-1){
	         end=uri.indexOf(";");  //요청 uri에 ';'가 있을 경우 ';'문자 위치를 구함
	      }else if(uri.indexOf("?")!=-1){
	         end=uri.indexOf("?");   //요청 uri에 '?'가 있을 경우 '?' 문자 위치를 구함
	      }else{
	         end=uri.length();
	      }

	      //http://localhost:8080/member/listMember.do로 요청시 먼저 '.do'를 제거한 http://localhost:8090/member/listMember를 구한 후,
	      //다시 http://localhost:8080/member/listMember에서 역순으로 첫번째 '/' 위치를 구한 후, 그 뒤의 listMember를 구한다.
	      String fileName=uri.substring(begin,end);
	      if(fileName.indexOf(".")!=-1){
	         fileName=fileName.substring(0,fileName.lastIndexOf("."));  //요청명에서 역순으로 최초 '.'의 위치를 구한후, '.do' 앞에까지의 문자열을 구함
	      }
	      if(fileName.lastIndexOf("/")!=-1){
	         fileName=fileName.substring(fileName.lastIndexOf("/"),fileName.length()); //요청명에서 역순으로 최초 '/'의 위치를 구한후, '/' 다음부터의 문자열을 구함  
	      }
	      return fileName;
	   }

}

 
* MemberServiceImpl.java

package com.spring.member.service;

import java.util.List;

import org.springframework.dao.DataAccessException;

import com.spring.member.dao.MemberDAOImpl;
import com.spring.member.vo.MemberVO;

public class MemberServiceImpl {
	private MemberDAOImpl dao;
	public void setMemberDAO(MemberDAOImpl dao) {
		this.dao = dao;
	}
	
	public List listMembers() throws DataAccessException{
		List membersList = dao.selectAllMemberList();
		return membersList;
	}
	
	public int addMember(MemberVO memberVO) throws DataAccessException {
	     return dao.insertMember(memberVO);
	   }


	   public int removeMember(String id) throws DataAccessException {
	      return dao.deleteMember(id);
	   }
}

 
* MemberDAOImpl.java

package com.spring.member.dao;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.dao.DataAccessException;

import com.spring.member.vo.MemberVO;


public class MemberDAOImpl {
	private SqlSession sqlSession;

	public void setSqlSession(SqlSession sqlSession) {
		this.sqlSession = sqlSession;
	}

	public List selectAllMemberList() throws DataAccessException {
		List<MemberVO> membersList = null;
		membersList = sqlSession.selectList("mapper.member.selectAllMemberList");
		return membersList;
	}

	public int insertMember(MemberVO memberVO) throws DataAccessException {
		int result = sqlSession.insert("mapper.member.insertMember", memberVO);
		return result;
	}

	public int deleteMember(String id) throws DataAccessException {
		int result =  sqlSession.delete("mapper.member.deleteMember", id);
		return result;
	}
}

 

* WebContent/WEB-INF/views/member/listMembers.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" 
    isELIgnored="false"  %>
 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"  %>
<c:set var="contextPath"  value="${pageContext.request.contextPath}"  />

<%
  request.setCharacterEncoding("UTF-8");
%>    

<html>
<head>
<meta charset=UTF-8">
<title>회원 정보 출력창</title>
</head>
<body>
<table border="1"  align="left"  width="800">
    <tr align="center"   bgcolor="lightgreen">
      <td ><b>아이디</b></td>
      <td><b>비밀번호</b></td>
      <td><b>이름</b></td>
      <td><b>이메일</b></td>
      <td><b>가입일</b></td>
      <td><b>삭제</b></td>
   </tr>
   
 <c:forEach var="member" items="${membersList}" >     
   <tr align="center">
      <td>${member.id}</td>
      <td>${member.pwd}</td>
      <td>${member.name}</td>
      <td>${member.email}</td>
      <td>${member.joinDate}</td>
      <td><a href="${contextPath}/member/removeMember.do?id=${member.id }">삭제하기</a></td>
    </tr>
  </c:forEach>   
</table>
<a  href="${contextPath}/member/memberForm.do"><h1 style="text-align:center">회원가입</h1></a>
</body>
</html>

* WebContent/WEB-INF/views/member/memberForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"
    isELIgnored="false" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>    
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="contextPath"  value="${pageContext.request.contextPath}"  />
<%
   request.setCharacterEncoding("UTF-8");
%> 
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 가입창</title>
<style>
   .text_center{
     text-align:center;
   }
</style>
</head>
<body>
	<form method="post"   action="${contextPath}/member/addMember.do">
	<h1  class="text_center">회원 가입창</h1>
	<table  align="center">
	   <tr>
	      <td width="200"><p align="right">아이디</td>
	      <td width="400"><input type="text" name="id"></td>
	   </tr>
	   <tr>
	      <td width="200"><p align="right">비밀번호</td>
	      <td width="400"><input type="password" name="pwd"></td>
	    </tr>
	    <tr>
	       <td width="200"><p align="right">이름</td>
	       <td width="400"><p><input type="text" name="name"></td>
	    </tr>
	    <tr>
	       <td width="200"><p align="right">이메일</td>
	       <td width="400"><p><input type="text" name="email"></td>
	    </tr>
	    <tr>
	       <td width="200"><p>&nbsp;</p></td>
	       <td width="400"><input type="submit" value="가입하기"><input type="reset" value="다시입력"></td>
	    </tr>
	</table>
	</form>
</body>

 
 
- 작성 후 /member/listMembers.do로 요청해 회원 정보 리스트가 출력되는지 확인한다.

출력 결과

 
 

반응형

'Spring' 카테고리의 다른 글

[Spring] 스프링 웹 프로젝트 생성하기  (0) 2024.10.15
[Spring]스프링 애너테이션  (0) 2024.08.17
[Spring]JDBC 연동  (0) 2024.08.17
[Spring]스프링 MVC  (0) 2024.08.17
[Spring]의존성 주입  (0) 2024.08.16
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함