SpringDAO (JdbcTemple 객체의 템플릿 메소드 호출)

woom·2023년 2월 20일
0

Framework

목록 보기
11/20
post-thumbnail

🌼 SpringDAO

  • spring에서 제공하는 DAO(Data Access Object) 모듈 (일반적으로 Data Access Framework라 부름)

    • Framework들의 기본 원리는 Template Method Pattern을 기본으로 구성됨
    • DataSource 객체 필요 (jdbc기능을 제공하기 위한 lib 빌드 처리 필요)
  • Spring DAO 기능을 이용하여 DAO 클래스 작성

    • spring-jdbc 라이브러리를 프로젝트에 빌드 처리
    • JdbcTemple 객체의 템플릿 메소드를 호출하여 DAO 클래스의 메소드 작성
  • DAO 클래스에 JdbcTemple 객체를 제공받아 사용하는 방법
  1. DI(Dependency Injection)를 이용하여 JdbcTemple 객체를 제공받아 필드에 저장하여 사용
  2. JdbcDaoSupport 클래스를 상속받아 JdbcTemple 객체의 Getter 메소드를 호출하여 사용

📌 jdbc lib 빌드 처리

  • ojdbc11 : JDBC 기능을 제공하기 위한 OracleDriver 관련 라이브러리

  • spring-jdbc : Spring DAO 관련 기능을 제공하는 라이브러리 (Spring DataSource 관련 클래스 포함)

    • 라이브러리 의존관계에 의해 spring-tx 라이브러리(트렌젝션 관리)도 빌드 처리


		<!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc11 -->
		<!-- => JDBC 기능을 제공하기 위한 OracleDriver 관련 라이브러리 -->
		<dependency>
		    <groupId>com.oracle.database.jdbc</groupId>
		    <artifactId>ojdbc11</artifactId>
		    <version>21.9.0.0</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
		<!-- => Spring DAO 관련 기능을 제공하는 라이브러리 - Spring DataSource 관련 클래스 포함 -->
		<!-- => 라이브러리 의존관계에 의해 spring-tx 라이브러리(트렌젝션 관리)도 빌드 처리 -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-jdbc</artifactId>
		    <version>${org.springframework-version}</version>
		</dependency>





💡 JDBC

  • JDBC를 이용해서 Database에 비종속적인 DB연동 프로그램을 구현 가능
  • JDBC 프로그램 작성 순서


