관리 메뉴

거니의 velog

(15) 스프링과 마이바티스 연동하기 본문

Java_Spring Framework part1

(15) 스프링과 마이바티스 연동하기

Unlimited00 2023. 11. 10. 21:11

1. 스프링-마이바티스 연동 관련 XML 파일 설정하기

* 우리는 이전 과정을 통해 웹 프로젝트에서 마이바티스 라이브러리를 추가하여 독립적으로 사용할 수 있음을 알았다. 스프링 기반 웹 애플리케이션을 개발할 때 마이바티스는 데이터베이스 연동 기능을 담당하기 때문에 스프링에서는 간단한 설정만으로 쉽게 마이바티스를 사용할 수 있다.

* 이번에는 스프링과 마이바티스를 연동해 회원 관리 기능을 구현해 보자. 우선 스프링 버전 3.0.1을 기준으로 수동으로 직접 설정한 후 관련 XML 파일들을 설정한다.

* 메이븐을 통해 중앙 서버에서 자동으로 라이브러리를 받아서 사용하는 방법도 있으나,
  이는 나중에 살펴보도록 한다.

1. 새 프로젝트 pro24를 만들고 스프링 라이브러리를 복사해 lib 폴더에 넣는다.

* 실습에서 사용하는 스프링 버전은 3.0.1이고 호환되는 마이바티스 라이브러리는 mybatis-3.0.5.jar 이다.

2. 스프링에서 사용할 빈을 생성하는 데 필요한 XML 파일을 설정하자. 먼저 XML 관련 파일들을 다음과 같이 준비한다.

3. 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://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	id="WebApp_ID" version="3.0">
	
	<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
			/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>

4, 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">
	
		
	<bean id="viewResolver"   
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="viewClass" 
                          value="org.springframework.web.servlet.view.JstlView"/>
		<property name="prefix" value="/WEB-INF/views/member/" />  <!-- JSP 파일의 위치를 지정한다. -->
		<property name="suffix" value=".jsp"/>
	</bean>
   
	<bean id="memberController" 
                            class="com.spring.member.controller.MemberControllerImpl">
		<property name="methodNameResolver">
			<ref local="memberMethodResolver"/>
		</property>
		<property name="memberService" ref="memberService"/>
	</bean>

	<bean id="memberMethodResolver"
		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/removeMember.do">removeMember</prop>
				<prop key="/member/memberForm.do" >form</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>

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

jdbc.properties 파일은 이전의 파일을 복사해 붙여 넣은 것이다.
<?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">

	<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<value>/WEB-INF/config/jdbc.properties</value>
		</property>
	</bean> <!-- PropertyPlaceholderConfigurer 클래스를 이용해 데이터베이스 설정 관련 정보를 jdbc.properties 파일에서 읽어 들인다. -->

 	<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> <!-- 마이바티스에서 제공하는 PooledDataSource 클래스를 이용해서 dataSource 빈을 생성한다. -->
	
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- sqlSessionFactory 클래스를 이용해 dataSource 속성에 dataSource 빈을 설정한다. -->
		<property name="dataSource" ref="dataSource" />
		<property name="configLocation" value="classpath:mybatis/model/modelConfig.xml" /> <!-- configLocation 속성에 modelConfig.xml을 설정한다. -->
		<property name="mapperLocations" value="classpath:mybatis/mappers/*.xml" /> <!-- mapperLocations 속성에 mybatis/mappers 패키지의 모든 매퍼 파일들을 읽어 들여와 설정한다. -->
	</bean>

	<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
	</bean> <!-- SqlSessionTemplate 클래스를 이용해 sqlSession 빈을 생성한다. -->

	<bean id="memberDAO" class="com.spring.member.dao.MemberDAOImpl">
		<property name="sqlSession" ref="sqlSession"></property> <!-- sqlSession 빈을 memberDAO 빈 속성에 주입한다. -->
	</bean>

</beans>

6. MemberDAO 빈을 사용할 memberService 빈을 설정한다.

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

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

* 이번에는 마이바티스를 사용하기 위한 설정 파일과 자바 클래스를 구현해 보자.


2. 마이바티스 관련 XML 파일 설정하기

1. src 패키지 아래에 mybatis.mappers 패키지를 만들고 이전에 실습한 member.xml을 복사해 붙여 넣는다. 또한 SQL 문에서 데이터를 전달할 때 사용할 memberVO 빈을 설정하기 위해 mybatis 아래에 model 패키지를 만들고 modelConfig.xml 파일을 생성한다.

