반응형
우리가 프로젝트에서 DAO 만들 때는 Spring 말고 mybatis 이용할 것임
왜?
- resultMap 객체의 강력한 기능들을 이용하기 위해
- resultMap 객체를 이용하면 재사용 가능, 상속 가능, 객체를 만들어 필드에 직접 주입 가능, 간단한 동적SQL 기능 구현 가능 ...
01. DTO
Student 클래스
- mybatis 처럼 자동매핑 기능은 없으므로 굳이 컬럼명과 필드명을 같게 할 필요는 없음!!
- 무조건 수동매핑만 가능
- 롬북라이브러리를 이용해 @data 에 의해 생긴 기본 메소드들, setter&getter, 생성자
package xyz.itwill08.dao;
import lombok.Data;
/*
이름 널? 유형
-------- -------- -------------
NO NOT NULL NUMBER(4)
NAME VARCHAR2(50)
PHONE VARCHAR2(50)
ADDRESS VARCHAR2(100)
BIRTHDAY DATE
*/
//학생정보를 저장하기 위한 클래스 - VO 클래스(DTO 클래스)
@Data
public class Student {
private int no;
private String name;
private String phone;
private String address;
private String birthday;
}
02. DAO [의존관계(부)]
🖤(부모) StudentDAO 인터페이스
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();
}
🖤(자식) StudentDAOImplOne 클래스
package xyz.itwill8.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import lombok.Setter;
//Spring DAO 기능을 이용하여 DAO 클래스 작성 - spring-jdbc 라이브러리를 프로젝트에 빌드 처리
// => JdbcTemplate 객체의 템플릿 메소드를 호출하여 DAO 클래스의 메소드 작성
// JdbcTemplate 객체를 제공받아 사용하는 방법
//방법1. DI(Dependency Injection)을 이용하여 JdbcTemplate 객체를 제공받아 필드에 저장하여 사용
//방법2. JdbcTemplateSupport 클래스를 상속받아 JdbcTemplate 객체의 Getter 메소드를 호출하여 사용
//방법1. 이용
@Setter
public class StudentDAOImplOne implements StudentDAO{
//JdbcTemplate 객체를 저장하기 위한 필드
// => Spring Bean configuration File에서 클래스를 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 객체의 필드값으로 저장하여 반환하기 위한 정보를 제공하는 객체
//=> mybatis의 resultMap과 동일한 기능 (Student 객체의 컬럼값을 Student 객체에 저장해주세요~)
// => RowMapper 인터페이스를 상속받은 익명의 내부클래스(Anonymous Inner Class)로 객체 생성
// => RowMapper 인터페이스의 제네릭에는 결과를 RowMapper 객체가 매핑하여 반환할 Java 객체의 자료형(클래스)를 설정
// => RowMapper 인터페이스의 mapRow 추상메소드를 반드시 오버라이드 선언
// => mapRow 메소드 : 검색행의 컬럼값을 객체 필드에 매핑되도록 설정 - 매개변수로 검색결과를 제공받아 사용 가능
return jdbcTemplate.queryForObject(sql, new RowMapper<Student>() {
@Override
//rowNum이 있으면 행번호를 붙일 필요없이 SpringDAO가 자동적으로 붙여줌
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;
}
});
}
}
🖤(자식) StudentDAOImplTwo 클래스
package xyz.itwill08.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
// JdbcTemplate 객체를 제공받아 사용하는 방법
//방법1. DI(Dependency Injection)을 이용하여 JdbcTemplate 객체를 제공받아 필드에 저장하여 사용
//방법2. JdbcTemplateSupport 클래스를 상속받아 JdbcTemplate 객체의 Getter 메소드를 호출하여 사용
//방법2. 이용
//JdbcDaoSupport 클래스를 상속받아 DAO 클래스 작성
//=> JdbcDaoSupport 클래스 : StudentTemplate 객체를 포함하고 있는 클래스
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;
}
}
}
03. Service [의존관계(주)]
- 대형프로그램 작성 시 Service 클래스 반드시 만듦
🖤(부모) StudentService 인터페이스
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();
}
🖤(자식) StudentServiceImpl 클래스
package xyz.itwill08.dao;
import java.util.List;
import lombok.Setter;
@Setter
public class StudentServiceImpl implements StudentService {
//StudentDAO 인터페이스를 상속바은 자식클래스의 객체를 저장하기 위한 필드
// => Spring Bean configuration File에서 클래스를 Spring Bean으로 등록할 때
//DAO 클래스의 Spring Bean을 제공받아 의존관계 구현 - Setter 메소드를 이용한 의존성 주입
//=> 가져다 쓸 DAO가 많다면 다 작성해줘야함
private StudentDAO studentDAO;
//ex. 장바구니Service 만들 시 (필요한 DAO 함께 모듈화 시켜주기)
//private StudentDAO productDAO;
//private StudentDAO cartDAO;
@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();
}
}
04. 💖Spring Bean Configuration File
[08_dao.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>"
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(DataBase 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">
<!-- xml 파일만 변경하면 되므로 유지보수의 효율성 증가 -->
<!-- <property name="studentDAO" ref="studentDAOImplOne"/> -->
<property name="studentDAO" ref="studentDAOImplTwo"/>
</bean>
</beans>
05. 실행프로그램
StudentApp
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);
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();
}
}
반응형
'framework > spring DAO' 카테고리의 다른 글
[SpringDAO] 1. Spring에서 DB에 접근하는 Connection 객체 생성하는 법 (0) | 2024.08.01 |
---|