📕 환경설정파일 (DBCP)

  • Spring Framework의 spring-jdbc 라이브러리의 DriverManagerDataSource 클래스를 Spring Bean으로 등록

    • DBCP(DataBasc ConnectionPool) 기능을 제공하는 DataSource 객체 생성
    • DataSource 객체 필드에 Connection 객체를 생성하기 위한 값을 전달하여 저장 (Setter Injection)
  • JdbcTemplate 클래스를 Spring Bean으로 등록
    • dataSource 필드에 DataSource 인터페이스를 상속받은 자식클래스의 Spring Bean을 제공받아 의존성 주입 (Setter Injection)
  • StudentDAO 인터페이스를 상속받은 자식클래스를 Spring Bean으로 등록
    • jdbcTemplate 필드에 JdbcTemplate 클래스의 Spring Bean을 제공받아 의존성 주입 (Setter Injection)
  • StudentService 인터페이스를 상속받은 자식클래스를 Spring Bean으로 등록
    • studentDAO 필드에 StudentDAO 인터페이스를 상속받은 자식클래스의 Spring Bean을 제공받아 의존성 주입 (Setter Injection_

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	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.xsd">

	<!-- Spring Framework의 spring-jdbc 라이브러리의 DriverManagerDataSource 클래스를 Spring Bean으로 등록 -->
	<!-- => DBCP(DataBasc ConnectionPool) 기능을 제공하는 DataSource 객체 생성 -->
	<!-- => DataSource 객체 필드에 Connection 객체를 생성하기 위한 값을 전달하여 저장 - Setter Injection -->
	<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
		<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
		<property name="username" value="scott"/>
		<property name="password" value="tiger"/>
	</bean>
	
	<!-- JdbcTemplate 클래스를 Spring Bean으로 등록 -->
	<!-- => dataSource 필드에 DataSource 인터페이스를 상속받은 자식클래스의 Spring Bean을 
	제공받아 의존성 주입 - Setter Injection -->
	<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
		<property name="dataSource" ref="dataSource"/>
	</bean>
	
	<!-- StudentDAO 인터페이스를 상속받은 자식클래스를 Spring Bean으로 등록 -->
	<!-- => jdbcTemplate 필드에 JdbcTemplate 클래스의 Spring Bean을 제공받아 의존성 주입 - Setter Injection -->
	<bean class="xyz.itwill08.dao.StudentDAOImplOne" id="studentDAOImplOne">
		<property name="jdbcTemplate" ref="jdbcTemplate"/>
	</bean>
	
	<bean class="xyz.itwill08.dao.StudentDAOImplTwo" id="studentDAOImplTwo">
		<property name="jdbcTemplate" ref="jdbcTemplate"/>
	</bean>
	
	<!-- StudentService 인터페이스를 상속받은 자식클래스를 Spring Bean으로 등록 -->
	<!-- => studentDAO 필드에 StudentDAO 인터페이스를 상속받은 자식클래스의 Spring Bean을 
	제공받아 의존성 주입 - Setter Injection -->
	<bean class="xyz.itwill08.dao.StudentServiceImpl" id="studentService">
		<!-- <property name="studentDAO" ref="studentDAOImplOne"/> -->
		<property name="studentDAO" ref="studentDAOImplTwo"/>
	</bean>
</beans>





🐣 DataSource App

  • DataSource 객체 : 다수의 Connection 객체를 미리 생성하여 저장하기 위한 객체
    • DBCP(DataBase ConnectionPool)
    • Spring Bean Configuration File에서 DataSource 인터페이스를 상속받은 자식클래스를 Spring Bean 등록하여 사용
    • DataSource 인터페이스를 상속받은 자식클래스는 Spring Framework에서 제공하는 spring-jdbc 라이브러리를 빌드 처리하여 사용 (메이븐 : pom.xml)
    • DataSource 관련 라이브러리외에 Oracle Driver 관련 ojdbc 라이브러리도 프로젝트에 빌드 처리


package xyz.itwill08.dao;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DataSourceApp {
	public static void main(String[] args) throws SQLException {
		ApplicationContext context=new ClassPathXmlApplicationContext("08_dao.xml");
		DataSource dataSource=context.getBean("dataSource", DataSource.class);
		System.out.println("================================================================");
		System.out.println("dataSource = "+dataSource);
		Connection connection=dataSource.getConnection();
		System.out.println("connection = "+connection);
		connection.close();
		System.out.println("================================================================");
		((ClassPathXmlApplicationContext)context).close();	
	}
}





🐣 Student class (vo)

  • 학생정보를 저장하기 위한 클래스 - VO 클래스(DTO 클래스)

package xyz.itwill08.dao;

import lombok.Data;

/*
이름       널?       유형            
-------- -------- ------------- 
NO       NOT NULL NUMBER(4)     
NAME              VARCHAR2(50)  
PHONE             VARCHAR2(20)  
ADDRESS           VARCHAR2(100) 
BIRTHDAY          DATE 
*/

@Data
public class Student {
	private int no;
	private String name;
	private String phone;
	private String address;
	private String birthday;
}





🌸 StudentDAO (interface)


package xyz.itwill08.dao;

import java.util.List;

public interface StudentDAO {
	int insertStudent(Student student);
	int updateStudent(Student student);
	int deleteStudent(int no);
	Student selectStudent(int no);
	List<Student> selectStudentList();
}






📙 DAOImpl1 (JdbcTemplate 필드)

  • JdbcTemplate 객체를 저장하기 위한 필드
    • Spring Bean Configuration File에서 DAO 클래스를 Spring Bean으로 등록할 때 JdbcTemplate 클래스의 Spring Bean를 제공받아 의존관계 구현 (Setter 메소드를 이용한 의존성 주입)
    • private JdbcTemplate jdbcTemplate;
  • JdbcTemplate.update(String sql, Object ... args) : SQL 명령(INSET,UPDATE,DELETE)을 DBMS 서버에 전달하여 실행하는 메소드 (조작행의 갯수 반환)
    • 매개변수에는 DBMS 서버에 전달한 SQL 명령과 SQL 명령의 InParameter(?) 대신 표현될 값을 차례대로 나열하여 제공
    • SQL 명령의 InParameter(?) 갯수만큼 반드시 args 매개변수에 값을 전달
  • JdbcTemplate.queryForObject(String sql, RowMapper<T> rowMapper, Object ... args)
    • SQL 명령(SELECT)을 DBMS 서버에 전달하여 실행하는 메소드
    • 단일행의 검색결과를 하나의 Java 객체로 반환받기 위해 사용
    • 매개변수에는 DBMS 서버에 전달한 SQL 명령과 검색행을 Java 객체로 변환하기 위한 매핑정보를 저장한 RowMapper 객체와 SQL 명령의 InParameter(?) 대신 표현될 값을 차례대로 나열하여 제공
  • RowMapper 객체 : 검색행의 컬럼값을 Java 객체의 필드값으로 저장하여 반환하기 위한 정보를 제공하는 객체
    • RowMapper 인터페이스를 상속받은 익명의 내부클래스(Annoymous Inner Class)로 객체 생성
    • RowMapper 인터페이스의 제네릭에는 RowMapper 객체가 매핑하여 반환할 Java 객체의 자료형(클래스)을 설정
    • RowMapper 인터페이스의 mapRow 추상메소드를 반드시 오버라이드 선언
    • mapRow 메소드 : 검색행의 컬럼값을 객체 필드에 매핑되도록 설정 (매개변수로 검색결과를 제공받아 사용 가능)
    • EmptyResultDataAccessException : queryForObject() 메소드에 의해 검색된 행이 없는 경우 발생되는 예외
  • JdbcTemplate.query(String sql, RowMapper<T> rowMapper, Object ... args)
    • SQL 명령(SELECT)을 DBMS 서버에 전달하여 실행하는 메소드
    • 다수행의 검색결과를 List 객체로 반환받기 위해 사용 (하나의 검색행은 List 객체의 요소로 추가)
    • 매개변수에는 DBMS 서버에 전달한 SQL 명령과 검색행을 Java 객체로 변환하기 위한 매핑정보를 저장한 RowMapper 객체와 SQL 명령의 InParameter(?) 대신 표현될 값을 차례대로 나열하여 제공


package xyz.itwill08.dao;

//SpringDAO 기능을 이용하여 DAO 클래스 작성 - spring-jdbc 라이브러리를 프로젝트에 빌드 처리 
// => JdbcTemple 객체의 템플릿 메소드를 호출하여 DAO 클래스의 메소드 작성

//DAO 클래스에 JdbcTemple 객체를 제공받아 사용하는 방법
//1.DI(Dependency Injection)를 이용하여 JdbcTemple 객체를 제공받아 필드에 저장하여 사용
//2.JdbcDaoSupport 클래스를 상속받아 JdbcTemple 객체의 Getter 메소드를 호출하여 사용

@Setter
public class StudentDAOImplOne implements StudentDAO {
	//JdbcTemplate 객체를 저장하기 위한 필드
	// => Spring Bean Configuration File에서 DAO 클래스를 Spring Bean으로 등록할 때 JdbcTemplate
	//클래스의 Spring Bean를 제공받아 의존관계 구현 - Setter 메소드를 이용한 의존성 주입
	private JdbcTemplate jdbcTemplate;

	@Override
	public int insertStudent(Student student) {
		String sql="insert into student values(?,?,?,?,?)";
		//JdbcTemplate.update(String sql, Object ... args) : SQL 명령(INSERT,UPDATE,DELETE)을
		//DBMS 서버에 전달하여 실행하는 메소드 - 조작행의 갯수 반환
		// => 매개변수에는 DBMS 서버에 전달한 SQL 명령과 SQL 명령의 InParameter(?) 대신 표현될
		//값을 차례대로 나열하여 제공
		// => SQL 명령의 InParameter(?) 갯수만큼 반드시 args 매개변수에 값을 전달
		return jdbcTemplate.update(sql, student.getNo(), student.getName()
				, student.getPhone(), student.getAddress(), student.getBirthday());
	}

	@Override
	public int updateStudent(Student student) {
		String sql="update student set name=?,phone=?,address=?,birthday=? where no=?";
		return jdbcTemplate.update(sql, student.getName(), student.getPhone()
				, student.getAddress(), student.getBirthday(), student.getNo());
	}
	
	@Override
	public int deleteStudent(int no) {
		return jdbcTemplate.update("delete from student where no=?", no);
	}

	@Override
	public Student selectStudent(int no) {
		try {
			String sql="select * from student where no=?";
			//JdbcTemplate.queryForObject(String sql, RowMapper<T> rowMapper, Object ... args)
			// => SQL 명령(SELECT)을 DBMS 서버에 전달하여 실행하는 메소드
			// => 단일행의 검색결과를 하나의 Java 객체로 반환받기 위해 사용
			// => 매개변수에는 DBMS 서버에 전달한 SQL 명령과 검색행을 Java 객체로 변환하기 위한 매핑정보를 
			//저장한 RowMapper 객체와 SQL 명령의 InParameter(?) 대신 표현될 값을 차례대로 나열하여 제공
			//RowMapper 객체 : 검색행의 컬럼값을 Java 객체의 필드값으로 저장하여 반환하기 위한 정보를 제공하는 객체
			// => RowMapper 인터페이스를 상속받은 익명의 내부클래스(Annoymous Inner Class)로 객체 생성
			// => RowMapper 인터페이스의 제네릭에는 RowMapper 객체가 매핑하여 반환할 Java 객체의 자료형(클래스)을 설정
			// => RowMapper 인터페이스의 mapRow 추상메소드를 반드시 오버라이드 선언
			// => mapRow 메소드 : 검색행의 컬럼값을 객체 필드에 매핑되도록 설정 - 매개변수로 검색결과를 제공받아 사용 가능
			return jdbcTemplate.queryForObject(sql, new RowMapper<Student>() {
				@Override
				public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
					Student student=new Student();
					student.setNo(rs.getInt("no"));
					student.setName(rs.getString("name"));
					student.setPhone(rs.getString("phone"));
					student.setAddress(rs.getString("address"));
					student.setBirthday(rs.getString("birthday"));
					return student;
				}
			}, no);
		} catch (EmptyResultDataAccessException e) {
			//EmptyResultDataAccessException : queryForObject() 메소드에 의해 검색된 행이
			//없는 경우 발생되는 예외
			return null;
		}
	}

	@Override
	public List<Student> selectStudentList() {
		String sql="select * from student order by no";
		//JdbcTemplate.query(String sql, RowMapper<T> rowMapper, Object ... args)
		// => SQL 명령(SELECT)을 DBMS 서버에 전달하여 실행하는 메소드
		// => 다수행의 검색결과를 List 객체로 반환받기 위해 사용 - 하나의 검색행은 List 객체의 요소로 추가
		// => 매개변수에는 DBMS 서버에 전달한 SQL 명령과 검색행을 Java 객체로 변환하기 위한 매핑정보를 
		//저장한 RowMapper 객체와 SQL 명령의 InParameter(?) 대신 표현될 값을 차례대로 나열하여 제공
		return jdbcTemplate.query(sql, new RowMapper<Student>() {
			@Override
			public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
				Student student=new Student();
				student.setNo(rs.getInt("no"));
				student.setName(rs.getString("name"));
				student.setPhone(rs.getString("phone"));
				student.setAddress(rs.getString("address"));
				student.setBirthday(rs.getString("birthday"));
				return student;
			}
		});
	}
}





