spring에서 제공하는 DAO(Data Access Object) 모듈 (일반적으로 Data Access Framework라 부름)
Spring DAO 기능을 이용하여 DAO 클래스 작성
- DAO 클래스에 JdbcTemple 객체를 제공받아 사용하는 방법
- DI(Dependency Injection)를 이용하여 JdbcTemple 객체를 제공받아 필드에 저장하여 사용
- JdbcDaoSupport 클래스를 상속받아 JdbcTemple 객체의 Getter 메소드를 호출하여 사용
ojdbc11 : JDBC 기능을 제공하기 위한 OracleDriver 관련 라이브러리
spring-jdbc : Spring DAO 관련 기능을 제공하는 라이브러리 (Spring DataSource 관련 클래스 포함)
<!-- 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>
Spring Framework의 spring-jdbc 라이브러리의 DriverManagerDataSource 클래스를 Spring Bean으로 등록
- 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>
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();
}
}
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;
}
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();
}
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(?) 대신 표현될 값을 차례대로 나열하여 제공
- 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;
}
});
}
}
JdbcDaoSupport 클래스를 상속받아 DAO 클래스 작성
RowMapper 인터페이스를 상속받은 자식클래스(내부클래스)를 객체로 생성하여 매개변수에 전달
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;
}
}
}
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();
}
studentDAO 인터페이스를 상속받은 자식클래스의 객체를 저장하기 위한 필드
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();
}
}