영보의 SystemOut.log

[Mybatis] Mybatis 와 연동하여 동적 웹페이지 구현하기 본문

국비교육(아이티센 입사교육)

[Mybatis] Mybatis 와 연동하여 동적 웹페이지 구현하기

영보로그 2021. 10. 21. 21:43
반응형

 

 

Mybatis 개요

 - SQL 질의문을 통해 결과물을 개발자가 지정한 클래스에 매핑하여 내보내주는 아주 우용한 프레임워크이다. 즉 기존 JDBC 방법은 SQL 질의문 실행 후 결과값을 모델에 담는 로직으로 소스가 길어졌지만, Mybatis는 매핑된 모델에 자동으로 변수와 컬럼의 값이 매핑되어 아주 편해졌다. 

 - 개발자가 지정한 SQL, 저장프로시저 그리고 몇가지 고급 매핑을 지원하는 Persistence 프레임워크이다.

 - JDBC 코드와 수동으로 셋팅하는 파라미터와 결과 매핑을 제거한다. 즉 기존에 직접 jdbc connection, sql statement, parameter, result record set 등을 개발하던 것을 Mybatis 프레임워크가 대신해준다. 

 - 데이터베이스 레코드에 원시타입과 Map 인터페이스 그리고 자바 POJO를 설정하고 매핑하기 위해 XML과 애노테이션을 사용할 수 있다.

 

 

 

# Mybatis 3.0의 주요 구성물

구성물 역할
Mybatis 설정 파일 데이터베이스의 접속 주소정보나 매핑 파일의 경로 등의 고정된 환경정보를 설정한다. XML 파일로 기술한다.
SqlSessionFactoryBuilder  Mybatis 설정 파일을 바탕으로 SqlSessionFactory생성한다. 애플리케이션을 시작할 때 사용해 SqlSessionFactory를 생성하면 SqlSessionaFactoryBuiler오프젝트는 필요 없어지므로 참조를 유지할 필요는 없다. 애플리케이션의 시작시에 쓰고 버려지는 이미지다.
SqlSessionFactory  SqlSession을 생성한다. SqlSessionFactoryBuilder 오브젝트는 스레드 세이프하며, 애플리케이션 안의 프로그램은 하나의 오브젝트를 싱글톤 패턴으로 공유해야만 한다.
SqlSession SQL 발행이나 트랜잭션 관리를 실행한다. SqlSession 오브젝트는 스레드 세이프 하지 않으므로 스레드마다 필요에 따라 생성하고 폐기한다.
Mapper 인터페이스 매핑 파일에 기재된 SQL을 호출하기 위한 인터페이스이다. Mapper오브젝트는 SqlSession오브젝트와 관련해 생성되므로 SqlSession오브젝트와 함께 생성하고 폐기한다.
매핑 파일 SQL과 QR 매핑을 설정한다. XML 파일을 기술한다.

 

 

 

 ✔️ MyBatis 사용 목적 중 하나는 DAO로부터 SQL문을 분리하는 것이다. 분리된 SQL문은 SQL mapper 파일에 작성하며 DAO에서는 SqlSession 객체가 SQL mapper 파일을 참조하게 된다.

 ✔️ XML에서 SqlSessionFactory 빌드하기 모든 마이바티스 애플리케이션은 SqlSessionFactory 인스턴스를 사용한다.

   -SqlSessionFactory인스턴스는 SqlSessionFactoryBuilder를 사용하여 만들수 있다.

   - SqlSessionFactoryBuilder는 XML설정파일에서 SqlSessionFactory인스턴스를 빌드할 수 있다.

 ✔️ XML설정파일에서 지정하는 마이바티스의 핵심이 되는 설정은

   - 트랜잭션을 제어하기 위한 TransactionManager과 함께

   - 데이터베이스 Connection인스턴스를 가져오기 위한 DataSource 를 포함한다.

 

 

 

Mybatis 사원 테이블  웹 페이지 실습

 

# 자바에 Mybatis 프레임워크 적용하여 사원(Emp) 테이블에서 사원 ‘목록 보기’ 및 ‘사원 추가’ Web 개발 순서


<EMP_MyBatis 전체 설계도>

 

 

 

실습 코드

 

mybatis-3.5.5.jar
1.66MB
ojdbc6.jar
2.61MB

[WebContent] - [WEB-INF] - [lib] 폴더 안에 jar파일 두 개를 넣어준다.

 

 

# 테이블 생성

