스프링 부트에서 토비 3.1 따라하기 : 1장 오브젝트와 의존관계 - 1.2 DAO 분리
0. 개발환경
- OS : mac
- STS : 4.0.1
- MySQL : Server version: 8.0.13 Homebrew
- Frame-Work : 일단 최대한 의존성 없이 운영될 수 있도록 jar로 만 진행
관련 링크
- 스프링 사용자 모임_홈페이지 http://www.ksug.org/
- 스프링 사용자 모임 질의응답 https://groups.google.com/forum/#!topic/ksug/13vB4tCFqrI
- 2017 스프링캠프 https://www.youtube.com/playlist?list=PLdHtZnJh1KdZ6NDO9zc9hF4tONDLTSEUV
1장 오브젝트와 의존관계
1.2 DAO 분리
관심사의 분리. 관심이 같은 것끼리는 하나의 객체 안으로 또는 친한 객체로 모이게 하고, 관심이 다른 것은 가능한 한 따로 떨어져서 서로 영향을 주지 않도록 분리하는 것이라고 생각할 수 있다.
01-1. 커넥션 만들기의 추출
1. UserDao의 관심사항 인지
1) DB연결을 위해 커넥션을 어떻게 가져올까
2) DB에 보낼 SQL 문장을 담을 statement를 샐행
(1) 파라미터로 넘어온 사용자 정보를 statement에 바인딩
(2) statement에 담긴 SQL을 DB를 통해 실행시키는 방법
(3) 사용 후엔 리소스 닫기
2. Dao 분리작업
1) 중복된 코드 제거
(1) 커넥션을 가져오는 중복된 코드 분리
- 코드 내용 = UserDao.java
package springbook.user.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import springbook.user.domain.User;
/**
* 토비의 스피링 3.1 예제 따라하기
* 1장 - 02 DAO 분리
*
* @since 2019.02.19
* @author 변찬우 http://normalstory.tistory.com
*/
public class UserDao {
public void add(User user) throws ClassNotFoundException, SQLException {
Connection c = getConnection();
PreparedStatement ps = c.prepareStatement(
"insert into users(id,name,password) values(?,?,?)");
ps.setString(1, user.getId());
ps.setString(2, user.getName());
ps.setString(3, user.getPassword());
ps.executeUpdate();
ps.close();
c.close();
}
public User get(String id) throws ClassNotFoundException, SQLException {
Connection c = getConnection();
PreparedStatement ps = c.prepareStatement(
"select * from users where id =?");
ps.setString(1, id);
ResultSet rs = ps.executeQuery();
rs.next();
User user = new User();
user.setId(rs.getNString("id"));
user.setName(rs.getString("name"));
user.setPassword(rs.getString("password"));
rs.close();
ps.close();
c.close();
return user;
}
/**
* 토비의 스피링 3.1 예제 따라하기
* 1장 - 02 DAO 분리 : ReFactoring
*
* @since 2019.02.19
* @author 변찬우 http://normalstory.tistory.com
*
* @return c
* @throws ClassNotFoundException
* @throws SQLException
*/
private Connection getConnection() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
String ConnectUrl = "jdbc:mysql://localhost:3306/sample?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC";
String ConnectId = "root";
String ConnectPass = "ever1227";
Connection c = DriverManager.getConnection(
ConnectUrl, ConnectId, ConnectPass);
return c;
}
}
(2) 변경사항 점증 테스트
PK에 해당하는 setId 값만 변경해주면 이전과 같이 정상적인 기능을 수행한다.
(3) 리뷰
방금한 작업은 UserDao의 기능에는 아무런 변화를 주지 않았다. 하지만 중요한 변화가 있었다. 앞에서 한 작업은 여러 메소드에 중복되어 등장하는 특정 관심사항이 담긴 코드를 별도의 메소드로 분리해낸 것이다. 이 작업은 기능에는 영향을 주지 않으면서 구조만 변경한다. 미래의 변화에 조금 더 손쉽게 대응할 수 있는 코드가 되었다. 이러한 작업을 리팩토링이라고 한다. 또한 이번 예제에서 처럼 공통의 기능을 담당하는 메서드로 중복된 코드를 뽑아내는 기법을 메소드 추출 extract method 기법이라고 한다.
3) DB 커넥션 만들기의 독립 = DB 커넥션 전용 클래스 만들기
본 예제에 따르면 이 기능의 경우 DB 환경이 다른 두 곳의 회사에는 납품할 수가 없다. 지금 상태로 납품을 하려면, 어쩌면 핵심 기능이 담겨있을지도 모르는 getConnection()를 공개한 후 '알아서 수정해라'라고 해야한다. 어떻게 하면 좋을까?
(1) 상속을 통한 확장
UserDao를 한번 더 분리한다. 그리고 구현코드를 제거하고 getConnection()를 추상 메서드로 만든다. 비록 코드는 없지만 메소드 자체는 존재하기 때문에 add(), get(), getConnection()을 호출하는 코드는 그대로 유지할 수 있다.
(2) getConnection() 전용 DAO
이전 getConnection() 메소드에 있던 구현 코드는 제거하고 추상 메소드로 바꾸었다.이제 메소드의 구현은 서브 클레스(class NUserDao extends UserDao)가 담당하게 된다. 코드 내용은 아래와 같다. User.java 의 내용은 실행결과 캡쳐화면을 참고하면 된다. UserDao를 NUserDao로 바꾸었다.
- 코드 내용 = UserDao.java : 여기에 있던 getConnection()를 추상클래스로 조정하고
package springbook.user.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import springbook.user.domain.User;
/**
* 토비의 스피링 3.1 예제 따라하기
* 1장 - 01 초난감 DAO
*
* @since 2019.02.17
* @author 변찬우 http://normalstory.tistory.com
*/
public abstract class UserDao {
public void add(User user) throws ClassNotFoundException, SQLException {
Connection c = getConnection();
PreparedStatement ps = c.prepareStatement(
"insert into users(id,name,password) values(?,?,?)");
ps.setString(1, user.getId());
ps.setString(2, user.getName());
ps.setString(3, user.getPassword());
ps.executeUpdate();
ps.close();
c.close();
}
public User get(String id) throws ClassNotFoundException, SQLException {
Connection c = getConnection();
PreparedStatement ps = c.prepareStatement(
"select * from users where id =?");
ps.setString(1, id);
ResultSet rs = ps.executeQuery();
rs.next();
User user = new User();
user.setId(rs.getNString("id"));
user.setName(rs.getString("name"));
user.setPassword(rs.getString("password"));
rs.close();
ps.close();
c.close();
return user;
}
/**
* 토비의 스피링 3.1 예제 따라하기
* 1장 - 02 DAO 분리 : 추상 메소드로 조정,
* 메소드 구현은 서브 클래스(NUserDao.class)가 담당
*
* @since 2019.02.19
* @author 변찬우 http://normalstory.tistory.com
*
* @return c
* @throws ClassNotFoundException
* @throws SQLException
*/
public abstract Connection getConnection()
throws ClassNotFoundException, SQLException;
}
- 코드 내용 = NUserDao. java : UserDao. java에 있던 getConnection()를 가져왔다. 이를 위해 먼저 extends UserDao 했다.
package springbook.user.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class NUserDao extends UserDao{
public Connection getConnection() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
String ConnectUrl = "jdbc:mysql://localhost:3306/sample?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC";
String ConnectId = "root";
String ConnectPass = "ever1227";
Connection c = DriverManager.getConnection(
ConnectUrl, ConnectId, ConnectPass);
return c;
}
}
(3) 실행결과
3. 프로젝트 파일 study_spring190219.zip
1) 왼쪽 프로젝트 목록 영역 내 -> 빈 공간에서 오른쪽마우스 클릭 -> import -> Existing Projects into Workspace -> 다운로드한 파일 선택
2) 혹시, 이전 포스팅 파일 import 하신 분은 이전 프로젝트를 삭제하시거나 이름을 바꾸신 후 다시 import 하셔야 합니다.
4. 업데이트( 1.4.2 제어의 역전 IoC 부분을 하다가 다시 돌아옮 ! )
우리?가 지금 한 예제가 바로 제어의 역전에 해당하는 거라는 거 !
이 예제에서의 템플릿 메소드는 제어의 역전이라는 개념을 활용해 문제를 해결하는 디자인 패턴이라고 할 수 있다.
자세한 내용은 링크에서~ ( 1.4.2 부분에 )
'새로워지기 > 서른의 생활코딩' 카테고리의 다른 글
스프링 부트에서 토비 3.1 따라하기 : 1장 - 1.4 제어의 역전 IoC (0) | 2019.02.21 |
---|---|
스프링 부트에서 토비 3.1 따라하기 : 1장 - 1.3 DAO 확장 (0) | 2019.02.21 |
스프링 부트에서 테스트 주도 개발 실습 - 2장. 타락한 객체 (0) | 2019.02.19 |
스프링 부트에서 토비 3.1 따라하기 : 1장 - 1.1 초난감 DAO (0) | 2019.02.17 |
스프링 부트에서 테스트 주도 개발 실습 - 1장. 다중통화를 지원하는 Money 객체 (0) | 2019.02.15 |
댓글