본문 바로가기

programming/Gukbi

국비 교육 76일차 - spring DI, MyBatis

728x90
반응형

 새로운 문법을 배우느라 아주 정신이 없는데 그래도 블로깅으로 잘 정리해봐야겠다. 

 

어제는 오라클에 연결해서 값을 가져오는 연습을 했는데, 이번에는 select, inert, delete, update를 전부 연습해봤다. 

xml에 셋팅을 해두면, 스프링 컨테이너에서 알아서 값을 가져오고 채워 넣어주는 과정을 살펴보겠다. 

 

일단 XML 파일에 셋팅해야 할 것은 3가지이다. 

1. sql 문장

2. ?에 값 채워넣기

3. vo에 값 채워 넣기

 

이 세 가지만 개발자가 채워넣어주면, 컨테이너에서는 알아서 값을 읽어간다. 

 

 

java파일 안쪽에 app.xml 파일을 생성해주고, 오라클에서부터 값을 읽어올 수 있도록 준비를 한다. 

 

<?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:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<!-- 오라클 정보를 모아서 전송 준비 -->
	<!-- 
		public class BasicDataSource
		{
			private String driverClassName;
			private String url;
			private String username;
			private String password;
			public BasicDataSource(){
			{
				setDriverClassName(oracle.jdbc.driver.OracleDriver)
			}
			private void setDriverClassName(String driverClassName)
			{
				this.driverClassName=driverClassName
			}
		}
	 -->
	<bean id="ds" class="org.apache.commons.dbcp.BasicDataSource"
		p:driverClassName="oracle.jdbc.driver.OracleDriver"
		p:url="jdbc:oracle:thin:@localhost:1521:XE"
		p:username="hr"
		p:password="happy"
	/>
	<!-- 
		p:dataSource="ds"
		public void setDataSource(DataSource dataSource)
		{
			this.dataSource=datSource;
		}
	 -->
	<bean id="dao" class="com.sist.main.StudentDAO"
		p:dataSource-ref="ds"
	/>
</beans>

 bean id="ds"에 값을 읽어올 수 있는 BasicDataSource 클래스를 등록하고 url과 아이디, 비번을 같이 등록해준다. 

 

읽어올 dao의 패키지명과 dataSource의 주소값 (dataSource-ref)를 이용해서 연동을 해준다. 

 

package com.sist.main;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
/*
 * 	public class JdbcDaoSupport
 * 	{
 * 		private DataSource dataSource;
 * 		private Connection conn;
 * 		private PreparedStatement ps;
 * 		public void setDataSource(DataSource dataSource)
 * 		{
 * 			this.dataSource=dataSource;
 * 		}
 * 		public void getConnection()
 * 		{
 * 			conn=DriverManager.getConnection(dataSource.getUrl(), dataSource.getUername()..
 * 		}
 * 		public void disConnection()
 * 		{
 * 		}
 * 	}
 * 	DI : 클래스와 클래스들의 연관관계를 맺어 주는 것, (값을 주입해주는 것)
 */
public class StudentDAO extends JdbcDaoSupport {
	// JdbcDaoSupport ==> getConnection(), disConnection 문장 만들어줌 => DataSource(오라클 정보)
	public List studentAllData()
	{
		// 이 안에 getconnection()들어가 있음
		return getJdbcTemplate().query("SELECT name, kor, eng, math, (kor+eng+math),(kor+math+eng)/3 FROM spring_student", 
				 new RowMapper(){

					@Override
					public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
						StudentVO vo=new StudentVO();
						vo.setName(rs.getString(1));
						vo.setKor(rs.getInt(2));
						vo.setEng(rs.getInt(3));
						vo.setMath(rs.getInt(4));
						vo.setTotal(rs.getInt(5));
						vo.setAvg(rs.getDouble(6));
						return vo;
					}
					
				}
		);
	}
	/*
	 * 	객체 지향 프로그램
	 * 	제네릭스타입
	 */
	public StudentVO studentDetailData(String name)
	{
		String sql="SELECT name, kor, eng, math, (kor+eng+math),(kor+math+eng)/3 FROM spring_student WHERE name=?";
																		// 여기서 Object를 StudentVO로 형변환을 해준것	 - 제네릭스 (Object의 데이터형을 원하는 데이터형으로 바꿔주는 것) ex) List<StudentVO>
		return getJdbcTemplate().queryForObject(sql,new Object[]{name},new RowMapper<StudentVO>(){

			@Override
			public StudentVO mapRow(ResultSet rs, int rowNum) throws SQLException {
				StudentVO vo=new StudentVO();
				vo.setName(rs.getString(1));
				vo.setKor(rs.getInt(2));
				vo.setEng(rs.getInt(3));
				vo.setMath(rs.getInt(4));
				vo.setTotal(rs.getInt(5));
				vo.setAvg(rs.getDouble(6));
				return vo;
			}
			
		});
	}
	// 가변형 데이터형
	public void studentInsert(StudentVO vo)
	{
		// update(String sql, Object... args) => 가변형 매개변수
		// update(string sql, Object[] args)
		getJdbcTemplate().update("INSERT INTO spring_student VALUES(?,?,?,?)", vo.getName(), vo.getKor(), vo.getEng(), vo.getMath());
	}
	public void StudentDelete(String name)
	{
		getJdbcTemplate().update("DELETE FROM spring_student WHERE name=?", name);
	}
	public void studentUpdate(StudentVO vo)
	{
		getJdbcTemplate().update("UPDATE spring_student SET kor=?, eng=?, math=? WHERE name=?",
				vo.getKor(), vo.getEng(), vo.getMath(), vo.getName() );
	}
}

 JdbcDaoSupport는 getConnection(), disConnection() 메소드를 가지고 있다. 이것을 상속받은 StudentDAO는 DataSource로 부터 오라클 정보를 읽어오고, 오라클과 연등을 시켜준다. 

 