create table emp_table(
empno number(4),
ename varchar2(20),
position varchar2(10),
constraint emp_tab_pk primary key(empno));

 

 

# 값 추가

insert into emp_table values(1001,'박태호','부장');
insert into emp_table values(1002,'손유일','과장');
insert into emp_table values(1003,'오수철','대리');
insert into emp_table values(1004,'안재홍','사원');

 

 

# 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>
 	<environments default="">
 		<environment id="">
 			<transactionManager type="JDBC" />
 			<dataSource type="POOLED">
 				<property name="driver" value="oracle.jdbc.OracleDriver"/>
 				<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
 				<property name="username" value="testdb"/>
 				<property name="password" value="testdb1234"/>
 			</dataSource>
 		</environment>
 	</environments>
 	
 	<mappers>
 		<mapper resource="mybatis/sqlmapper/empMapper.xml" />
 	</mappers>
 	
 </configuration>

 - oracle database와 프로젝트를 연결

 - mybatis 연결

 

 

# EmpVO.java

package mybatis.vo;

public class EmpVO {
	// 맴버 변수
	private int empno;			// 사원번호
	private String ename;		// 사원명
	private String position;	// 직책
	
	public int getEmpno() {
		return empno;
	}
	public void setEmpno(int empno) {
		this.empno = empno;
	}
	public String getEname() {
		return ename;
	}
	public void setEname(String ename) {
		this.ename = ename;
	}
	public String getPosition() {
		return position;
	}
	public void setPosition(String position) {
		this.position = position;
	}
}

 - VO에서 맴버 변수를 생성하고 getter / setter 

 

 

# EmpDAO.java

package mybatis.dao;

import java.util.*;
import javax.print.attribute.HashAttributeSet;
import org.apache.ibatis.session.SqlSession;
import mybatis.service.FactoryService;
import mybatis.vo.EmpVO;

public class EmpDAO {
	public static List<EmpVO> getTotal(){
		/* 이미 생성되어있는 factory를 이용하여 Sqlsession을 얻어낸다. 
		 * select 작업은 auto commit을 하지 않아도 되기 때문에 openSession()메소드 호출 시 true를 인자값으로 주지 않아도 된다.
		 */
	
		SqlSession ss = FactoryService.getFactory().openSession();
		
		List<EmpVO> list = ss.selectList("emp.total");
		ss.close();
	
		return list;
	}
	
	public static int add(String empno, String ename, String position) {
		// mapper를 호출할 때 Map 자료구조로 전달해야 하므로 Map 계열의 객체 생성
		Map<String, String> map = new Hashtable<String, String>();
		
		map.put("empno", empno);
		map.put("ename", ename);
		map.put("position", position);
		
		/* SqlSession 객체를 얻을 때 openSession(true)와 같이 호출하면 
		 * DML(insert,update,delete) 실행 시 auto commit을 수행하는 
		 * SqlSession 객체를 얻을 수 있다. 꼭 true를 인자값으로 준다.
		 */
		SqlSession ss = FactoryService.getFactory().openSession(true);
		
		int cnt = ss.insert("emp.add", map);
		ss.close();
		return cnt;
		
	}
}

 - Mybatis 사용 목적 중 하나가 Data Accept Object DAO로 부터 SQL문을 분리하는 것이다. 분리된 SQL문은 SQL mapper 파일에 작성하며 DAO에서는 SqlSession 객체가 SQL mapper 파일을 참조하게 된다.

 - SqlSession 객체를 얻을 때 openSession(true)와 같이 호출하면 DML(insert,update,delete) 실행 시 auto commit을 수행하는  SqlSession 객체를 얻을 수 있다. 꼭 true를 인자 값으로 준다.

 

 

# FactoryService.java

package mybatis.service;

