<!-- Root Context: defines shared resources visible to all other web components -->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
		<property name="url" value="jdbc:mysql://localhost:3306/springbasic?useUnicode=true&amp;characterEncoding=utf8"></property>
		<property name="username" value="asdf"></property>
		<property name="password" value="1234"></property>
	</bean>

먼저 root-context.xml 파일에 다음과 같은 코드를 추가하여 Bean을 생성함.

 

 

package com.fastcampus.ch3;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;
import java.sql.Connection;

public class DBConnectionTest2 {
    public static void main(String[] args) throws Exception {
        // root-context.xml 파일에 bean을 등록해놓아야 함.
        ApplicationContext ac = new GenericXmlApplicationContext("file:src/main/webapp/WEB-INF/spring/**/root-context.xml");
        DataSource ds = ac.getBean(DataSource.class);

        Connection conn = ds.getConnection(); // 데이터베이스의 연결을 얻는다.

        System.out.println("conn = " + conn);
//        assertTrue(conn!=null);
    }

root-context에 Bean을 생성했기 때문에 getBean 메소드로 객체를 얻어올 수 있다.

 

이렇게 해서 데이터베이스와 연결이 가능해진다.

 

 

 

 

JUnit이라는 TestFramework을 이용하면 Test를 자동화 할 수 있다. (TDD - Test Driven Development)

package com.fastcampus.ch3;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.sql.DataSource;
import java.sql.Connection;

import static org.junit.Assert.*;

@RunWith(SpringJUnit4ClassRunner.class) // ac를 자동으로 만들어줌
@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/**/root-context.xml"}) // 이 설정파일(root-context.xml)을 이용함
public class DBConnectionTest2Test {
    @Autowired
    DataSource ds;

    @Test
    public void main() throws Exception {
    	// @Autowired
//      ApplicationContext ac = new GenericXmlApplicationContext("file:src/main/webapp/WEB-INF/spring/**/root-context.xml");
//      DataSource ds = ac.getBean(DataSource.class);

        Connection conn = ds.getConnection(); // 데이터베이스의 연결을 얻는다.

        System.out.println("conn = " + conn);
        assertTrue(conn!=null); // 괄호 안의 조건식이 true면 테스트 성공, 아니면 실패
    }
}

Test할 메소드에 @Test 애너테이션을 붙임

테스트 메소드의 반환 타입은 void이어야 함.

 

Test 메소드의 마지막에 assert문이 꼭 필요하다.

 

assertTrue의 결과를 보면 테스트 성공, 실패를 확인할 수 있음.

 

 

 

 

[MySQL 설치 후 IntelliJ에 데이터베이스를 추가 후 진행]

 

package com.fastcampus.ch3;

import java.sql.*;

public class DBConnectionTest { // JDCB API로 DB에 접근
    public static void main(String[] args) throws Exception {
        // 스키마의 이름(springbasic)이 다른 경우 알맞게 변경해야 함
        String DB_URL = "jdbc:mysql://localhost:3306/springbasic?useUnicode=true&characterEncoding=utf8";

        // DB의 userid와 pwd를 알맞게 변경해야 함
        String DB_USER = "asdf"; // 본인 MySQL 아이디를 asdf 자리에 넣어야 함.
        String DB_PASSWORD = "1234"; // 본인 MySQL 비밀번호를 1234 자리에 넣어야 함.

        Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD); // 데이터베이스의 연결을 얻는다.
        Statement stmt  = conn.createStatement(); // Statement를 생성한다.

        String query = "SELECT now()"; // 시스템의 현재 날짜시간을 출력하는 쿼리(query)
        ResultSet rs = stmt.executeQuery(query); // query를 실행한 결과를 rs에 담는다.

        // 실행결과가 담긴 rs에서 한 줄씩 읽어서 출력
        while (rs.next()) {
            String curDate = rs.getString(1);  // 읽어온 행의 첫번째 컬럼의 값을 String으로 읽어서 curDate에 저장
            System.out.println(curDate);       // 2022-01-11 13:53:00.0
        }
    } // main()
}

(MySQL의 schema의 이름을 springbasic으로 설정하였음. schema의 이름이 달라지면 DB_URL 주소가 달라짐)

(DB_USER 값과 DB_PASSWORD 값은 본인의 아이디와 비밀번호를 넣어줘야 함)

 

이 프로그램은 MySQL에 저장된 데이터베이스(DB)를 연결하고, 연결이 잘 되었는지 확인하는 프로그램이다.

 