2. 회원 관련 기능 SQL 문이 있는 매퍼 파일인 member.xml이다. 이전에 실습한 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>

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

    <select id="selectName" resultType="String">
        <![CDATA[
		select name from t_member
		where id = 'hong'			
		]]>
    </select>

    <select id="selectPwd" resultType="int">
        <![CDATA[ 
	    select pwd from t_member 
	    where id = 'hong'
	 ]]>
    </select>

    <select id="selectMemberById" resultType="memberVO" parameterType="String">
        <![CDATA[
         select * from t_member
         where
         id=#{id}			
      ]]>
    </select>

    <select id="selectMemberByPwd" resultMap="memResult" parameterType="int">
        <![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>

    <!-- 동적 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>

    <!--  
   <sql id="a">
    <![CDATA[
      select * from t_member
     ]]> 
   </sql>  -->

    <!--    
  <select id="searchMember" parameterType="memberVO" resultMap="memResult">
	     <include refid="a" /> 
	   <![CDATA[
         select * from t_member 
      ]]>
	  
       <where>
		  <choose>
		      <when test="name != '' and name != null 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">
        <!-- <include refid="a" /> -->
        <![CDATA[
        select * from t_member 
          
      ]]>

        where name in
        <foreach item="item" collection="list" open="(" separator="," close=")">
            #{item}
        </foreach>
        order by joinDate desc
    </select>

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

    <!--  like 검색 -->
    <select id="selectLike" resultMap="memResult" parameterType="String">
        <![CDATA[
         select * from t_member
         where
         name like '%' || #{name} || '%'		
      ]]>
    </select>
</mapper>

3. 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" /> <!-- typeAlias 태그로 마이바티스에서 데이터 전달에 사용될 memberVO 빈을 설정한다. -->
	</typeAliases>
</configuration>

3. 자바 클래스와 JSP 파일 구현하기

* 이제 자바 클래스와 JSP 파일을 구현할 차례이다.

1. 자바 클래스는 다음과 같이 com.spring.member 패키지 아래에 다시 패키지별로 위치시킨다. 또 JSP 파일은 WEB-INF/views/member 폴더에 위치하도록 준비한다.

2. 컨트롤러 역할을 하는 MemberControllerImpl 클래스에서는 memberService 속성에 빈을 주입하기 위해 setter를 구현한다. 상속 받는 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.MemberService;
import com.spring.member.service.MemberServiceImpl;
import com.spring.member.vo.MemberVO;

public class MemberControllerImpl extends MultiActionController implements MemberController {
	private MemberService memberService;

	public void setMemberService(MemberServiceImpl memberService) {
		this.memberService = memberService;
	} // memberService 빈을 주입하기 위해 setter를 구현한다.
	
	@Override
	public ModelAndView listMembers(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String viewName = getViewName(request);
		List membersList = memberService.listMembers();
		ModelAndView mav = new ModelAndView(viewName);
		mav.addObject("membersList", membersList); // 조회한 회원 정보를 ModelAndView의 addObject() 메서드를 이용해 바인딩한다.
		return mav;
	}

	@Override
	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(request, memberVO); // 회원 가입창에서 전송된 회원 정보를 bind() 메서드를 이용해 memberVO 해당 속성에 자동으로 설정한다.
		int result = 0;
		result = memberService.addMember(memberVO);
		ModelAndView mav = new ModelAndView("redirect:/member/listMembers.do"); // 회원 정보 추가 후 ModelAndView 클래스의 redirect 속성을 이용해 /member/listMembers.do로 리다이렉트 한다.
		return mav;
	}
	
	@Override
	public ModelAndView removeMember(HttpServletRequest request, HttpServletResponse response) throws Exception{
		request.setCharacterEncoding("utf-8");
		String id=request.getParameter("id");
		memberService.removeMember(id);
		ModelAndView mav = new ModelAndView("redirect:/member/listMembers.do"); // 회원 정보를 삭제하고 회원 목록 창으로 리다이렉트 한다.
		return mav;
	}
	
	public ModelAndView form(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String viewName = getViewName(request);
		ModelAndView mav = new ModelAndView();
		mav.setViewName(viewName);
		return mav;
	} // 데이터베이스 연동 작업이 없는 입력창 요청 시 뷰이름만 ModelAndView 로 반환한다.

	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();
		}

		int begin = 0;
		if (!((contextPath == null) || ("".equals(contextPath)))) {
			begin = contextPath.length();
		}

		int end;
		if (uri.indexOf(";") != -1) {
			end = uri.indexOf(";");
		} else if (uri.indexOf("?") != -1) {
			end = uri.indexOf("?");
		} else {
			end = uri.length();
		}

		String fileName = uri.substring(begin, end);
		if (fileName.indexOf(".") != -1) {
			fileName = fileName.substring(0, fileName.lastIndexOf("."));
		}
		if (fileName.lastIndexOf("/") != -1) {
			fileName = fileName.substring(fileName.lastIndexOf("/"), fileName.length());
		}
		return fileName;
	}	

}