/*
 * 	public class JdbcDaoSupport
 * 	{
 * 		private DataSource dataSource;
 * 		private Connection conn;
 * 		private PreparedStatement ps;
 * 		public void setDataSource(DataSource dataSource)
 * 		{
 * 			this.dataSource=dataSource;
 * 		}
 * 		public void getConnection()
 * 		{
 * 			conn=DriverManager.getConnection(dataSource.getUrl(), dataSource.getUername()..
 * 		}
 * 		public void disConnection()
 * 		{
 * 		}
 * 	}
 * 	DI : 클래스와 클래스들의 연관관계를 맺어 주는 것, (값을 주입해주는 것)
 */

 내부가 이렇게 구성되어 있다고 생각하면 될 것 같다. 

 

그리고 getJdbcTemplate().update(String sql, Object ...) 내부에서는 가변형 매개변수인 Object를 사용하고 있어서 제네릭스를 사용해서 형변환을 하는 것을 잊으면 안된다. 

 

package com.sist.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.*;
public class MainClass {

	public static void main(String[] args) {
		ApplicationContext app=
				new ClassPathXmlApplicationContext("app.xml");
		// getBean 리턴형이 Object 이기 때문에 반드시 매번 형변환을 해줘야함 
		StudentDAO dao=app.getBean("dao", StudentDAO.class);
		List list=dao.studentAllData();
		for(Object obj:list)
		{
			StudentVO vo=(StudentVO)obj;
			System.out.println(vo.getName()+" "
					+vo.getKor()+" "
					+vo.getEng()+" "
					+vo.getMath()+" "
					+vo.getTotal()+" "
					+vo.getAvg());
		}
		System.out.println("===============");
		StudentVO vo=dao.studentDetailData("박지성");
		System.out.println(vo.getName()+" "
				+vo.getKor()+" "
				+vo.getEng()+" "
				+vo.getMath()+" "
				+vo.getTotal()+" "
				+vo.getAvg());
		/*StudentVO ivo=new StudentVO();
		ivo.setName("이동혁");
		ivo.setKor(60);
		ivo.setMath(60);
		ivo.setEng(60);
		dao.studentInsert(ivo);*/
		
		dao.StudentDelete("이동혁");
		StudentVO uvo=new StudentVO();
		uvo.setKor(46);
		uvo.setEng(48);
		uvo.setMath(50);
		uvo.setName("황런쥔");
		dao.studentUpdate(uvo);
		
	}

}

 Main에서는 이렇게 값을 불러오거나 저장하고 있다. 주의해서 봐야할 것은 dao로 받아온 결과값이 Object형이기 때문에, 값을 VO에 대입할때 꼭 형변환을 해줘야 한다는 점이다. 

 