일일이 DB URL과 아이디, 비밀번호를 입력할 필요 없이, Bean으로 등록해놓으면 편리하게 사용할 수 있다.

 

(root-context.xml 파일에 Bean으로 등록해야 한다)

<?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 https://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
		<property name="url" value="jdbc:mysql://localhost:3306/springbasic?useUnicode=true&amp;characterEncoding=utf8"></property>
		<property name="username" value="asdf"></property>
		<property name="password" value="1234"></property>
	</bean>
</beans>

다음과 같이 <bean> 태그와 그 안에 <property> 태그를 이용하여 MySQL에 대한 정보를 등록해놓았다.

 

 

package com.fastcampus.ch3;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;
import java.sql.Connection;

public class DBConnectionTest2 {
    public static void main(String[] args) throws Exception {
        // root-context.xml 파일에 bean을 등록해놓아야 함.
        ApplicationContext ac = new GenericXmlApplicationContext("file:src/main/webapp/WEB-INF/spring/**/root-context.xml");
        DataSource ds = ac.getBean(DataSource.class);

        Connection conn = ds.getConnection(); // 데이터베이스의 연결을 얻는다.

        System.out.println("conn = " + conn);
//        assertTrue(conn!=null);
    }
}

그럼 다음과 같이 연결을 얻는 코드가 짧아진다.

 

 

 

package com.fastcampus.ch3;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Date;

import static org.junit.Assert.*;

@RunWith(SpringJUnit4ClassRunner.class) // ac를 자동으로 만들어줌
@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/**/root-context.xml"}) // 이 설정파일(root-context.xml)을 이용함
public class DBConnectionTest2Test {
    @Autowired
    DataSource ds;

    @Test
    public void insertUserTest() throws Exception {
        User user = new User("asdf2","1234","abc","aaa@aaa.com",new Date(), "fb", new Date());
        deleteAll();
        int rowCnt = insertUser(user);

        assertTrue(rowCnt==1);
    }

    @Test
    public void selectUserTest() throws Exception {
        deleteAll();
        User user = new User("asdf2","1234","abc","aaa@aaa.com",new Date(), "fb", new Date());
        int rowCnt = insertUser(user);
        User user2 = selectUser("asdf2");

        assertTrue(user.getId().equals("asdf2"));
    }
    @Test
    public void deleteUserTest() throws Exception {
        deleteAll();
        int rowCnt = deleteUser("asdf");

        assertTrue(rowCnt==0);

        User user = new User("asdf2","1234","abc","aaa@aaa.com", new Date(), "fb", new Date());
        rowCnt = insertUser(user);
        assertTrue(rowCnt==1);

        rowCnt = deleteUser(user.getId());
        assertTrue(rowCnt==1);

        assertTrue(selectUser(user.getId())==null);
    }

    @Test
    public void updateUserTest() throws Exception {
        deleteAll();
        User user = new User("asdf2","1234","abc","aaa@aaa.com", new Date(), "fb", new Date());
        int rowCnt = insertUser(user);
        assertTrue(rowCnt==1);

        User user2 = new User("asdf2","5678","def","bbb@bbb.com", new Date(), "kakao", new Date());
        rowCnt = updateUser(user2);
        assertTrue(rowCnt==1);

        assertTrue(selectUser("asdf2").getName().equals("def"));
    }

    // 매개변수로 받은 사용자 정보로 user_info 테이블을 update 하는 메소드
    public int updateUser(User user) throws Exception {
        Connection conn = ds.getConnection();

        String sql = "update user_info set pwd=?, name=?, email=?, birth=?, sns=?, reg_date=? where id=?";

        PreparedStatement pstat = conn.prepareStatement(sql);

        pstat.setString(1, user.getPwd());
        pstat.setString(2, user.getName());
        pstat.setString(3, user.getEmail());
        pstat.setDate(4, new java.sql.Date(user.getBirth().getTime()));
        pstat.setString(5, user.getSns());
        pstat.setTimestamp(6, new java.sql.Timestamp(user.getReg_date().getTime()));
        pstat.setString(7, user.getId());

        return pstat.executeUpdate();
    }

    // id에 해당하는 데이터를 user_info에서 삭제하는 메소드
    public int deleteUser(String id) throws Exception {
        Connection conn = ds.getConnection();

        String sql = "delete from user_info where id=?";

        PreparedStatement pstat = conn.prepareStatement(sql);
        pstat.setString(1, id);
//        int rowCnt = pstat.executeUpdate(); // insert, delete, update
//        return rowCnt;
        return pstat.executeUpdate();
    }