3. 속성 memberDAO 에 memberDAO 빈을 주입하기 위해 setter를 구현한다.

[MemberServiceImpl.java]

package com.spring.member.service;

import java.util.List;

import org.springframework.dao.DataAccessException;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

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

/*@Transactional(propagation=Propagation.REQUIRED) */
public class MemberServiceImpl  implements MemberService{
	   private MemberDAO memberDAO;
	   public void setMemberDAO(MemberDAO memberDAO){
	      this.memberDAO = memberDAO;
	   } // 속성 memberDAO에 memberDAO 빈을 주입하기 위해 setter를 구현한다.

	   @Override
	   public List listMembers() throws DataAccessException {
	      List membersList = null;
	      membersList = memberDAO.selectAllMemberList();
	      return membersList;
	   }

	   @Override
	   public int addMember(MemberVO memberVO) throws DataAccessException {
	     return memberDAO.insertMember(memberVO);
	   }


	   @Override
	   public int removeMember(String id) throws DataAccessException {
	      return memberDAO.deleteMember(id);
	   }
}

4. 설정 파일에서 만든 sqlSession 빈을 속성 sqlSession에 주입하기 위해 setter를 구현한다. sqlSession 빈의 메서드들을 이용해 매퍼 파일에 정의된 SQL문을 사용한다.

[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 implements MemberDAO {
	private SqlSession sqlSession;

	public void setSqlSession(SqlSession sqlSession) {
		this.sqlSession = sqlSession;
	} // 속성 sqlSession에 sqlSession 빈을 주입하기 위해 setter를 구현한다.

	@Override
	public List selectAllMemberList() throws DataAccessException {
		List<MemberVO> membersList = null;
		membersList = sqlSession.selectList("mapper.member.selectAllMemberList"); // 주입된 sqlSession 빈으로 selectList() 메서드를 호출하면서 SQL문의 id를 전달한다.
		return membersList;
	}

	@Override
	public int insertMember(MemberVO memberVO) throws DataAccessException {
		int result = sqlSession.insert("mapper.member.insertMember", memberVO); // 주입된 sqlSession 빈으로 insert() 메서드를 호출하면서 SQL문의 id와 memberVO를 전달한다.
		return result;
	}

	@Override
	public int deleteMember(String id) throws DataAccessException {
		int result =  sqlSession.delete("mapper.member.deleteMember", id); // 주입된 sqlSession 빈으로 delete() 메서드를 호출하면서 SQL문의 id와 회원 ID를 전달한다.
		return result;
	}
}

5. 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="center" width="80%">
        <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>

		<!-- 삭제하기를 클릭시 /member/removeMember.do 로 요청한다. -->
        <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>
    
    <!-- 회원 가입 클릭 시 /member/memberForm.do로 요청한다. -->
    <a href="${contextPath}/member/memberForm.do">
        <h1 style="text-align:center">회원가입</h1>
    </a>
</body>

</html>

6. 회원 가입창에서 회원 정보를 입력한 후 action 값을 /member/addMember.do 서블릿으로 전송한다.

[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">아이디</p>
                </td>
                <td width="400"><input type="text" name="id"></td>
            </tr>
            <tr>
                <td width="200">
                    <p align="right">비밀번호</p>
                </td>
                <td width="400"><input type="password" name="pwd"></td>
            </tr>
            <tr>
                <td width="200">
                    <p align="right">이름</p>
                </td>
                <td width="400">
                    <p><input type="text" name="name"></p>
                </td>
            </tr>
            <tr>
                <td width="200">
                    <p align="right">이메일</p>
                </td>
                <td width="400">
                    <p><input type="text" name="email"></p>
                </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>

</html>

7. 다음의 주소로 요청하면 다음과 같이 회원 정보를 표시한다. 하단의 회원 가입을 클릭한다.

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

8. 김동준이라는 새 회원 정보를 입력하고 가입하기를 클릭한다.

9. 그러면 컨트롤러에 http://localhost:8090/pro24/member/listMembers.do로 요청하여 회원을 추가하고 다시 회원 목록을 표시한다. 이번에는 삭제하기를 클릭해 앞에서 추가한 '김동준' 회원을 삭제해보자.

10. 삭제하기를 클릭하면 서버의 http://localhost:8090/pro24/member/listMembers.do로 요청한다. 다음과 같이 '김동준' 회원 정보가 삭제된 것을 볼 수 있다.

* 지금까지 스프링과 마이바티스를 연동하여 회원 관리 프로그램을 실습해 보았다. 이 외에도 매퍼 파일에 회원 정보 수정 SQL문과 modMember.jsp 파일도 추가해 수정 기능을 직접 구현해 보기 바란다.