StudentVO vo=(StudentVO)obj;
			System.out.println(vo.getName()+" "
					+vo.getKor()+" "
					+vo.getEng()+" "
					+vo.getMath()+" "
					+vo.getTotal()+" "
					+vo.getAvg());

 위와 같이 (StudentVO)obj로 받아온다.

 

 

다음은 myBatis에 연결해서 오라클과 연동하는 방법이다. myBatis와 연동하기 위해서는 2개의 xml 파일이 필요하다

 

1. config.xml 

2. mapper.xml

 

먼저 config.xml은 데이터베이스에 연결하는 connection 의 역할을 한다. 

 

<?xml version="1.0" encoding="UTF-8"?>
<!-- Connection -->
<!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <!-- VO등록 -->
  <typeAliases>
   <typeAlias type="com.sist.main.EmpVO" alias="EmpVO"/>
  </typeAliases>
  <!-- SQL문장 -->
  <mappers>
   <mapper resource="com/sist/main/emp-mapper.xml"/>
  </mappers>
</configuration>

 typeAlias 태그 밑에 vo를 등록을 해주고, 그 밑에 연결할 mapper.xml 파일의 주소를 적어준다. 그러면 이 config.xml이 저 주소를 읽고 mapper 파일의 sql문장을 읽어간다. 

 

 

 

mapper.xml은 ResultSet, PreparedStatement 를 관리하는 역할을 한다. 

<?xml version="1.0" encoding="UTF-8"?>
<!-- PreparedStatement,ResultSet -->
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <!-- 
      XML : namespace
      Java : Package
      
      SELECT CEIL(MAX(no)/10.0) FROM board
      resultType="int"
      SELECT pwd,name,COUNT(*) FROM board
      resultType="String"
      
      ==> Map,VO
  -->
<mapper namespace="com.sist.main.emp-mapper">
  <!-- SQL문장 -->
  <!-- 
      public List<EmpVO> empAllData()
      {
      }
      
           공통모듈 (AOP)
           
           Before
           =============
                          메소드 
           =============
           After
   -->
  <sql id="select"> <!-- include : 반복이 많은 SQL문장 일 경우  -->
    SELECT * FROM emp
  </sql>
  <select id="empAllData" resultType="EmpVO">
    <include refid="select"/>
  </select>
  <!-- 
        public EmpVO empDetailData(int empno)
        {
           return session.selectOne("id",empno)
                          selectList
        }
   -->
  <select id="empDetailData" resultType="EmpVO" parameterType="int">
    <include refid="select"/>
    WHERE empno=#{empno}
  </select>
  <!-- 
       <select> : resultType(리턴형) 어떤 결과값 , parameterType(매개변수) => ?에 값을 채운다 
       <insert> : parameterType
       <update> : parameterType
       <delete> : parameterType
   -->
</mapper>

 namespace에는 패키지명을 등록하고, 

select 태그 밑에는 불러올 sql문장을 작성한다. 

 

<select id="empAllData" resultType="EmpVO">

 id는 메소드명, resultType에는 결과값을 담을 데이터형을 적어준다. 모든 데이터를 받아오는 메소드여도 List가 아닌 EmpVO로 받아준다. 

 

<select id="empDetailData" resultType="EmpVO" parameterType="int">

  parameterType에는 매개변수로 받아올 데이터형을 적어준다. detailData를 가져올때는 주로 no (int)를 사용해서 불러오기 때문에 parameterType을 int로 설정해준다. 

 

<!-- 
       <select> : resultType(리턴형) 어떤 결과값 , parameterType(매개변수) => ?에 값을 채운다 
       <insert> : parameterType
       <update> : parameterType
       <delete> : parameterType
   -->

 

그리고 app.xml 파일에 오라클을 연결할 정보들을 등록해준다. 

<?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:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 오라클 정보 : DataSource -->
    <bean id="ds" class="org.apache.commons.dbcp.BasicDataSource"
       p:driverClassName="oracle.jdbc.driver.OracleDriver"
       p:url="jdbc:oracle:thin:@localhost:1521:XE"
       p:username="hr"
       p:password="happy"
    />
    <!-- MyBatis연결 -->
    <bean id="ssf" class="org.mybatis.spring.SqlSessionFactoryBean"
       p:dataSource-ref="ds"
       p:configLocation="classpath:config.xml"
    />
    <!-- DAO등록  -->
    <bean id="dao" class="com.sist.main.EmpDAO"
      p:sqlSessionFactory-ref="ssf"
    />
