MVC 패턴, Mybatis

dev_hnbm·2023년 11월 28일
1

대덕인재개발원

목록 보기
20/30
post-thumbnail

MVC 패턴

MVC(Mode-View-Controller) 패턴은 소프트웨어 디자인 패턴 중 하나로, 소프트웨어를 세 가지 주요 구성 요소로 나누어 설계하는 방법이다. 각 구성 요소는 특정한 역할을 수행하며, 이를 통해 소프트웨어의 유지보수성과 확장성을 향상시킬 수 있다.

  1. Model: 데이터와 데이터를 처리하는 비즈니스 로직 관리
  2. View: 사용자 인터페이스, 사용자에게 정보를 표시하고 정보를 입력받음
  3. Controller: 사용자 입력을 받아 Model을 업데이트 하거나 모델로부터 데이터를 가져와 View를 업데이트, Model과 View 사이의 중간자 역할 수행

MVC 패턴의 비즈니스 로직에 사용되는 클래스

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에서 처리한다.

VO 객체의 멤버 변수 자동 생성 (DB 연동용)

SELECT 'private ' ||
		DECODE(LOWER(DATA_TYPE), 'number', 'int ', 'String ') ||
		LOWER(COLUMN_NAME) || ';'
FROM COLS
WHERE LOWER(TABLE_NAME) = 'jdbc_board';




MyBatis

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

MyBatis 환경 설정 문서 (mybatis-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>
	<!-- 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>

MyBatis SQL 작성 문서 (mapper.xml)

코드 보기 전에 💁‍♀️

  • <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로 DB를 처리하는 순서

  1. MyBatis의 환경 설정 파일 (mybatis-config.xml)을 읽어와서 그 내용을 처리한 후 SqlSessionFactory 객체를 생성한다. 환경 설정 파일을 읽어올 스트림 객체를 생성해야 하고, 처리 성공시 SqlSessionFactory 객체를 생성하여 반환한다.
  2. mapper에 등록된 SQL문 중 실행할 SQL문을 호출하여 원하는 작업을 수행한다.
    첫번째로, 위에서 생성된 SqlSessionFactory 객체의 openSession()을 이용하여 mapper에서 SQL문을 호출하고 실행할 수 있는 SqlSession 객체를 생성한다.
    두번째로, SqlSession 객체를 이용하여 처리할 SQL문을 호출하여 실행한다.




MVC 패턴 + MyBatis 연습

java 기본 틀 갖추기 (참고)

  • jdbc jar 파일 및 mybatis jar 파일 추가
  • src folder
    • MVC 패턴에 맞는 패키지 및 클래스 생성 (controller, service, dao, vo)
    • DB 연결 관련 패키지 및 클래스 생성 (util)
  • res folder
    • DB 및 MyBatis 환경 설정 관련 패키지 및 파일 생성 (config)
    • SQL문 작성 관련 패키지 및 파일 생성 (mapper)

아래 예제는 간단하게 구현한 내용으로 controller 대신 test용 클래스 (JdbcToMyBatisTest.java), util, vo, config, mapper만 사용한 점 참고하기~

1. dbinfo.properties

DB 연결 환경 설정
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:xe
user=pc15
pass=java

2. mybatis-config.xml

mybatis 환경 설정
<?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>

3. MybatisUtil.java

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

4. LprodVO.java

테이블 컬럼 정보 저장
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 + "]";
	}
	
}

5. jdbc-mapper.xml

SQL문 작성
<?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>

6. JdbcToMyBatisTest.java

Controller 대신 테스트용 클래스
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();
		}
		
	}

}

0개의 댓글