MVC(Mode-View-Controller) 패턴은 소프트웨어 디자인 패턴 중 하나로, 소프트웨어를 세 가지 주요 구성 요소로 나누어 설계하는 방법이다. 각 구성 요소는 특정한 역할을 수행하며, 이를 통해 소프트웨어의 유지보수성과 확장성을 향상시킬 수 있다.
VO(Value Object), DTO(Data Transfer Object)
: DB 테이블에서 1개의 데이터 저장
DAO(Data Access Object)
: SQL문을 DB 서버로 보내서 결과를 얻어옴
Service
: 일을 수행하는 중간 관리자와 같은 역할, 일이 있으면 그 일에 필요한 DAO를 호출하여 처리한 후 결과를 Controller에게 전달
Controller
: 비즈니스 로직이 시작되는 곳으로 사용자의 요청이 오면 요청에 맞는 Service에게 일을 시키고, Service가 보내온 처리 결과를 환영에 반영시킴 (모델1) 혹은 View에 보냄 (모델2)
-입력과 출력은 Controller에서 수행하며 Service와 DAO에는 금지~
-일반적인 작업 순서는 VO, DTO
-> DAO
-> Service
-> Controller
-사용자는 하나의 작업인데 DB에서 두가지 이상의 작업을 처리해야 할 때 (조회수 증가, 게시글 목록 조회 등) Service에서 처리한다.
SELECT 'private ' ||
DECODE(LOWER(DATA_TYPE), 'number', 'int ', 'String ') ||
LOWER(COLUMN_NAME) || ';'
FROM COLS
WHERE LOWER(TABLE_NAME) = 'jdbc_board';
JAVA에서 DB 액세스와 동시에 편하게 핸들링할 수 있게 해주는 프레임워크
SQL문과 Java 코드를 분리하고, 파라미터 값만 변경되지 않으면 Java 코드 변경 없이 SQL문만 변경하여 사용 가능하다.
MyBatis 데이터 MapperAPI를 사용하여 자바빈즈 (보통 VO 객체) 혹은 Map 객체를 PreparedStatement의 파라미터에 매핑해 주고, SQL문의 실행 결과를 자바빈즈 혹은 Map 객체에 자동으로 매핑해 준다.
MyBatis를 사용하려면 관련 jar 파일을 다운로드 받은 후, JAVA에서 해당 프로젝트에 추가해 주면 된다.
https://mvnrepository.com/artifact/org.mybatis/mybatis/3.5.9
위 페이지에 접속하여 jar 파일 다운로드 > 자바 프로젝트 우클릭 > Properties > Java Build Path > Libraries > Add External JARs... > 다운로드 받은 jar 파일 선택 > Apply and Close
<?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>
<!-- DB 연결 정보가 저장된 properties 파일에 대한 정보 구성하기 -->
<properties resource="kr/or/ddit/mybatis/config/dbinfo.properties"/>
<!-- 기본 설정 -->
<settings>
<!-- 데이터 null로 전달되면 빈칸으로 처리하지 말고 null로 처리해 -->
<setting name="jdbcTypeForNull" value="NULL"/>
</settings>
<!-- 사용되는 데이터 저장용 객체(보통 VO 객체)의
긴 전체 경로를 포함한 클래스명을 짧은 이름으로 사용하기 위해 별칭 설정 -->
<typeAliases>
<!-- 형식: <typeAlias type="전체 이름" alias="별칭 이름"/> -->
<typeAlias type="kr.or.ddit.vo.LprodVO" alias="lprodVo"/>
</typeAliases>
<!-- DB 연결 설정 -->
<environments default="oracleDev">
<environment id="oracleDev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!-- 연결 정보 설정 -->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${pass}"/>
</dataSource>
</environment>
</environments>
<!-- DB에서 사용되는 SQL문이 작성된 mapper 파일 등록 -->
<mappers>
<!-- 형식: <mapper resource="경로명/mapper파일명.xml" -->
<mapper resource="kr/or/ddit/mybatis/mappers/lprod-mapper.xml"/>
<mapper resource="kr/or/ddit/mybatis/mappers/jdbc-mapper.xml"/>
</mappers>
</configuration>
<mapper>
태그의namespace
속성값은 java에서 SQL문 호출시 사용되는 이름<select>
,<insert>
,<delete>
,<update>
등 SQL문에 맞는 태그를 사용하여 SQL문 작성id
속성
- 실행할 태그를 java에서 호출시 사용되는 이름
<mapper>
태그의namespace
속성값과 연결하여 사용parameterType
속성
- 작성된 SQL문에 사용될 데이터가 저장된 객체
- 보통 VO 클래스, java의 기본 타입명, Map 객체 등이 사용됨
- 객체 기술시 해당 클래스의 전체 이름 기술
- 전체 이름 대신
<typeAlias>
태그의alias
명 사용 가능PreparedStatement
객체 사용시 썼던 물음표 대신parameterType
에 지정한 객체 변수명을 기재- 설정되는 값이 단일값이면 SQL문에 나타내는 변수는 사용자가 임의로 지정 가능
resultType
속성
- select문 처리 결과를 저장할 VO 클래스, java 기본 타입명, Map 객체 지정
<?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="lprod">
<insert id="insertLprod" parameterType="lprodVo">
INSERT INTO LPROD (LPROD_ID, LPROD_GU, LPROD_NM)
VALUES (#{lprod_id}, #{lprod_gu}, #{lprod_nm})
</insert>
<update id="updateLprod" parameterType="kr.or.ddit.vo.LprodVO">
UPDATE LPROD
SET LPROD_ID = #{lprod_id}, LPROD_NM = #{lprod_nm}
WHERE LPROD_GU = #{lprod_gu}
</update>
<delete id="deleteLprod" parameterType="String">
DELETE FROM LPROD WHERE LPROD_GU = #{lprod_gu}
</delete>
<select id="getAllLprod" resultType="lprodVo">
SELECT * FROM LPROD
</select>
<select id="getLprod" parameterType="String" resultType="lprodVo">
SELECT * FROM LPROD WHERE LPROD_GU = #{lprod_gu}
</select>
</mapper>
(mybatis-config.xml)
을 읽어와서 그 내용을 처리한 후 SqlSessionFactory
객체를 생성한다. 환경 설정 파일을 읽어올 스트림 객체를 생성해야 하고, 처리 성공시 SqlSessionFactory
객체를 생성하여 반환한다.mapper
에 등록된 SQL문 중 실행할 SQL문을 호출하여 원하는 작업을 수행한다.SqlSessionFactory
객체의 openSession()
을 이용하여 mapper
에서 SQL문을 호출하고 실행할 수 있는 SqlSession
객체를 생성한다.SqlSession
객체를 이용하여 처리할 SQL문을 호출하여 실행한다.아래 예제는 간단하게 구현한 내용으로 controller 대신 test용 클래스 (JdbcToMyBatisTest.java), util, vo, config, mapper만 사용한 점 참고하기~
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:xe
user=pc15
pass=java
<?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>
<properties resource="kr/or/ddit/mybatis/config/dbinfo.properties"/>
<settings>
<setting name="jdbcTypeForNull" value="NULL"/>
</settings>
<typeAliases>
<typeAlias type="kr.or.ddit.vo.LprodVO" alias="lprodVo"/>
</typeAliases>
<environments default="oracleDev">
<environment id="oracleDev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${pass}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="kr/or/ddit/mybatis/mappers/jdbc-mapper.xml"/>
</mappers>
</configuration>
SqlSession
객체 반환
package kr.or.ddit.util;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MybatisUtil {
private static SqlSessionFactory sqlSessionFactory;
static {
InputStream in = null;
try {
in = Resources.getResourceAsStream("kr/or/ddit/mybatis/config/mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
} catch (Exception e) {
System.out.println("Mybatis 초기화 실패!!");
e.printStackTrace();
} finally {
if(in!=null) try { in.close(); }catch(IOException e) {}
}
}
// SqlSession 객체를 반환하는 메서드
public static SqlSession getSqlSession() {
SqlSession session = sqlSessionFactory.openSession();
return session;
}
}
package kr.or.ddit.vo;
public class LprodVO {
private int lprod_id;
private String lprod_gu;
private String lprod_nm;
public int getLprod_id() {
return lprod_id;
}
public void setLprod_id(int lprod_id) {
this.lprod_id = lprod_id;
}
public String getLprod_gu() {
return lprod_gu;
}
public void setLprod_gu(String lprod_gu) {
this.lprod_gu = lprod_gu;
}
public String getLprod_nm() {
return lprod_nm;
}
public void setLprod_nm(String lprod_nm) {
this.lprod_nm = lprod_nm;
}
@Override
public String toString() {
return "LprodVO [lprod_id=" + lprod_id + ", lprod_gu=" + lprod_gu + ", lprod_nm=" + lprod_nm + "]";
}
}
<?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="jdbc">
<select id="getLprodCount" parameterType="String" resultType="int">
select count(*) cnt from lprod where lprod_gu = #{lprod_gu}
</select>
<select id="getMaxid" resultType="int">
select max(lprod_id) maxid from lprod
</select>
<insert id="insertLprod" parameterType="lprodVo">
insert into lprod (lprod_id, lprod_gu, lprod_nm)
values (#{lprod_id}, #{lprod_gu}, #{lprod_nm} )
</insert>
</mapper>
package kr.or.ddit.basic;
import java.util.Scanner;
import org.apache.ibatis.session.SqlSession;
import kr.or.ddit.util.MybatisUtil;
import kr.or.ddit.vo.LprodVO;
public class JdbcToMyBatisTest {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
SqlSession session = null;
try {
session = MybatisUtil.getSqlSession();
int maxId = session.selectOne("jdbc.getMaxid");
maxId++;
String gu;
int count = 0;
do {
System.out.print("상품 분류 코드(LPROD_GU) 입력 >> ");
gu = scan.next();
count = session.selectOne("jdbc.getLprodCount", gu);
if(count>0) {
System.out.println("입력한 상품 분류 코드 " + gu + "는(은) 이미 등록된 코드입니다.");
System.out.println("다른 코드로 다시 입력하세요...");
System.out.println();
}
}while(count>0);
System.out.print("상품 분류명(LPROD_NM) 입력 >> ");
String nm = scan.next();
// 입력하거나 구해진 데이터를 VO에 저장
LprodVO lvo = new LprodVO();
lvo.setLprod_id(maxId);
lvo.setLprod_gu(gu);
lvo.setLprod_nm(nm);
int cnt = session.insert("jdbc.insertLprod", lvo);
if(cnt>0) {
session.commit();
System.out.println("등록 성공!!!");
}else {
System.out.println("등록 실패~~~");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
}
}
}