</beans>

 오라클 정보를 담고 있는 ds, 

MyBatis에 연결 시켜주는 객체인 SqlSessionFactoryBean ssf를 bean으로 생성해준다. 

 

MyBatis에 연결할때 p:를 사용해서 dataSource-ref(주소값)으로는 ds를 넣어주고, 

configLocation에는 config.xml 파일의 경로값을 넣어준다. (classpath는 자바 파일까지의 주소를 의미한다)

 

그리고 나서 dao를 등록한다. 이때 sqlSessionFactory-ref에는 위에서 생성한 ssf의 주소를 입력해준다. 

 

package com.sist.main;

import org.mybatis.spring.support.SqlSessionDaoSupport;
/*
 *   89page
 *                      JDBC          MyBatis => 필요한 데이터는 XML,Annotation
 *   1) Connection   직접 생성                    자동 생성 
 *   2) Statement    직접 전송                    자동 전송 
 *   3) ResultSet    직접 처리                    자동 생성 
 *   4) close        직접 처리                    자동 처리
 *                                   필요한 데이터 
 *                                    1) 오라클 정보  => DataSource
 *                                    2) SQL문장     => mapper.xml
 *                                    3) 결과값 받는 데이터형 설정 => resultType , parameterType
 *                                    
 *     public List selectList()
 *     {
 *          getConnection()
 *          ================================
 *          
 *          ================================
 *          ps=conn.preparedStatement(sql);
 *          ================================
 *          
 *          ================================
 *          ResultSet rs=ps.executeQuery();
 *          while(rs,next())
 *          {
 *             
 *          }
 *          disConnection()
 *     }
 */
import java.util.*;
public class EmpDAO extends SqlSessionDaoSupport{
    public List<EmpVO> empAllData()
    {
    	return getSqlSession().selectList("empAllData");
    	// connection
    }
    public EmpVO empDetailData(int empno)
    {
    	return getSqlSession().selectOne("empDetailData",empno);
    }
    public EmpVO empUpdateData(int empno)
    {
    	return getSqlSession().selectOne("empDetailData",empno);
    }
}

 저 위의 빈 부분을 mapper.xml에서 채워준다고 생각하면 된다. 

 

그리고 mapper에서 등록한 메소드들을 호출해서 return값으로 받아오면 된다. 

매개변수가 있는 메소드인지, 하나만을 배출하는 메소드인지, List로 여러 값을 배출하는 메소드인지 잘 생각해서 받아온다. 

 

package com.sist.main;
import java.util.*;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainClass {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
        ApplicationContext app=
        		new ClassPathXmlApplicationContext("app.xml");
        EmpDAO dao=(EmpDAO)app.getBean("dao");
        //EmpDAO dao=new EmpDAO();
        List<EmpVO> list=dao.empAllData();
        for(EmpVO vo:list)
        {
        	System.out.println(vo.getEmpno()+" "
        			+vo.getEname()+" "
        			+vo.getJob()+" ");
        }
        System.out.println("=======================");
        EmpVO vo=dao.empDetailData(7788);
        System.out.println(vo.getEmpno()+" "
    			+vo.getEname()+" "
    			+vo.getJob()+" ");
        System.out.println("========================");
        vo=dao.empUpdateData(7788);
        System.out.println(vo.getEmpno()+" "
    			+vo.getEname()+" "
    			+vo.getJob()+" ");
	}

}

 그리고 main 에서 실행

 

ApplicationContext로 app.xml에 등록해둔 오라클 정보, MyBatis연결, dao등록 정보를 읽어온다. 

그리고 dao를 생성하고, 필요한 값들을 가져올 수 있게 메소드들을 실행한다. 

 

이게 xml기반으로 MyBatis에 연결하는 방법이었다. 

 

 

 

annotaion으로 MyBatis에 연결하는 방법도 있다. 

 

package com.sist.main2;

import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.stereotype.Component;

