이전에 했던 프로젝트를 인터페이스 클래스를 사용하여 나중에 Spring에서 사용할때 다중 상속을 받을 수 있도록 리팩토링 하였다.(DB별 설정 각자 받음)
이전 프로젝트 : https://velog.io/@qowl880/Java-Java%EC%97%90%EC%84%9C-Query%EB%AC%B8-%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%812
public interface ConnectionMaker { // makeConnection을 각 DB에 맞게 사용할 수 있도록 불러오기 위한 interface
Connection makeConnection() throws SQLException, ClassNotFoundException;
}
@Override
public Connection makeConnection() throws SQLException, ClassNotFoundException {
Map<String, String> env = System.getenv(); // 환경변수를 사용하여
String dbHost = env.get("DB_HOST");
String dbUser = env.get("DB_USER");
String dbPassword = env.get("DB_PASSWORD");
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection(dbHost, dbUser, dbPassword);
return conn;
}
public class LocalConnectionMaker implements ConnectionMaker {
@Override
public Connection makeConnection() throws SQLException {
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/likelion-db","root","password");
// 원래는 dbHost, dbUser,dbPassword를 가져와 넣어야 하지만 root는 주소를 오픈해도 해커가 침투하기가 힘들다
return conn;
}
}
class UserDaoInterfaceTest {
@Test
void addAndSelect() throws ClassNotFoundException, SQLException {
UserDaoInterface userDao = new UserDaoInterface();
String id = "12";
User user = new User(id,"test","1234"); // user 값을 DTO에 저장함
userDao.add(user); // DB 값 Insert
User selectedUser = userDao.select(id); // DTO에 저장되어 있는 데이터를 가져와 비교함
Assertions.assertEquals("test",selectedUser.getName());
}
}
public interface ConnectionMaker { // makeConnection을 각 DB에 맞게 사용할 수 있도록 불러오기 위한 interface
Connection makeConnection() throws SQLException, ClassNotFoundException;
}
public class AWSConnectionMaker implements ConnectionMaker {
@Override
public Connection makeConnection() throws SQLException, ClassNotFoundException {
Map<String, String> env = System.getenv(); // 환경변수를 사용하여
String dbHost = env.get("DB_HOST");
String dbUser = env.get("DB_USER");
String dbPassword = env.get("DB_PASSWORD");
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection(dbHost, dbUser, dbPassword);
return conn;
}
}
public class LocalConnectionMaker implements ConnectionMaker {
@Override
public Connection makeConnection() throws SQLException {
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/likelion-db","root","password");
return conn;
}
}
※ Bean 관련 설명 : https://velog.io/@qowl880/Bean%EC%9D%B4%EB%9E%80
Bean 파일 추가하는 법
@Configuration
public class HelloConfiguration {
@Bean
public HelloController sampleController() {
return new SampleController;
}
}
@Configuration과 @Bean Annotation 을 이용하여 Bean을 등록할 수 있다. @Configuration를 사용하여 Spring Project에서의 Configuration 역할을 하는 Class를 지정할 수 있다. 해당 File 하위에 Bean 으로 등록하고자 하는 Class에 @Bean Annotation을 사용해주면 간단하게 Bean을 등록할 수 있다.
Factory 클래스
UserDao, UserDaoTest등에서 ConnectionMakerInterface의 구현제인 AWSConnectionMaker나 LocalConnectionMaker를 주입받아야함 따라서 주입받는 부분을 팩토리에 모아놓음으로써 객체들을 한곳에서 관리할 수 있음
@Configuration
public class UserDaoFactory {
@Bean
public UserDaoInterface awsUserDao(){
AWSConnectionMaker awsConnectionMaker = new AWSConnectionMaker();
UserDaoInterface userDao = new UserDaoInterface(awsConnectionMaker);
return userDao;
}
@Bean
public UserDaoInterface localUserDao(){
UserDaoInterface userDao = new UserDaoInterface(new LocalConnectionMaker());
return userDao;
}
}
spring을 테스트 하기 위해서는 추가해줘야 하는 설정이 있다. 이에 대한 내용들은 정리해둔 블로그에서 확인이 가능하다
정리 블로그 : https://velog.io/@qowl880/test
@ExtendWith(SpringExtension.class) // spring에서 테스트 하기 위한 확장자
@ContextConfiguration(classes = UserDaoFactory.class)
class UserDaoInterfaceTest {
@Autowired
ApplicationContext context; // Spring ApplicationContext를 사용하기 위해서는
// @ExtendWith 과 @ContextConfiguration를 추가해줘야 한다.
@Test
void addAndSelect() throws ClassNotFoundException, SQLException {
UserDaoInterface userDao = new UserDaoFactory().awsUserDao();
// awsUserDao()가 UserDaoInterface를 반환하기 때문에 다형성 가능
String id = "3";
userDao.add(new User(id,"Spring","123"));
User user = userDao.select(id);
Assertions.assertEquals("Spring",user.getName());
}
}
인터페이스
public interface ConnectionMaker { // makeConnection을 각 DB에 맞게 사용할 수 있도록 불러오기 위한 interface
Connection makeConnection() throws SQLException, ClassNotFoundException;
}
AWS 설정
public class AWSConnectionMaker implements ConnectionMaker{
@Override
public Connection makeConnection() throws SQLException, ClassNotFoundException {
Map<String, String> env = System.getenv(); // 환경변수를 사용하여
String dbHost = env.get("DB_HOST");
String dbUser = env.get("DB_USER");
String dbPassword = env.get("DB_PASSWORD");
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection(dbHost, dbUser, dbPassword);
return conn;
}
}
Local 설정
public class LocalConnectionMaker implements ConnectionMaker{
@Override
public Connection makeConnection() throws SQLException {
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/likelion-db","root","password");
return conn;
}
}
DAO
public class UserDaoInterface {
private ConnectionMaker connectionMaker; // interface의 makeConnection()를 가져옴
public UserDaoInterface(){ // 생성자를 통해 AWS DB의 makeConnection()을 오버라이딩하여 사용
this.connectionMaker = new AWSConnectionMaker();
}
public UserDaoInterface(ConnectionMaker connectionMaker){
this.connectionMaker = connectionMaker;
}
public void add(User user) throws ClassNotFoundException {
try{
// db 연결(호스트,이름,비밀번호)
Connection conn = connectionMaker.makeConnection(); // 설정들을 모아둔 메서드 호출
PreparedStatement ps = conn.prepareStatement("INSERT INTO users(id,name,password) VALUES(?,?,?)");
ps.setString(1,user.getId()); // mysql 테이블로 값 insert
ps.setString(2,user.getName());
ps.setString(3,user.getPassword());
ps.executeUpdate(); // ctrl + enter 즉, mysql에서 번개모양을 눌러 최신화 한다는 느낌
ps.close();
conn.close();
System.out.println("데이터가 insert 됬습니다.");
}catch (SQLException e){
throw new RuntimeException(e);
}
}
public User select(String id) throws SQLException, ClassNotFoundException {
try {
Connection conn = connectionMaker.makeConnection();
PreparedStatement ps = conn.prepareStatement("SELECT id,name,password FROM users WHERE id = ?");
ps.setString(1, id); // id는 get(String id)로 받은 id
ResultSet rs = ps.executeQuery(); // 쿼리문을 저장함 insert문과 달리 excuteQuery() 사용
// rs에는 쿼리 실행 결과가 담겨져 있다. (select * from users where id = 1;)
rs.next();
// User 생성자를 통해 쿼리문에 id값을 넣어 찾은 id, name,password 값을 저장한다.
User user = new User(rs.getString("id"), rs.getString("name"), rs.getString("password"));
rs.close();
ps.close();
conn.close();
return user;
}catch (SQLException e){
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws ClassNotFoundException, SQLException {
UserDaoInterface userDao = new UserDaoInterface();
userDao.add(new User("7","Ruru","1234qwer")); // user로 값을 받아 DTO에 저장한 후 mysql로 데이터 보냄
System.out.println(userDao.select("1"));
}
}
Factory(bean 폴더)
@Configuration
public class UserDaoFactory {
@Bean
public UserDaoInterface awsUserDao(){
AWSConnectionMaker awsConnectionMaker = new AWSConnectionMaker();
UserDaoInterface userDao = new UserDaoInterface(awsConnectionMaker);
return userDao;
}
@Bean
public UserDaoInterface localUserDao(){
UserDaoInterface userDao = new UserDaoInterface(new LocalConnectionMaker());
return userDao;
}
}