    // id에 해당하는 데이터를 user_info에서 받아와서, User객체에 저장해서 반환하는 메소드
    public User selectUser(String id) throws Exception {
        Connection conn = ds.getConnection();

        String sql = "select * from user_info where id=?";

        PreparedStatement pstat = conn.prepareStatement(sql); // SQL Injection공격, 성능형상
        pstat.setString(1, id);

        // ResultSet 이라는 타입의 테이블을 반환
        ResultSet rs = pstat.executeQuery(); // select문은 executeQuery()로 해야 함.

        if(rs.next()) {
            User user = new User();
            user.setId(rs.getString(1));
            user.setPwd(rs.getString(2));
            user.setName(rs.getString(3));
            user.setEmail(rs.getString(4));
            user.setBirth(new Date(rs.getDate(5).getTime()));
            user.setSns(rs.getString(6));
            user.setReg_date(new Date(rs.getTimestamp(7).getTime()));

            return user;
        }
        return null;
    }

    // user_info 테이블의 모든 데이터를 삭제하는 메소드
    private void deleteAll() throws Exception {
        Connection conn = ds.getConnection();

        String sql = "delete from user_info";

        PreparedStatement pstat = conn.prepareStatement(sql); // SQL Injection공격, 성능형상
        pstat.executeUpdate(); // insert, delete, update

    }

    // 사용자 정보를 user_info 테이블에 저장하는 메소드
    public int insertUser(User user) throws Exception {
        Connection conn = ds.getConnection();

//        insert into user_info (id, pwd, name, email, birth, sns, reg_date)
//        values ('asdf22','1234','smith','aaa@aaa.com', '2021-01-01', 'facebook', now());

        String sql = "insert into user_info values (?,?,?,?,?,?, now())";

        PreparedStatement pstat = conn.prepareStatement(sql); // SQL Injection공격, 성능형상
        pstat.setString(1, user.getId());
        pstat.setString(2, user.getPwd());
        pstat.setString(3, user.getName());
        pstat.setString(4, user.getEmail());
        pstat.setDate(5, new java.sql.Date(user.getBirth().getTime()));
        pstat.setString(6, user.getSns());

        int rowCnt = pstat.executeUpdate(); // insert, delete, update

        return rowCnt;
    }

    @Test
    public void main() throws Exception {
        // ac를 @RunWith가 자동으로 만들어줌
//      ApplicationContext ac = new GenericXmlApplicationContext("file:src/main/webapp/WEB-INF/spring/**/root-context.xml");
//      DataSource ds = ac.getBean(DataSource.class);

        Connection conn = ds.getConnection(); // 데이터베이스의 연결을 얻는다.

        System.out.println("conn = " + conn);
        assertTrue(conn!=null); // 괄호 안의 조건식이 true면 테스트 성공, 아니면 실패

    }
}

먼저 가장 아래의 main 메소드를 살펴보면, 데이터베이스의 연결을 얻는 코드가 훨씬 간결해진 것을 볼 수 있다.

 

그 이유는 아까 root-context.xml 파일에 Datasource의 정보를 Bean으로 등록해놓고, @Autowired 애너테이션을 붙여서 생성한 객체를 연결했기 때문이다.

 

메인 메소드를 제외한 나머지 메소드들은

데이터베이스의 연결을 얻어 객체의 정보를 DB에 저장하거나 정보를 선택, 수정, 삭제하는 기능을 가진 메소드들이다.

(직접 여러번 작성해봐야 익숙해지므로 반복 필요)

 

@Test 메소드의 결과는 assert문의 조건식이 true이면 성공이고, false면 실패이다.

 

rowCnt (= pstat.executeUpdate() ) 는 데이터베이스의 변화가 몇 줄을 변화시키느냐에 따라 반환값이 다른데 변화가 있으면 보통 1을 반환하고 변화가 없으면 0을 반환한다.

 

 

// ResultSet 이라는 타입의 테이블을 반환
ResultSet rs = pstat.executeQuery(); // select문은 executeQuery()로 해야 함.

select 문은 pstat.executeUpdate() 대신 executeQuery() 로 변화를 주고, 반환값을 ResultSet 타입으로 받는다.


출처 : 스프링의 정석 : 남궁성과 끝까지 간다

 

 

+ Recent posts