/*
 *   <bean id="ds" class="org.apache.commons.dbcp.BasicDataSource"
       p:driverClassName="oracle.jdbc.driver.OracleDriver"
       p:url="jdbc:oracle:thin:@localhost:1521:XE"
       p:username="hr"
       p:password="happy"
    />
     * 
     * myBasicDataSource
 */
@Component("ds")
public class MyBasicDataSource extends BasicDataSource{
   public MyBasicDataSource()
   {
	   setDriverClassName("oracle.jdbc.driver.OracleDriver");
	   setUrl("jdbc:oracle:thin:@localhost:1521:XE");
	   setUsername("hr");
	   setPassword("happy");
   }
}

 위는 BasicDataSource 파일

오라클 정보를 적어두고 읽어올 수 있도록 한다. 

 

위에 @Component("ds") 어노테이션을 줘서 ds로 주소값을 읽어올 수 있게 해준다. 

 

 

package com.sist.main2;

import javax.sql.DataSource;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

/*
 *   <bean id="ssf" class="org.mybatis.spring.SqlSessionFactoryBean"
       p:dataSource-ref="ds"
       p:configLocation="classpath:config.xml"
    />
 */
@Component("ssf")
public class MySqlSesseionFactoryBean extends SqlSessionFactoryBean{

	@javax.annotation.Resource(name="ds")
	public void setDataSource(DataSource dataSource) {
		// TODO Auto-generated method stub
		super.setDataSource(dataSource);
	}
    public MySqlSesseionFactoryBean()
    {
    	try
    	{
    		Resource res=new ClassPathResource("config.xml");
        	setConfigLocation(res);
    	}catch(Exception ex){}
    }
}

MySqlSesseionFactoryBean파일. 

Resource로 ds의 주소값을 읽어와서 dataSource(오라클 정보)를 가져오고, config.xml파일의 위치를 찾아 MyBatis에 연결 할 수 있도록 한다. 

 

package com.sist.main2;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.*;

import javax.annotation.Resource;
/*
 *   <bean id="dao" class="com.sist.main.EmpDAO"
      p:sqlSessionFactory-ref="ssf"
    />
 */
@Repository("dao")
public class EmpDAO extends SqlSessionDaoSupport{
	
    @Resource(name="ssf")
	public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
		// TODO Auto-generated method stub
		super.setSqlSessionFactory(sqlSessionFactory);
	}
    
	public List<EmpVO> empAllData()
    {
    	return getSqlSession().selectList("empAllData");
    }
    public EmpVO empDetailData(int empno)
    {
    	return getSqlSession().selectOne("empDetailData",empno);
    }
}

 그리고 dao를 생성해주는 파일 

SqlSessionDaoSupport를 상속받아온다. ssf의 주소값을 받아와서 dao를 등록해준다. 

 

package com.sist.main2;
import java.util.*;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainClass {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
        ApplicationContext app=
        		new ClassPathXmlApplicationContext("app2.xml");
        EmpDAO dao=(EmpDAO)app.getBean("dao");
        List<EmpVO> list=dao.empAllData();
        for(EmpVO vo:list)
        {
        	System.out.println(vo.getEmpno()+" "
        			+vo.getEname()+" "
        			+vo.getJob());
        }
	}

}

 그리고 Main에서 다시 실행해주면 데이터를 읽어오게 된다. 

 

여기까지가 오늘 집중적으로 배웠던 MyBatis 연결이다. 

 

우선 DataSource (ds)가 데이터 베이스 연동을 위한 정보를 가지고 있다는 것, 

SqlSessionFactoryBean(ssf)가 Mybatis 연결을 해준다는 것, 

dao 등록은 ssf의 주소값을 읽어와서 해준 다는 것

 

이 세가지 흐름을 잘 파악하고 있어야 겠다. 

 

또 config.xml은 connection의 역할을,

 public List selectList()
 *     {
 *          getConnection()
 *          ================================
 *          
 *          ================================
 *          ps=conn.preparedStatement(sql);
 *          ================================
 *          
 *          ================================
 *          ResultSet rs=ps.executeQuery();
 *          while(rs,next())
 *          {
 *             
 *          }
 *          disConnection()
 *     }

mapper.xml은 이 공백의 값을 채워주는 문장을 적어주고 있다는 것을 잘 기억하고 있어야 겠다. 

 

 

 

728x90
반응형