import java.io.Reader;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class FactoryService {
	private static SqlSessionFactory factory;
	
	static {
		try {
			// 먼저 Mybatis 설정 파일인 config.xml 파일로부터 설정 정보를 읽어들이기 위한 입력 스트림을 생성한다.
			Reader reader = Resources.getResourceAsReader("mybatis/config/config.xml");
			// 그 후 입력 스트림을 통해 config.xml 파일을 읽어 SqlSessionFactory 객체를 생성한다.
			factory = new SqlSessionFactoryBuilder().build(reader);
			reader.close();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	public static SqlSessionFactory getFactory() {
		return factory;
		
	}
}

 - 먼저 Mybatis 설정 파일인 config.xml파일로부터 설정 정보를 읽어들이기 위한 스트림을 생성한 후, 스트림을 통해 config.xml 파일을 읽어 SqlSessionFactory 객체를 생성

 

 

# empMapper.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="emp">
	<select id="total" resultType="mybatis.vo.EmpVO">
		select empno, ename, position from emp_table
	</select>
	
	<insert id="add" parameterType="java.util.Map">
		INSERT INTO emp_table(empno, ename, position) 
		VALUES(#{empno}, #{ename}, #{position})
	</insert>
</mapper>

 

 

# add.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- 자바 클래스 임포트 -->
<%@ page import="mybatis.vo.EmpVO"%>
<%@ page import="mybatis.dao.EmpDAO"%>
<%@ page import="java.util.*"%>
<% 	
	// 넘어오는 파라미터 받기 (empno, ename, position)
	request.setCharacterEncoding("UTF-8");

	String empno = request.getParameter("empno");
	String ename = request.getParameter("ename");
	String position = request.getParameter("position");
	
	int cnt = EmpDAO.add(empno, ename, position);
	
	// 클라이언트에 응답
	response.sendRedirect("total.jsp");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>add Page</title>
</head>
<body>

</body>
</html>

 

# total.jsp

<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!-- 자바 클래스 임포트 -->
<%@ page import="mybatis.vo.EmpVO"%>
<%@ page import="mybatis.dao.EmpDAO"%>
<%@ page import="java.util.*"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>total 페이지</title>
<style>
table {
	width: 500px;
	border-collapse: collapse;
}

table, th, table>tbody td {
	border: 1px solid black;
	padding: 4px;
}

table thead>tr:first-child>th {
	border: 0px
}

#add_win {
	width: 200px;
	border: 1px solid black;
	background-color: #fff;
	position: absolute;
	top: 100px;
	left: 580px;
	display: none;
}

#add_win input[type=text] {
	width: 90px;
	padding: 3px;
	border: 1px solid black;
	margin-bottom: 5px;
}
</style>
</head>
<body>
	<header>
		<h1>사원 목록</h1>
	</header>
	<article>
		<table>
			<caption>사원들의 목록을 위한 테이블</caption>
			<thead>
				<tr>
					<th colspan="3" style="text-align: right;"><input
						type="button" value="사원추가" id="add_btn" onclick="addFun()" /></th>
				</tr>

				<tr>
					<th bgcolor="orange">사원번호</th>
					<th bgcolor="orange">사원명</th>
					<th bgcolor="orange">직책</th>
				</tr>
			</thead>
			<tbody>
				<%
					List<EmpVO> list = EmpDAO.getTotal();

					if (list != null && list.size() > 0) {
						for (EmpVO vo : list) {
				%>
				<tr>
					<td><%=vo.getEmpno()%></td>
					<td><%=vo.getEname()%></td>
					<td><%=vo.getPosition()%></td>
				</tr>
				<%
					}
					}
				%>
			</tbody>
		</table>
	</article>

	   <div id="add_win">
      <header>
         <h2>사원 추가</h2>
      </header>
      <div id="body">
         <form method="POST" action="add.jsp">
            <label for="empno">사원번호</label>
            <input type="text" id="empno" name="empno"/>
            <br/>
            
            <label for="ename">사원명</label>
            <input type="text" id="ename" name="ename"/>
            <br/>
            
            <label for="position">직책</label>
            <input type="text" id="position" name="position" />
            <br>
            
            <input type="button" value="추가" id="append_btn" onclick="sendData()"/>
            <input type="button" value="취소" id="cancel_btn" onclick="closeWin()"/>
         </form>
         <br/>
      </div>
   </div>
	<script>
		function addFun() {
			var addWin = document.getElementById("add_win");
			addWin.style.display = "block"
		}
		function sendData() {
			var empno = document.getElementById("empno").value;
			var ename = document.getElementById("ename").value;
			var position = document.getElementById("position").value;

			if (empno.trim().length < 1) {
				// 한자도 입력하지 않은 경우
				document.getElementById("empno").value = "";
				alert("사원 번호를 입력 해 주세요.")

				document.getgetElementById("ename").focus();
				return;
			}
			document.forms[0].submit(); // submit 객체를 누른 경우와 똑같은 효과를 줌.

		}
		function closeWin() {
			var addWin = document.getElementById("add_win");
			addWin.style.display = "none"
		}
	</script>
</body>
</html>

 

 

반응형