📙 DAOImpl2 (JdbcDaoSupport 상속)

  • JdbcDaoSupport 클래스를 상속받아 DAO 클래스 작성

    • JdbcDaoSupport 클래스 : JdbcTemplate 객체를 포함하고 있는 클래스
    • JdbcDaoSupport 클래스의 getJdbcTemplate() 메소드를 호출하여 JdbcTemplate 객체를 반환받아 템플릿 메소드 호출
  • RowMapper 인터페이스를 상속받은 자식클래스(내부클래스)를 객체로 생성하여 매개변수에 전달

    • 중복된 코드를 최소화하여 유지보수의 효율성 증가
    • RowMapper 인터페이스를 상속받은 자식클래스 - 내부 클래스(Inner Class - Nested Class)
    • 검색행의 컬럼값을 객체 필드에 저장하는 매핑정보를 제공하여 객체를 반환하는 메소드


package xyz.itwill08.dao;

public class StudentDAOImplTwo extends JdbcDaoSupport implements StudentDAO {
	@Override
	public int insertStudent(Student student) {
		String sql="insert into student values(?,?,?,?,?)";
		//JdbcDaoSupport 클래스의 getJdbcTemplate() 메소드를 호출하여 JdbcTemplate 객체를 
		//반환받아 템플릿 메소드 호출
		return getJdbcTemplate().update(sql, student.getNo(), student.getName()
				, student.getPhone(), student.getAddress(), student.getBirthday());
	}

