From 1f29099a4f82cbfc345a39e514bd0e451b60a9bb Mon Sep 17 00:00:00 2001 From: SCY Date: Fri, 4 Oct 2024 16:48:56 +0900 Subject: [PATCH 01/11] =?UTF-8?q?feat:=20UserDao=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/techcourse/dao/UserDao.java | 156 +++++++++++++++--- .../java/com/techcourse/dao/UserDaoTest.java | 10 +- 2 files changed, 142 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/techcourse/dao/UserDao.java b/app/src/main/java/com/techcourse/dao/UserDao.java index e22d84bb85..7aede1da37 100644 --- a/app/src/main/java/com/techcourse/dao/UserDao.java +++ b/app/src/main/java/com/techcourse/dao/UserDao.java @@ -1,16 +1,16 @@ package com.techcourse.dao; -import com.techcourse.domain.User; import com.interface21.jdbc.core.JdbcTemplate; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.sql.DataSource; +import com.techcourse.domain.User; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; import java.util.List; +import javax.sql.DataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class UserDao { @@ -49,23 +49,94 @@ public void insert(final User user) { if (pstmt != null) { pstmt.close(); } - } catch (SQLException ignored) {} + } catch (SQLException ignored) { + } try { if (conn != null) { conn.close(); } - } catch (SQLException ignored) {} + } catch (SQLException ignored) { + } } } public void update(final User user) { - // todo + final var sql = "update users set account = ?, password = ?, email = ? where id = ?"; + + Connection conn = null; + PreparedStatement pstmt = null; + try { + conn = dataSource.getConnection(); + pstmt = conn.prepareStatement(sql); + + log.debug("query : {}", sql); + + pstmt.setString(1, user.getAccount()); + pstmt.setString(2, user.getPassword()); + pstmt.setString(3, user.getEmail()); + pstmt.setLong(4, user.getId()); + pstmt.executeUpdate(); + } catch (SQLException e) { + log.error(e.getMessage(), e); + throw new RuntimeException(e); + } finally { + try { + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException ignored) { + } + + try { + if (conn != null) { + conn.close(); + } + } catch (SQLException ignored) { + } + } } public List findAll() { - // todo - return null; + final var sql = "select id, account, password, email from users"; + + Connection conn = null; + PreparedStatement pstmt = null; + try { + conn = dataSource.getConnection(); + pstmt = conn.prepareStatement(sql); + + log.debug("query : {}", sql); + + List result = new ArrayList<>(); + + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) { + result.add(new User( + rs.getLong("id"), + rs.getString("account"), + rs.getString("password"), + rs.getString("email"))); + } + return result; + } catch (SQLException e) { + log.error(e.getMessage(), e); + throw new RuntimeException(e); + } finally { + try { + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException ignored) { + } + + try { + if (conn != null) { + conn.close(); + } + } catch (SQLException ignored) { + } + } } public User findById(final Long id) { @@ -84,10 +155,10 @@ public User findById(final Long id) { if (rs.next()) { return new User( - rs.getLong(1), - rs.getString(2), - rs.getString(3), - rs.getString(4)); + rs.getLong("id"), + rs.getString("account"), + rs.getString("password"), + rs.getString("email")); } return null; } catch (SQLException e) { @@ -98,24 +169,71 @@ public User findById(final Long id) { if (rs != null) { rs.close(); } - } catch (SQLException ignored) {} + } catch (SQLException ignored) { + } try { if (pstmt != null) { pstmt.close(); } - } catch (SQLException ignored) {} + } catch (SQLException ignored) { + } try { if (conn != null) { conn.close(); } - } catch (SQLException ignored) {} + } catch (SQLException ignored) { + } } } public User findByAccount(final String account) { - // todo - return null; + final var sql = "select id, account, password, email from users where account = ?"; + + Connection conn = null; + PreparedStatement pstmt = null; + ResultSet rs = null; + try { + conn = dataSource.getConnection(); + pstmt = conn.prepareStatement(sql); + pstmt.setString(1, account); + rs = pstmt.executeQuery(); + + log.debug("query : {}", sql); + + if (rs.next()) { + return new User( + rs.getLong("id"), + rs.getString("account"), + rs.getString("password"), + rs.getString("email")); + } + return null; + } catch (SQLException e) { + log.error(e.getMessage(), e); + throw new RuntimeException(e); + } finally { + try { + if (rs != null) { + rs.close(); + } + } catch (SQLException ignored) { + } + + try { + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException ignored) { + } + + try { + if (conn != null) { + conn.close(); + } + } catch (SQLException ignored) { + } + } } } diff --git a/app/src/test/java/com/techcourse/dao/UserDaoTest.java b/app/src/test/java/com/techcourse/dao/UserDaoTest.java index 773d7faf82..bbeb13f5fa 100644 --- a/app/src/test/java/com/techcourse/dao/UserDaoTest.java +++ b/app/src/test/java/com/techcourse/dao/UserDaoTest.java @@ -17,7 +17,7 @@ void setup() { DatabasePopulatorUtils.execute(DataSourceConfig.getInstance()); userDao = new UserDao(DataSourceConfig.getInstance()); - final var user = new User("gugu", "password", "hkkang@woowahan.com"); + final var user = new User("ever", "password", "ever@woowahan.com"); userDao.insert(user); } @@ -32,12 +32,12 @@ void findAll() { void findById() { final var user = userDao.findById(1L); - assertThat(user.getAccount()).isEqualTo("gugu"); + assertThat(user.getAccount()).isEqualTo("ever"); } @Test void findByAccount() { - final var account = "gugu"; + final var account = "ever"; final var user = userDao.findByAccount(account); assertThat(user.getAccount()).isEqualTo(account); @@ -45,8 +45,8 @@ void findByAccount() { @Test void insert() { - final var account = "insert-gugu"; - final var user = new User(account, "password", "hkkang@woowahan.com"); + final var account = "insert-ever"; + final var user = new User(account, "password", "ever@woowahan.com"); userDao.insert(user); final var actual = userDao.findById(2L); From de251f8b0730aef0d46b68d47af102d03fd7ad13 Mon Sep 17 00:00:00 2001 From: SCY Date: Fri, 4 Oct 2024 22:45:01 +0900 Subject: [PATCH 02/11] =?UTF-8?q?refactor:=20JdbcTemplate=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EB=A1=9C=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=EB=B2=A0=EC=9D=B4=EC=8A=A4=20=EA=B4=80=EB=A0=A8=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/techcourse/dao/UserDao.java | 207 ++---------------- .../main/java/com/techcourse/domain/User.java | 5 + .../java/com/techcourse/dao/UserDaoTest.java | 7 +- .../java/com/interface21/ConsumerWrapper.java | 21 ++ .../com/interface21/ThrowingConsumer.java | 6 + .../interface21/jdbc/core/JdbcTemplate.java | 159 +++++++++++++- 6 files changed, 206 insertions(+), 199 deletions(-) create mode 100644 jdbc/src/main/java/com/interface21/ConsumerWrapper.java create mode 100644 jdbc/src/main/java/com/interface21/ThrowingConsumer.java diff --git a/app/src/main/java/com/techcourse/dao/UserDao.java b/app/src/main/java/com/techcourse/dao/UserDao.java index 7aede1da37..1f6a96f846 100644 --- a/app/src/main/java/com/techcourse/dao/UserDao.java +++ b/app/src/main/java/com/techcourse/dao/UserDao.java @@ -1,14 +1,9 @@ package com.techcourse.dao; +import com.interface21.ConsumerWrapper; import com.interface21.jdbc.core.JdbcTemplate; import com.techcourse.domain.User; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; import java.util.List; -import javax.sql.DataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,224 +11,48 @@ public class UserDao { private static final Logger log = LoggerFactory.getLogger(UserDao.class); - private final DataSource dataSource; - - public UserDao(final DataSource dataSource) { - this.dataSource = dataSource; - } + private JdbcTemplate jdbcTemplate; public UserDao(final JdbcTemplate jdbcTemplate) { - this.dataSource = null; + this.jdbcTemplate = jdbcTemplate; } public void insert(final User user) { final var sql = "insert into users (account, password, email) values (?, ?, ?)"; - - Connection conn = null; - PreparedStatement pstmt = null; - try { - conn = dataSource.getConnection(); - pstmt = conn.prepareStatement(sql); - - log.debug("query : {}", sql); - + jdbcTemplate.executeUpdate(sql, ConsumerWrapper.accept(pstmt -> { pstmt.setString(1, user.getAccount()); pstmt.setString(2, user.getPassword()); pstmt.setString(3, user.getEmail()); - pstmt.executeUpdate(); - } catch (SQLException e) { - log.error(e.getMessage(), e); - throw new RuntimeException(e); - } finally { - try { - if (pstmt != null) { - pstmt.close(); - } - } catch (SQLException ignored) { - } - - try { - if (conn != null) { - conn.close(); - } - } catch (SQLException ignored) { - } - } + })); } public void update(final User user) { final var sql = "update users set account = ?, password = ?, email = ? where id = ?"; - - Connection conn = null; - PreparedStatement pstmt = null; - try { - conn = dataSource.getConnection(); - pstmt = conn.prepareStatement(sql); - - log.debug("query : {}", sql); - + jdbcTemplate.executeUpdate(sql, ConsumerWrapper.accept(pstmt -> { pstmt.setString(1, user.getAccount()); pstmt.setString(2, user.getPassword()); pstmt.setString(3, user.getEmail()); pstmt.setLong(4, user.getId()); - pstmt.executeUpdate(); - } catch (SQLException e) { - log.error(e.getMessage(), e); - throw new RuntimeException(e); - } finally { - try { - if (pstmt != null) { - pstmt.close(); - } - } catch (SQLException ignored) { - } - - try { - if (conn != null) { - conn.close(); - } - } catch (SQLException ignored) { - } - } + })); } public List findAll() { final var sql = "select id, account, password, email from users"; - - Connection conn = null; - PreparedStatement pstmt = null; - try { - conn = dataSource.getConnection(); - pstmt = conn.prepareStatement(sql); - - log.debug("query : {}", sql); - - List result = new ArrayList<>(); - - ResultSet rs = pstmt.executeQuery(); - while (rs.next()) { - result.add(new User( - rs.getLong("id"), - rs.getString("account"), - rs.getString("password"), - rs.getString("email"))); - } - return result; - } catch (SQLException e) { - log.error(e.getMessage(), e); - throw new RuntimeException(e); - } finally { - try { - if (pstmt != null) { - pstmt.close(); - } - } catch (SQLException ignored) { - } - - try { - if (conn != null) { - conn.close(); - } - } catch (SQLException ignored) { - } - } + return jdbcTemplate.executeQueryReturnList(sql, pstmt -> { + }, User.class); } public User findById(final Long id) { final var sql = "select id, account, password, email from users where id = ?"; - - Connection conn = null; - PreparedStatement pstmt = null; - ResultSet rs = null; - try { - conn = dataSource.getConnection(); - pstmt = conn.prepareStatement(sql); + return jdbcTemplate.executeQuery(sql, ConsumerWrapper.accept(pstmt -> { pstmt.setLong(1, id); - rs = pstmt.executeQuery(); - - log.debug("query : {}", sql); - - if (rs.next()) { - return new User( - rs.getLong("id"), - rs.getString("account"), - rs.getString("password"), - rs.getString("email")); - } - return null; - } catch (SQLException e) { - log.error(e.getMessage(), e); - throw new RuntimeException(e); - } finally { - try { - if (rs != null) { - rs.close(); - } - } catch (SQLException ignored) { - } - - try { - if (pstmt != null) { - pstmt.close(); - } - } catch (SQLException ignored) { - } - - try { - if (conn != null) { - conn.close(); - } - } catch (SQLException ignored) { - } - } + }), User.class); } public User findByAccount(final String account) { final var sql = "select id, account, password, email from users where account = ?"; - - Connection conn = null; - PreparedStatement pstmt = null; - ResultSet rs = null; - try { - conn = dataSource.getConnection(); - pstmt = conn.prepareStatement(sql); + return jdbcTemplate.executeQuery(sql, ConsumerWrapper.accept(pstmt -> { pstmt.setString(1, account); - rs = pstmt.executeQuery(); - - log.debug("query : {}", sql); - - if (rs.next()) { - return new User( - rs.getLong("id"), - rs.getString("account"), - rs.getString("password"), - rs.getString("email")); - } - return null; - } catch (SQLException e) { - log.error(e.getMessage(), e); - throw new RuntimeException(e); - } finally { - try { - if (rs != null) { - rs.close(); - } - } catch (SQLException ignored) { - } - - try { - if (pstmt != null) { - pstmt.close(); - } - } catch (SQLException ignored) { - } - - try { - if (conn != null) { - conn.close(); - } - } catch (SQLException ignored) { - } - } + }), User.class); } } diff --git a/app/src/main/java/com/techcourse/domain/User.java b/app/src/main/java/com/techcourse/domain/User.java index 986721038b..421c7ffc97 100644 --- a/app/src/main/java/com/techcourse/domain/User.java +++ b/app/src/main/java/com/techcourse/domain/User.java @@ -20,6 +20,11 @@ public User(String account, String password, String email) { this.email = email; } + private User() { + this.account = null; + this.email = null; + } + public boolean checkPassword(String password) { return this.password.equals(password); } diff --git a/app/src/test/java/com/techcourse/dao/UserDaoTest.java b/app/src/test/java/com/techcourse/dao/UserDaoTest.java index bbeb13f5fa..b510f9336f 100644 --- a/app/src/test/java/com/techcourse/dao/UserDaoTest.java +++ b/app/src/test/java/com/techcourse/dao/UserDaoTest.java @@ -1,13 +1,14 @@ package com.techcourse.dao; +import static org.assertj.core.api.Assertions.assertThat; + +import com.interface21.jdbc.core.JdbcTemplate; import com.techcourse.config.DataSourceConfig; import com.techcourse.domain.User; import com.techcourse.support.jdbc.init.DatabasePopulatorUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; - class UserDaoTest { private UserDao userDao; @@ -16,7 +17,7 @@ class UserDaoTest { void setup() { DatabasePopulatorUtils.execute(DataSourceConfig.getInstance()); - userDao = new UserDao(DataSourceConfig.getInstance()); + userDao = new UserDao(new JdbcTemplate(DataSourceConfig.getInstance())); final var user = new User("ever", "password", "ever@woowahan.com"); userDao.insert(user); } diff --git a/jdbc/src/main/java/com/interface21/ConsumerWrapper.java b/jdbc/src/main/java/com/interface21/ConsumerWrapper.java new file mode 100644 index 0000000000..8b3cac5b06 --- /dev/null +++ b/jdbc/src/main/java/com/interface21/ConsumerWrapper.java @@ -0,0 +1,21 @@ +package com.interface21; + +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ConsumerWrapper { + + private static final Logger log = LoggerFactory.getLogger(ConsumerWrapper.class); + + public static Consumer accept(ThrowingConsumer consumer) { + return i -> { + try { + consumer.accept(i); + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new RuntimeException(e); + } + }; + } +} diff --git a/jdbc/src/main/java/com/interface21/ThrowingConsumer.java b/jdbc/src/main/java/com/interface21/ThrowingConsumer.java new file mode 100644 index 0000000000..d372422848 --- /dev/null +++ b/jdbc/src/main/java/com/interface21/ThrowingConsumer.java @@ -0,0 +1,6 @@ +package com.interface21; + +@FunctionalInterface +public interface ThrowingConsumer { + void accept(T t) throws Exception; +} diff --git a/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java b/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java index 4e50a5153e..77892e5a33 100644 --- a/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java +++ b/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java @@ -1,10 +1,18 @@ package com.interface21.jdbc.core; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import javax.sql.DataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.sql.DataSource; - public class JdbcTemplate { private static final Logger log = LoggerFactory.getLogger(JdbcTemplate.class); @@ -14,4 +22,151 @@ public class JdbcTemplate { public JdbcTemplate(final DataSource dataSource) { this.dataSource = dataSource; } + + public void executeUpdate(String sql, Consumer beforeExecution) { + Connection conn = null; + PreparedStatement pstmt = null; + try { + conn = dataSource.getConnection(); + pstmt = conn.prepareStatement(sql); + + log.debug("query : {}", sql); + + beforeExecution.accept(pstmt); + pstmt.executeUpdate(); + + } catch (SQLException e) { + log.error(e.getMessage(), e); + throw new RuntimeException(e); + } finally { + try { + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException ignored) { + } + + try { + if (conn != null) { + conn.close(); + } + } catch (SQLException ignored) { + } + } + } + + public T executeQuery(String sql, Consumer beforeExecution, Class dataType) { + Connection conn = null; + PreparedStatement pstmt = null; + ResultSet rs = null; + try { + conn = dataSource.getConnection(); + pstmt = conn.prepareStatement(sql); + + log.debug("query : {}", sql); + + beforeExecution.accept(pstmt); + rs = pstmt.executeQuery(); + + if (!rs.next()) { + return null; + } + return createData(dataType, rs); + + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new RuntimeException(e); + } finally { + try { + if (rs != null) { + rs.close(); + } + } catch (SQLException ignored) { + } + + try { + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException ignored) { + } + + try { + if (conn != null) { + conn.close(); + } + } catch (SQLException ignored) { + } + } + } + + public List executeQueryReturnList(String sql, Consumer beforeExecution, + Class dataType) { + Connection conn = null; + PreparedStatement pstmt = null; + ResultSet rs = null; + try { + conn = dataSource.getConnection(); + pstmt = conn.prepareStatement(sql); + + log.debug("query : {}", sql); + + beforeExecution.accept(pstmt); + rs = pstmt.executeQuery(); + + if (!rs.next()) { + return null; + } + return createDatas(dataType, rs); + + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new RuntimeException(e); + } finally { + try { + if (rs != null) { + rs.close(); + } + } catch (SQLException ignored) { + } + + try { + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException ignored) { + } + + try { + if (conn != null) { + conn.close(); + } + } catch (SQLException ignored) { + } + } + } + + private List createDatas(Class dataType, ResultSet rs) throws Exception { + List result = new ArrayList<>(); + while (rs.next()) { + result.add(createData(dataType, rs)); + } + return result; + } + + private T createData(Class dataType, ResultSet rs) throws Exception { + Constructor constructor = dataType.getDeclaredConstructor(); + constructor.setAccessible(true); + T instance = constructor.newInstance(); + constructor.setAccessible(false); + + Field[] fields = dataType.getDeclaredFields(); + for (Field field : fields) { + field.setAccessible(true); + Object value = rs.getObject(field.getName(), field.getType()); + field.set(instance, value); + field.setAccessible(false); + } + return instance; + } } From 44d01109731638bb319c20b1326f7befb1e40133 Mon Sep 17 00:00:00 2001 From: SCY Date: Fri, 4 Oct 2024 22:48:38 +0900 Subject: [PATCH 03/11] =?UTF-8?q?refactor:=20=ED=8C=8C=EB=9D=BC=EB=AF=B8?= =?UTF-8?q?=ED=84=B0=20=EC=A3=BC=EC=9E=85=20=EC=B1=85=EC=9E=84=20JdbcTempl?= =?UTF-8?q?ate=EC=97=90=20=EC=9C=84=EC=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/techcourse/dao/UserDao.java | 25 ++++--------------- .../java/com/interface21/ConsumerWrapper.java | 21 ---------------- .../com/interface21/ThrowingConsumer.java | 6 ----- .../interface21/jdbc/core/JdbcTemplate.java | 20 +++++++++------ 4 files changed, 17 insertions(+), 55 deletions(-) delete mode 100644 jdbc/src/main/java/com/interface21/ConsumerWrapper.java delete mode 100644 jdbc/src/main/java/com/interface21/ThrowingConsumer.java diff --git a/app/src/main/java/com/techcourse/dao/UserDao.java b/app/src/main/java/com/techcourse/dao/UserDao.java index 1f6a96f846..28603aca99 100644 --- a/app/src/main/java/com/techcourse/dao/UserDao.java +++ b/app/src/main/java/com/techcourse/dao/UserDao.java @@ -1,6 +1,5 @@ package com.techcourse.dao; -import com.interface21.ConsumerWrapper; import com.interface21.jdbc.core.JdbcTemplate; import com.techcourse.domain.User; import java.util.List; @@ -19,40 +18,26 @@ public UserDao(final JdbcTemplate jdbcTemplate) { public void insert(final User user) { final var sql = "insert into users (account, password, email) values (?, ?, ?)"; - jdbcTemplate.executeUpdate(sql, ConsumerWrapper.accept(pstmt -> { - pstmt.setString(1, user.getAccount()); - pstmt.setString(2, user.getPassword()); - pstmt.setString(3, user.getEmail()); - })); + jdbcTemplate.executeUpdate(sql, user.getAccount(), user.getPassword(), user.getEmail()); } public void update(final User user) { final var sql = "update users set account = ?, password = ?, email = ? where id = ?"; - jdbcTemplate.executeUpdate(sql, ConsumerWrapper.accept(pstmt -> { - pstmt.setString(1, user.getAccount()); - pstmt.setString(2, user.getPassword()); - pstmt.setString(3, user.getEmail()); - pstmt.setLong(4, user.getId()); - })); + jdbcTemplate.executeUpdate(sql, user.getAccount(), user.getPassword(), user.getEmail(), user.getId()); } public List findAll() { final var sql = "select id, account, password, email from users"; - return jdbcTemplate.executeQueryReturnList(sql, pstmt -> { - }, User.class); + return jdbcTemplate.executeQueryReturnList(sql, User.class); } public User findById(final Long id) { final var sql = "select id, account, password, email from users where id = ?"; - return jdbcTemplate.executeQuery(sql, ConsumerWrapper.accept(pstmt -> { - pstmt.setLong(1, id); - }), User.class); + return jdbcTemplate.executeQuery(sql, User.class, id); } public User findByAccount(final String account) { final var sql = "select id, account, password, email from users where account = ?"; - return jdbcTemplate.executeQuery(sql, ConsumerWrapper.accept(pstmt -> { - pstmt.setString(1, account); - }), User.class); + return jdbcTemplate.executeQuery(sql, User.class, account); } } diff --git a/jdbc/src/main/java/com/interface21/ConsumerWrapper.java b/jdbc/src/main/java/com/interface21/ConsumerWrapper.java deleted file mode 100644 index 8b3cac5b06..0000000000 --- a/jdbc/src/main/java/com/interface21/ConsumerWrapper.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.interface21; - -import java.util.function.Consumer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ConsumerWrapper { - - private static final Logger log = LoggerFactory.getLogger(ConsumerWrapper.class); - - public static Consumer accept(ThrowingConsumer consumer) { - return i -> { - try { - consumer.accept(i); - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new RuntimeException(e); - } - }; - } -} diff --git a/jdbc/src/main/java/com/interface21/ThrowingConsumer.java b/jdbc/src/main/java/com/interface21/ThrowingConsumer.java deleted file mode 100644 index d372422848..0000000000 --- a/jdbc/src/main/java/com/interface21/ThrowingConsumer.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.interface21; - -@FunctionalInterface -public interface ThrowingConsumer { - void accept(T t) throws Exception; -} diff --git a/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java b/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java index 77892e5a33..42983800a2 100644 --- a/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java +++ b/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java @@ -8,7 +8,6 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; -import java.util.function.Consumer; import javax.sql.DataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,7 +22,7 @@ public JdbcTemplate(final DataSource dataSource) { this.dataSource = dataSource; } - public void executeUpdate(String sql, Consumer beforeExecution) { + public void executeUpdate(String sql, Object... parameters) { Connection conn = null; PreparedStatement pstmt = null; try { @@ -32,7 +31,7 @@ public void executeUpdate(String sql, Consumer beforeExecutio log.debug("query : {}", sql); - beforeExecution.accept(pstmt); + setParameter(pstmt, parameters); pstmt.executeUpdate(); } catch (SQLException e) { @@ -55,7 +54,7 @@ public void executeUpdate(String sql, Consumer beforeExecutio } } - public T executeQuery(String sql, Consumer beforeExecution, Class dataType) { + public T executeQuery(String sql, Class dataType, Object... parameters) { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; @@ -65,7 +64,7 @@ public T executeQuery(String sql, Consumer beforeExecutio log.debug("query : {}", sql); - beforeExecution.accept(pstmt); + setParameter(pstmt, parameters); rs = pstmt.executeQuery(); if (!rs.next()) { @@ -100,8 +99,7 @@ public T executeQuery(String sql, Consumer beforeExecutio } } - public List executeQueryReturnList(String sql, Consumer beforeExecution, - Class dataType) { + public List executeQueryReturnList(String sql, Class dataType, Object... parameters) { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; @@ -111,7 +109,7 @@ public List executeQueryReturnList(String sql, Consumer List executeQueryReturnList(String sql, Consumer List createDatas(Class dataType, ResultSet rs) throws Exception { List result = new ArrayList<>(); while (rs.next()) { From f0be9b25ea9e56e7e7b5a87472726bcc4ba65f04 Mon Sep 17 00:00:00 2001 From: SCY Date: Sun, 6 Oct 2024 16:21:05 +0900 Subject: [PATCH 04/11] =?UTF-8?q?test:=20JdbcTemplate=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jdbc/core/JdbcTemplateTest.java | 89 +++++++++++++++++++ .../interface21/jdbc/support/TestUser.java | 24 +++++ 2 files changed, 113 insertions(+) create mode 100644 jdbc/src/test/java/com/interface21/jdbc/support/TestUser.java diff --git a/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java b/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java index daf6567e8f..10aff4dbed 100644 --- a/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java +++ b/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java @@ -1,5 +1,94 @@ package com.interface21.jdbc.core; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.interface21.jdbc.support.TestUser; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import javax.sql.DataSource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + class JdbcTemplateTest { + ResultSet rs; + JdbcTemplate jdbcTemplate; + + @BeforeEach + void setUp() throws SQLException { + DataSource dataSource = mock(DataSource.class); + Connection conn = mock(Connection.class); + PreparedStatement pstmt = mock(PreparedStatement.class); + rs = mock(ResultSet.class); + + when(dataSource.getConnection()).thenReturn(conn); + when(conn.prepareStatement(anyString())).thenReturn(pstmt); + when(pstmt.executeQuery()).thenReturn(rs); + + jdbcTemplate = new JdbcTemplate(dataSource); + } + + @DisplayName("삽입 쿼리를 실행하면 삽입된 데이터를 조회할 수 있다.") + @Test + void executeUpdate() throws SQLException { + // given + when(rs.next()).thenReturn(true); + when(rs.getObject("id", Long.class)).thenReturn(1L); + when(rs.getObject("account", String.class)).thenReturn("ever"); + + // when + String insertSql = "insert into users (account) values (?)"; + jdbcTemplate.executeUpdate(insertSql, "ever"); + + // then + String selectSql = "select id, account from users where id = ?"; + TestUser user = jdbcTemplate.executeQuery(selectSql, TestUser.class, 1); + assertThat(user.getId()).isEqualTo(1); + assertThat(user.getAccount()).isEqualTo("ever"); + } + + @DisplayName("단건 조회 쿼리를 실행하면 해당 데이터를 조회할 수 있다.") + @Test + void executeQuery() throws SQLException { + // given + when(rs.next()).thenReturn(true); + when(rs.getObject("id", Long.class)).thenReturn(1L); + when(rs.getObject("account", String.class)).thenReturn("ever"); + + // when + String selectSql = "select id, account from users where id = ?"; + TestUser user = jdbcTemplate.executeQuery(selectSql, TestUser.class, 1); + + // then + assertThat(user.getId()).isEqualTo(1); + assertThat(user.getAccount()).isEqualTo("ever"); + } + + @DisplayName("여러건 조회 쿼리를 실행하면 해당 데이터 목록을 조회할 수 있다.") + @Test + void executeQueryReturnList() throws SQLException { + // given + String insertSql = "insert into users (account) values (?)"; + jdbcTemplate.executeUpdate(insertSql, "ever1"); + jdbcTemplate.executeUpdate(insertSql, "ever2"); + + when(rs.next()).thenReturn(true) + .thenReturn(true) + .thenReturn(true) + .thenReturn(false); + + // when + String selectSql = "select id, account from users"; + List testUsers = jdbcTemplate.executeQueryReturnList(selectSql, TestUser.class); + + // then + assertThat(testUsers).hasSize(2); + } } diff --git a/jdbc/src/test/java/com/interface21/jdbc/support/TestUser.java b/jdbc/src/test/java/com/interface21/jdbc/support/TestUser.java new file mode 100644 index 0000000000..caeb12b465 --- /dev/null +++ b/jdbc/src/test/java/com/interface21/jdbc/support/TestUser.java @@ -0,0 +1,24 @@ +package com.interface21.jdbc.support; + +public class TestUser { + + private final Long id; + private final String account; + + public TestUser(Long id, String account) { + this.id = id; + this.account = account; + } + + private TestUser() { + this(null, null); + } + + public Long getId() { + return id; + } + + public String getAccount() { + return account; + } +} From 3a5f685d3b1b787d9503f7640e0506c4633ca9ef Mon Sep 17 00:00:00 2001 From: SCY Date: Sun, 6 Oct 2024 16:21:26 +0900 Subject: [PATCH 05/11] =?UTF-8?q?refactor:=20UserDao=20=EB=82=B4=20JdbcTem?= =?UTF-8?q?plate=20=ED=95=84=EB=93=9C=20=EB=B6=88=EB=B3=80=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/techcourse/dao/UserDao.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/techcourse/dao/UserDao.java b/app/src/main/java/com/techcourse/dao/UserDao.java index 28603aca99..eb7eeb1215 100644 --- a/app/src/main/java/com/techcourse/dao/UserDao.java +++ b/app/src/main/java/com/techcourse/dao/UserDao.java @@ -10,7 +10,7 @@ public class UserDao { private static final Logger log = LoggerFactory.getLogger(UserDao.class); - private JdbcTemplate jdbcTemplate; + private final JdbcTemplate jdbcTemplate; public UserDao(final JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; From 9058a611aff30a446a0e6b412b81e58dd3b143af Mon Sep 17 00:00:00 2001 From: SCY Date: Sun, 6 Oct 2024 16:27:39 +0900 Subject: [PATCH 06/11] =?UTF-8?q?refactor:=20JdbcTemplate=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=BF=BC=EB=A6=AC=20=EC=8B=A4=ED=96=89=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/techcourse/dao/UserDao.java | 6 +++--- .../main/java/com/interface21/jdbc/core/JdbcTemplate.java | 4 ++-- .../java/com/interface21/jdbc/core/JdbcTemplateTest.java | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/techcourse/dao/UserDao.java b/app/src/main/java/com/techcourse/dao/UserDao.java index eb7eeb1215..54682fbc9f 100644 --- a/app/src/main/java/com/techcourse/dao/UserDao.java +++ b/app/src/main/java/com/techcourse/dao/UserDao.java @@ -28,16 +28,16 @@ public void update(final User user) { public List findAll() { final var sql = "select id, account, password, email from users"; - return jdbcTemplate.executeQueryReturnList(sql, User.class); + return jdbcTemplate.executeQuery(sql, User.class); } public User findById(final Long id) { final var sql = "select id, account, password, email from users where id = ?"; - return jdbcTemplate.executeQuery(sql, User.class, id); + return jdbcTemplate.executeQueryForObject(sql, User.class, id); } public User findByAccount(final String account) { final var sql = "select id, account, password, email from users where account = ?"; - return jdbcTemplate.executeQuery(sql, User.class, account); + return jdbcTemplate.executeQueryForObject(sql, User.class, account); } } diff --git a/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java b/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java index 42983800a2..ce7700e4d0 100644 --- a/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java +++ b/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java @@ -54,7 +54,7 @@ public void executeUpdate(String sql, Object... parameters) { } } - public T executeQuery(String sql, Class dataType, Object... parameters) { + public T executeQueryForObject(String sql, Class dataType, Object... parameters) { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; @@ -99,7 +99,7 @@ public T executeQuery(String sql, Class dataType, Object... parameters) { } } - public List executeQueryReturnList(String sql, Class dataType, Object... parameters) { + public List executeQuery(String sql, Class dataType, Object... parameters) { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; diff --git a/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java b/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java index 10aff4dbed..89eeb30d1f 100644 --- a/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java +++ b/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java @@ -49,7 +49,7 @@ void executeUpdate() throws SQLException { // then String selectSql = "select id, account from users where id = ?"; - TestUser user = jdbcTemplate.executeQuery(selectSql, TestUser.class, 1); + TestUser user = jdbcTemplate.executeQueryForObject(selectSql, TestUser.class, 1); assertThat(user.getId()).isEqualTo(1); assertThat(user.getAccount()).isEqualTo("ever"); } @@ -64,7 +64,7 @@ void executeQuery() throws SQLException { // when String selectSql = "select id, account from users where id = ?"; - TestUser user = jdbcTemplate.executeQuery(selectSql, TestUser.class, 1); + TestUser user = jdbcTemplate.executeQueryForObject(selectSql, TestUser.class, 1); // then assertThat(user.getId()).isEqualTo(1); @@ -86,7 +86,7 @@ void executeQueryReturnList() throws SQLException { // when String selectSql = "select id, account from users"; - List testUsers = jdbcTemplate.executeQueryReturnList(selectSql, TestUser.class); + List testUsers = jdbcTemplate.executeQuery(selectSql, TestUser.class); // then assertThat(testUsers).hasSize(2); From ec8ae86e7eab109712bacc1d5f57069df6f079d7 Mon Sep 17 00:00:00 2001 From: SCY Date: Sun, 6 Oct 2024 16:40:35 +0900 Subject: [PATCH 07/11] =?UTF-8?q?refactor:=20=EC=9D=B8=EC=8A=A4=ED=84=B4?= =?UTF-8?q?=EC=8A=A4=20=EC=83=9D=EC=84=B1=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interface21/jdbc/core/JdbcTemplate.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java b/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java index ce7700e4d0..037ecf89b0 100644 --- a/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java +++ b/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java @@ -54,7 +54,7 @@ public void executeUpdate(String sql, Object... parameters) { } } - public T executeQueryForObject(String sql, Class dataType, Object... parameters) { + public T executeQueryForObject(String sql, Class clazz, Object... parameters) { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; @@ -70,7 +70,7 @@ public T executeQueryForObject(String sql, Class dataType, Object... para if (!rs.next()) { return null; } - return createData(dataType, rs); + return createInstance(clazz, rs); } catch (Exception e) { log.error(e.getMessage(), e); @@ -99,7 +99,7 @@ public T executeQueryForObject(String sql, Class dataType, Object... para } } - public List executeQuery(String sql, Class dataType, Object... parameters) { + public List executeQuery(String sql, Class clazz, Object... parameters) { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; @@ -115,7 +115,7 @@ public List executeQuery(String sql, Class dataType, Object... paramet if (!rs.next()) { return null; } - return createDatas(dataType, rs); + return createInstances(clazz, rs); } catch (Exception e) { log.error(e.getMessage(), e); @@ -150,21 +150,21 @@ private void setParameter(PreparedStatement pstmt, Object[] parameters) throws S } } - private List createDatas(Class dataType, ResultSet rs) throws Exception { + private List createInstances(Class clazz, ResultSet rs) throws Exception { List result = new ArrayList<>(); while (rs.next()) { - result.add(createData(dataType, rs)); + result.add(createInstance(clazz, rs)); } return result; } - private T createData(Class dataType, ResultSet rs) throws Exception { - Constructor constructor = dataType.getDeclaredConstructor(); + private T createInstance(Class clazz, ResultSet rs) throws Exception { + Constructor constructor = clazz.getDeclaredConstructor(); constructor.setAccessible(true); T instance = constructor.newInstance(); constructor.setAccessible(false); - Field[] fields = dataType.getDeclaredFields(); + Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); Object value = rs.getObject(field.getName(), field.getType()); From 0ac8a054bbf7fec00c65b95ac610c95ab49b2fc4 Mon Sep 17 00:00:00 2001 From: SCY Date: Sun, 6 Oct 2024 18:07:14 +0900 Subject: [PATCH 08/11] =?UTF-8?q?refactor:=20RowMapper=EB=A5=BC=20?= =?UTF-8?q?=ED=86=B5=ED=95=B4=20=EC=9D=B8=EC=8A=A4=ED=84=B4=EC=8A=A4=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/techcourse/dao/UserDao.java | 13 +++++-- .../interface21/jdbc/core/JdbcTemplate.java | 39 +++++-------------- .../com/interface21/jdbc/core/RowMapper.java | 9 +++++ .../jdbc/core/JdbcTemplateTest.java | 22 ++++++----- 4 files changed, 41 insertions(+), 42 deletions(-) create mode 100644 jdbc/src/main/java/com/interface21/jdbc/core/RowMapper.java diff --git a/app/src/main/java/com/techcourse/dao/UserDao.java b/app/src/main/java/com/techcourse/dao/UserDao.java index 54682fbc9f..fa8c61665a 100644 --- a/app/src/main/java/com/techcourse/dao/UserDao.java +++ b/app/src/main/java/com/techcourse/dao/UserDao.java @@ -1,6 +1,7 @@ package com.techcourse.dao; import com.interface21.jdbc.core.JdbcTemplate; +import com.interface21.jdbc.core.RowMapper; import com.techcourse.domain.User; import java.util.List; import org.slf4j.Logger; @@ -10,6 +11,12 @@ public class UserDao { private static final Logger log = LoggerFactory.getLogger(UserDao.class); + private static final RowMapper USER_ROW_MAPPER = (rs) -> new User( + rs.getLong("id"), + rs.getString("account"), + rs.getString("password"), + rs.getString("email")); + private final JdbcTemplate jdbcTemplate; public UserDao(final JdbcTemplate jdbcTemplate) { @@ -28,16 +35,16 @@ public void update(final User user) { public List findAll() { final var sql = "select id, account, password, email from users"; - return jdbcTemplate.executeQuery(sql, User.class); + return jdbcTemplate.executeQuery(sql, USER_ROW_MAPPER); } public User findById(final Long id) { final var sql = "select id, account, password, email from users where id = ?"; - return jdbcTemplate.executeQueryForObject(sql, User.class, id); + return jdbcTemplate.executeQueryForObject(sql, USER_ROW_MAPPER, id); } public User findByAccount(final String account) { final var sql = "select id, account, password, email from users where account = ?"; - return jdbcTemplate.executeQueryForObject(sql, User.class, account); + return jdbcTemplate.executeQueryForObject(sql, USER_ROW_MAPPER, account); } } diff --git a/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java b/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java index 037ecf89b0..b8a455970b 100644 --- a/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java +++ b/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java @@ -1,7 +1,5 @@ package com.interface21.jdbc.core; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -54,7 +52,7 @@ public void executeUpdate(String sql, Object... parameters) { } } - public T executeQueryForObject(String sql, Class clazz, Object... parameters) { + public T executeQueryForObject(String sql, RowMapper rowMapper, Object... parameters) { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; @@ -70,7 +68,7 @@ public T executeQueryForObject(String sql, Class clazz, Object... paramet if (!rs.next()) { return null; } - return createInstance(clazz, rs); + return rowMapper.mapRow(rs); } catch (Exception e) { log.error(e.getMessage(), e); @@ -99,7 +97,7 @@ public T executeQueryForObject(String sql, Class clazz, Object... paramet } } - public List executeQuery(String sql, Class clazz, Object... parameters) { + public List executeQuery(String sql, RowMapper rowMapper, Object... parameters) { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; @@ -115,7 +113,12 @@ public List executeQuery(String sql, Class clazz, Object... parameters if (!rs.next()) { return null; } - return createInstances(clazz, rs); + + List result = new ArrayList<>(); + while (rs.next()) { + result.add(rowMapper.mapRow(rs)); + } + return result; } catch (Exception e) { log.error(e.getMessage(), e); @@ -149,28 +152,4 @@ private void setParameter(PreparedStatement pstmt, Object[] parameters) throws S pstmt.setObject(i + 1, parameters[i]); } } - - private List createInstances(Class clazz, ResultSet rs) throws Exception { - List result = new ArrayList<>(); - while (rs.next()) { - result.add(createInstance(clazz, rs)); - } - return result; - } - - private T createInstance(Class clazz, ResultSet rs) throws Exception { - Constructor constructor = clazz.getDeclaredConstructor(); - constructor.setAccessible(true); - T instance = constructor.newInstance(); - constructor.setAccessible(false); - - Field[] fields = clazz.getDeclaredFields(); - for (Field field : fields) { - field.setAccessible(true); - Object value = rs.getObject(field.getName(), field.getType()); - field.set(instance, value); - field.setAccessible(false); - } - return instance; - } } diff --git a/jdbc/src/main/java/com/interface21/jdbc/core/RowMapper.java b/jdbc/src/main/java/com/interface21/jdbc/core/RowMapper.java new file mode 100644 index 0000000000..513659e238 --- /dev/null +++ b/jdbc/src/main/java/com/interface21/jdbc/core/RowMapper.java @@ -0,0 +1,9 @@ +package com.interface21.jdbc.core; + +import java.sql.ResultSet; +import java.sql.SQLException; + +@FunctionalInterface +public interface RowMapper { + T mapRow(ResultSet rs) throws SQLException; +} diff --git a/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java b/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java index 89eeb30d1f..ac00dbacc6 100644 --- a/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java +++ b/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java @@ -18,6 +18,10 @@ class JdbcTemplateTest { + static final RowMapper TEST_USER_ROW_MAPPER = (rs) -> new TestUser( + rs.getLong("id"), + rs.getString("account")); + ResultSet rs; JdbcTemplate jdbcTemplate; @@ -40,8 +44,8 @@ void setUp() throws SQLException { void executeUpdate() throws SQLException { // given when(rs.next()).thenReturn(true); - when(rs.getObject("id", Long.class)).thenReturn(1L); - when(rs.getObject("account", String.class)).thenReturn("ever"); + when(rs.getLong("id")).thenReturn(1L); + when(rs.getString("account")).thenReturn("ever"); // when String insertSql = "insert into users (account) values (?)"; @@ -49,22 +53,22 @@ void executeUpdate() throws SQLException { // then String selectSql = "select id, account from users where id = ?"; - TestUser user = jdbcTemplate.executeQueryForObject(selectSql, TestUser.class, 1); + TestUser user = jdbcTemplate.executeQueryForObject(selectSql, TEST_USER_ROW_MAPPER, 1); assertThat(user.getId()).isEqualTo(1); assertThat(user.getAccount()).isEqualTo("ever"); } @DisplayName("단건 조회 쿼리를 실행하면 해당 데이터를 조회할 수 있다.") @Test - void executeQuery() throws SQLException { + void executeQueryForObject() throws SQLException { // given when(rs.next()).thenReturn(true); - when(rs.getObject("id", Long.class)).thenReturn(1L); - when(rs.getObject("account", String.class)).thenReturn("ever"); + when(rs.getLong("id")).thenReturn(1L); + when(rs.getString("account")).thenReturn("ever"); // when String selectSql = "select id, account from users where id = ?"; - TestUser user = jdbcTemplate.executeQueryForObject(selectSql, TestUser.class, 1); + TestUser user = jdbcTemplate.executeQueryForObject(selectSql, TEST_USER_ROW_MAPPER, 1); // then assertThat(user.getId()).isEqualTo(1); @@ -73,7 +77,7 @@ void executeQuery() throws SQLException { @DisplayName("여러건 조회 쿼리를 실행하면 해당 데이터 목록을 조회할 수 있다.") @Test - void executeQueryReturnList() throws SQLException { + void executeQuery() throws SQLException { // given String insertSql = "insert into users (account) values (?)"; jdbcTemplate.executeUpdate(insertSql, "ever1"); @@ -86,7 +90,7 @@ void executeQueryReturnList() throws SQLException { // when String selectSql = "select id, account from users"; - List testUsers = jdbcTemplate.executeQuery(selectSql, TestUser.class); + List testUsers = jdbcTemplate.executeQuery(selectSql, TEST_USER_ROW_MAPPER); // then assertThat(testUsers).hasSize(2); From 65a5ef43eef22ee66ccb61bc5ea3c583d2c0d83b Mon Sep 17 00:00:00 2001 From: SCY Date: Sun, 6 Oct 2024 19:07:59 +0900 Subject: [PATCH 09/11] =?UTF-8?q?refactor:=20=EB=B0=9C=EC=83=9D=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EC=98=88=EC=99=B8=20=ED=83=80=EC=9E=85=20=EA=B5=AC?= =?UTF-8?q?=EC=B2=B4=EC=A0=81=EC=9C=BC=EB=A1=9C=20=EB=AA=85=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/interface21/jdbc/core/JdbcTemplate.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java b/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java index b8a455970b..48baee4eb5 100644 --- a/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java +++ b/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java @@ -70,7 +70,7 @@ public T executeQueryForObject(String sql, RowMapper rowMapper, Object... } return rowMapper.mapRow(rs); - } catch (Exception e) { + } catch (SQLException e) { log.error(e.getMessage(), e); throw new RuntimeException(e); } finally { @@ -110,17 +110,13 @@ public List executeQuery(String sql, RowMapper rowMapper, Object... pa setParameter(pstmt, parameters); rs = pstmt.executeQuery(); - if (!rs.next()) { - return null; - } - List result = new ArrayList<>(); while (rs.next()) { result.add(rowMapper.mapRow(rs)); } return result; - } catch (Exception e) { + } catch (SQLException e) { log.error(e.getMessage(), e); throw new RuntimeException(e); } finally { From c838cc35e26dbaf0d33829ce4cfbb8d1e84586a9 Mon Sep 17 00:00:00 2001 From: SCY Date: Sun, 6 Oct 2024 19:08:08 +0900 Subject: [PATCH 10/11] =?UTF-8?q?test:=20JdbcTemplateTest=20=EB=B3=B4?= =?UTF-8?q?=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/techcourse/domain/User.java | 5 - .../jdbc/core/JdbcTemplateTest.java | 92 ++++++++++++++----- .../interface21/jdbc/support/TestUser.java | 23 ++++- 3 files changed, 88 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/com/techcourse/domain/User.java b/app/src/main/java/com/techcourse/domain/User.java index 421c7ffc97..986721038b 100644 --- a/app/src/main/java/com/techcourse/domain/User.java +++ b/app/src/main/java/com/techcourse/domain/User.java @@ -20,11 +20,6 @@ public User(String account, String password, String email) { this.email = email; } - private User() { - this.account = null; - this.email = null; - } - public boolean checkPassword(String password) { return this.password.equals(password); } diff --git a/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java b/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java index ac00dbacc6..156b56243c 100644 --- a/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java +++ b/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java @@ -1,8 +1,13 @@ package com.interface21.jdbc.core; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import com.interface21.jdbc.support.TestUser; @@ -18,18 +23,24 @@ class JdbcTemplateTest { + static final String INSERT_SQL = "insert into test_users (account) values (?)"; + static final String SELECT_ALL_SQL = "select id, account from test_users"; + static final String SELECT_BY_ID_SQL = "select id, account from test_users where id = ?"; static final RowMapper TEST_USER_ROW_MAPPER = (rs) -> new TestUser( rs.getLong("id"), rs.getString("account")); + DataSource dataSource; + Connection conn; ResultSet rs; + PreparedStatement pstmt; JdbcTemplate jdbcTemplate; @BeforeEach void setUp() throws SQLException { - DataSource dataSource = mock(DataSource.class); - Connection conn = mock(Connection.class); - PreparedStatement pstmt = mock(PreparedStatement.class); + dataSource = mock(DataSource.class); + conn = mock(Connection.class); + pstmt = mock(PreparedStatement.class); rs = mock(ResultSet.class); when(dataSource.getConnection()).thenReturn(conn); @@ -39,23 +50,59 @@ void setUp() throws SQLException { jdbcTemplate = new JdbcTemplate(dataSource); } - @DisplayName("삽입 쿼리를 실행하면 삽입된 데이터를 조회할 수 있다.") + @DisplayName("데이터베이스 접근이 불가한 경우 예외가 발생한다.") @Test - void executeUpdate() throws SQLException { + void should_throwException_when_cannotAccessDatabase() throws SQLException { // given - when(rs.next()).thenReturn(true); - when(rs.getLong("id")).thenReturn(1L); - when(rs.getString("account")).thenReturn("ever"); + when(dataSource.getConnection()).thenThrow(SQLException.class); + + // when & then + assertThatThrownBy(() -> jdbcTemplate.executeUpdate(anyString())) + .isInstanceOf(RuntimeException.class); + } + + @DisplayName("해제된 connection에 대해 preparedStatement를 불러오려는 경우 예외가 발생한다.") + @Test + void should_throwException_when_getPreparedStatementOfClosedConnetion() throws SQLException { + // given + when(conn.prepareStatement(anyString())).thenThrow(SQLException.class); + + // when & then + assertThatThrownBy(() -> jdbcTemplate.executeUpdate(anyString())) + .isInstanceOf(RuntimeException.class); + } + @DisplayName("해제된 preparedStatement에 대해 setObject를 수행하는 경우 예외가 발생한다.") + @Test + void should_throwException_when_setObjectByClosedPreparedStatement() throws SQLException { + // given + doThrow(SQLException.class).when(pstmt).setObject(anyInt(), any(Object.class)); + + // when & then + assertThatThrownBy(() -> jdbcTemplate.executeUpdate(anyString())) + .isInstanceOf(RuntimeException.class); + } + + @DisplayName("executeUpdate를 통해 조회 쿼리를 수행하는 경우 예외가 발생한다.") + @Test + void should_throwException_when_executeUpdateWithSelectQuery() throws SQLException { + // given + doThrow(SQLException.class).when(pstmt).executeUpdate(); + + // when & then + assertThatThrownBy(() -> jdbcTemplate.executeUpdate(SELECT_ALL_SQL)) + .isInstanceOf(RuntimeException.class); + } + + @DisplayName("삽입 쿼리를 실행하면 파라미터 주입 후 쿼리가 실행된다.") + @Test + void should_setObjectAndExecute_when_executeInsertQuery() throws SQLException { // when - String insertSql = "insert into users (account) values (?)"; - jdbcTemplate.executeUpdate(insertSql, "ever"); + jdbcTemplate.executeUpdate(INSERT_SQL, "ever"); // then - String selectSql = "select id, account from users where id = ?"; - TestUser user = jdbcTemplate.executeQueryForObject(selectSql, TEST_USER_ROW_MAPPER, 1); - assertThat(user.getId()).isEqualTo(1); - assertThat(user.getAccount()).isEqualTo("ever"); + verify(pstmt).setObject(1, "ever"); + verify(pstmt).executeUpdate(); } @DisplayName("단건 조회 쿼리를 실행하면 해당 데이터를 조회할 수 있다.") @@ -67,11 +114,12 @@ void executeQueryForObject() throws SQLException { when(rs.getString("account")).thenReturn("ever"); // when - String selectSql = "select id, account from users where id = ?"; - TestUser user = jdbcTemplate.executeQueryForObject(selectSql, TEST_USER_ROW_MAPPER, 1); + TestUser user = jdbcTemplate.executeQueryForObject(SELECT_BY_ID_SQL, TEST_USER_ROW_MAPPER, 1L); // then - assertThat(user.getId()).isEqualTo(1); + verify(pstmt).setObject(1, 1L); + verify(pstmt).executeQuery(); + assertThat(user.getId()).isEqualTo(1L); assertThat(user.getAccount()).isEqualTo("ever"); } @@ -79,20 +127,18 @@ void executeQueryForObject() throws SQLException { @Test void executeQuery() throws SQLException { // given - String insertSql = "insert into users (account) values (?)"; - jdbcTemplate.executeUpdate(insertSql, "ever1"); - jdbcTemplate.executeUpdate(insertSql, "ever2"); + jdbcTemplate.executeUpdate(INSERT_SQL, "ever1"); + jdbcTemplate.executeUpdate(INSERT_SQL, "ever2"); when(rs.next()).thenReturn(true) - .thenReturn(true) .thenReturn(true) .thenReturn(false); // when - String selectSql = "select id, account from users"; - List testUsers = jdbcTemplate.executeQuery(selectSql, TEST_USER_ROW_MAPPER); + List testUsers = jdbcTemplate.executeQuery(SELECT_ALL_SQL, TEST_USER_ROW_MAPPER); // then + verify(pstmt).executeQuery(); assertThat(testUsers).hasSize(2); } } diff --git a/jdbc/src/test/java/com/interface21/jdbc/support/TestUser.java b/jdbc/src/test/java/com/interface21/jdbc/support/TestUser.java index caeb12b465..14e5c462b9 100644 --- a/jdbc/src/test/java/com/interface21/jdbc/support/TestUser.java +++ b/jdbc/src/test/java/com/interface21/jdbc/support/TestUser.java @@ -1,5 +1,7 @@ package com.interface21.jdbc.support; +import java.util.Objects; + public class TestUser { private final Long id; @@ -10,10 +12,6 @@ public TestUser(Long id, String account) { this.account = account; } - private TestUser() { - this(null, null); - } - public Long getId() { return id; } @@ -21,4 +19,21 @@ public Long getId() { public String getAccount() { return account; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TestUser testUser = (TestUser) o; + return Objects.equals(id, testUser.id); + } + + @Override + public int hashCode() { + return Objects.hash(id, account); + } } From ce1b7d44640c9f0057f2e00f28b6d890fddbce73 Mon Sep 17 00:00:00 2001 From: SCY Date: Sun, 6 Oct 2024 20:26:34 +0900 Subject: [PATCH 11/11] =?UTF-8?q?refactor:=20SQL=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=9E=A1=EC=9D=84=20=EA=B2=BD=EC=9A=B0=20=EB=8D=98=EC=A7=80?= =?UTF-8?q?=EB=8A=94=20=EC=98=88=EC=99=B8=20=EC=A2=85=EB=A5=98=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/interface21/jdbc/core/JdbcTemplate.java | 7 ++++--- .../interface21/jdbc/core/JdbcTemplateTest.java | 15 ++++++++------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java b/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java index 48baee4eb5..e7fa01425d 100644 --- a/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java +++ b/jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java @@ -1,5 +1,6 @@ package com.interface21.jdbc.core; +import com.interface21.dao.DataAccessException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -34,7 +35,7 @@ public void executeUpdate(String sql, Object... parameters) { } catch (SQLException e) { log.error(e.getMessage(), e); - throw new RuntimeException(e); + throw new DataAccessException(e); } finally { try { if (pstmt != null) { @@ -72,7 +73,7 @@ public T executeQueryForObject(String sql, RowMapper rowMapper, Object... } catch (SQLException e) { log.error(e.getMessage(), e); - throw new RuntimeException(e); + throw new DataAccessException(e); } finally { try { if (rs != null) { @@ -118,7 +119,7 @@ public List executeQuery(String sql, RowMapper rowMapper, Object... pa } catch (SQLException e) { log.error(e.getMessage(), e); - throw new RuntimeException(e); + throw new DataAccessException(e); } finally { try { if (rs != null) { diff --git a/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java b/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java index 156b56243c..becc754af1 100644 --- a/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java +++ b/jdbc/src/test/java/com/interface21/jdbc/core/JdbcTemplateTest.java @@ -10,6 +10,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.interface21.dao.DataAccessException; import com.interface21.jdbc.support.TestUser; import java.sql.Connection; import java.sql.PreparedStatement; @@ -57,8 +58,8 @@ void should_throwException_when_cannotAccessDatabase() throws SQLException { when(dataSource.getConnection()).thenThrow(SQLException.class); // when & then - assertThatThrownBy(() -> jdbcTemplate.executeUpdate(anyString())) - .isInstanceOf(RuntimeException.class); + assertThatThrownBy(() -> jdbcTemplate.executeUpdate(INSERT_SQL)) + .isInstanceOf(DataAccessException.class); } @DisplayName("해제된 connection에 대해 preparedStatement를 불러오려는 경우 예외가 발생한다.") @@ -68,8 +69,8 @@ void should_throwException_when_getPreparedStatementOfClosedConnetion() throws S when(conn.prepareStatement(anyString())).thenThrow(SQLException.class); // when & then - assertThatThrownBy(() -> jdbcTemplate.executeUpdate(anyString())) - .isInstanceOf(RuntimeException.class); + assertThatThrownBy(() -> jdbcTemplate.executeUpdate(INSERT_SQL)) + .isInstanceOf(DataAccessException.class); } @DisplayName("해제된 preparedStatement에 대해 setObject를 수행하는 경우 예외가 발생한다.") @@ -79,8 +80,8 @@ void should_throwException_when_setObjectByClosedPreparedStatement() throws SQLE doThrow(SQLException.class).when(pstmt).setObject(anyInt(), any(Object.class)); // when & then - assertThatThrownBy(() -> jdbcTemplate.executeUpdate(anyString())) - .isInstanceOf(RuntimeException.class); + assertThatThrownBy(() -> jdbcTemplate.executeQueryForObject(SELECT_BY_ID_SQL, TEST_USER_ROW_MAPPER, 1L)) + .isInstanceOf(DataAccessException.class); } @DisplayName("executeUpdate를 통해 조회 쿼리를 수행하는 경우 예외가 발생한다.") @@ -91,7 +92,7 @@ void should_throwException_when_executeUpdateWithSelectQuery() throws SQLExcepti // when & then assertThatThrownBy(() -> jdbcTemplate.executeUpdate(SELECT_ALL_SQL)) - .isInstanceOf(RuntimeException.class); + .isInstanceOf(DataAccessException.class); } @DisplayName("삽입 쿼리를 실행하면 파라미터 주입 후 쿼리가 실행된다.")