	@Override
	public int updateStudent(Student student) {
		String sql="update student set name=?,phone=?,address=?,birthday=? where no=?";
		return getJdbcTemplate().update(sql, student.getName(), student.getPhone()
				, student.getAddress(), student.getBirthday(), student.getNo());
	}
	
	@Override
	public int deleteStudent(int no) {
		return getJdbcTemplate().update("delete from student where no=?", no);
	}

	@Override
	public Student selectStudent(int no) {
		try {
			String sql="select * from student where no=?";
			//RowMapper 인터페이스를 상속받은 자식클래스를 객체로 생성하여 매개변수에 전달
			// => 중복된 코드를 최소화하여 유지보수의 효율성 증가
			return getJdbcTemplate().queryForObject(sql, new StudentRowMapper(), no);
		} catch (EmptyResultDataAccessException e) {
			return null;
		}
	}

	@Override
	public List<Student> selectStudentList() {
		String sql="select * from student order by no";
		return getJdbcTemplate().query(sql, new StudentRowMapper());
	}
	
	//RowMapper 인터페이스를 상속받은 자식클래스 - 내부 클래스(Inner Class - Nested Class)
	// => 검색행의 컬럼값을 객체 필드에 저장하는 매핑정보를 제공하여 객체를 반환하는 메소드
	public class StudentRowMapper implements RowMapper<Student> {
		@Override
		public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
			Student student=new Student();
			student.setNo(rs.getInt("no"));
			student.setName(rs.getString("name"));
			student.setPhone(rs.getString("phone"));
			student.setAddress(rs.getString("address"));
			student.setBirthday(rs.getString("birthday"));
			return student;
		}
	}
}





🌸 Service (interface)

package xyz.itwill08.dao;

import java.util.List;

public interface StudentService {
	void addStudent(Student student);
	void modifyStudent(Student student);
	void removeStudent(int no);
	Student getStudent(int no);
	List<Student> getStudentList();
	
}






📒 ServiceImpl (interface상속)

  • studentDAO 인터페이스를 상속받은 자식클래스의 객체를 저장하기 위한 필드

    • Spring Bean Configuration File에서 Service 클래스를 Spring Bean으로 등록할 때 DAO 클래스의 Spring Bean를 제공받아 의존관계 구현 (Setter 메소드를 이용한 의존성 주입)

package xyz.itwill08.dao;

import java.util.List;

import lombok.Setter;

@Setter
public class StudentServiceImpl implements StudentService {
	
	private StudentDAO studentDAO;
	
	@Override
	public void addStudent(Student student) {
		studentDAO.insertStudent(student);
	}

	@Override
	public void modifyStudent(Student student) {
		studentDAO.updateStudent(student);
	}

	@Override
	public void removeStudent(int no) {
		studentDAO.deleteStudent(no);
	}

	@Override
	public Student getStudent(int no) {
		return studentDAO.selectStudent(no);
		
	}

	@Override
	public List<Student> getStudentList() {
		return studentDAO.selectStudentList();
	}

}






🐣 앱 실행

package xyz.itwill08.dao;

import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StudentApp {
	public static void main(String[] args) {
		ApplicationContext context=new ClassPathXmlApplicationContext("08_dao.xml");
		StudentService service=context.getBean("studentService", StudentService.class);
		System.out.println("================================================================");
		/*
		Student newStudent=new Student();
		newStudent.setNo(6000);
		newStudent.setName("홍경래");
		newStudent.setPhone("010-4687-1311");
		newStudent.setAddress("서울시 도봉구");
		newStudent.setBirthday("1999-05-05");
		service.addStudent(newStudent);
		*/
		
		/*
		Student searchStudent=service.getStudent(6000);
		System.out.println(searchStudent);
		searchStudent.setName("로빈훗");
		searchStudent.setBirthday("1999-02-05");
		service.modifyStudent(searchStudent);
		*/
		
		service.removeStudent(6000);
		
		List<Student> studentList=service.getStudentList();
		for(Student student:studentList) {
			System.out.println("학번 = "+student.getNo()+", 이름 = "+student.getName()
				+", 전화번호 = "+student.getPhone()+", 주소 = "+student.getAddress()
				+", 생년월일 = "+student.getBirthday().substring(0, 10));
		}
		System.out.println("================================================================");
		((ClassPathXmlApplicationContext)context).close();	
	}
}





profile
Study Log 📂

0개의 댓글