diff --git a/app/src/main/java/com/techcourse/dao/UserDao.java b/app/src/main/java/com/techcourse/dao/UserDao.java index ee17c159c2..105f4a173a 100644 --- a/app/src/main/java/com/techcourse/dao/UserDao.java +++ b/app/src/main/java/com/techcourse/dao/UserDao.java @@ -1,121 +1,55 @@ package com.techcourse.dao; import com.techcourse.domain.User; +import java.util.List; +import javax.sql.DataSource; import nextstep.jdbc.JdbcTemplate; +import nextstep.jdbc.RowMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.List; - 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 DataSource dataSource; + private final JdbcTemplate jdbcTemplate; - public UserDao(final DataSource dataSource) { - this.dataSource = dataSource; + public UserDao(final JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; } - public UserDao(final JdbcTemplate jdbcTemplate) { - this.dataSource = null; + public UserDao(final DataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); } 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); - - 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) {} - } + String sql = "insert into users (account, password, email) values (?, ?, ?)"; + jdbcTemplate.update(sql, user.getAccount(), user.getPassword(), user.getEmail()); } public void update(final User user) { - // todo + String sql = "update users set (account, password, email) = (?, ?, ?) where id = ?"; + jdbcTemplate.update(sql, user.getAccount(), user.getPassword(), user.getEmail(), user.getId()); } public List findAll() { - // todo - return null; + String sql = "select id, account, password, email from users"; + return jdbcTemplate.query(sql, USER_ROW_MAPPER); } 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); - pstmt.setLong(1, id); - rs = pstmt.executeQuery(); - - log.debug("query : {}", sql); - - if (rs.next()) { - return new User( - rs.getLong(1), - rs.getString(2), - rs.getString(3), - rs.getString(4)); - } - 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) {} - } + String sql = "select id, account, password, email from users where id = ?"; + return jdbcTemplate.queryForObject(sql, USER_ROW_MAPPER, id); } public User findByAccount(final String account) { - // todo - return null; + String sql = "select id, account, password, email from users where account = ?"; + return jdbcTemplate.queryForObject(sql, USER_ROW_MAPPER, account); } } diff --git a/app/src/test/java/com/techcourse/dao/UserDaoTest.java b/app/src/test/java/com/techcourse/dao/UserDaoTest.java index 773d7faf82..2bcf5a8a40 100644 --- a/app/src/test/java/com/techcourse/dao/UserDaoTest.java +++ b/app/src/test/java/com/techcourse/dao/UserDaoTest.java @@ -1,13 +1,13 @@ package com.techcourse.dao; +import static org.assertj.core.api.Assertions.assertThat; + 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; diff --git a/jdbc/src/main/java/nextstep/jdbc/JdbcTemplate.java b/jdbc/src/main/java/nextstep/jdbc/JdbcTemplate.java index 613a588a93..485da70ef8 100644 --- a/jdbc/src/main/java/nextstep/jdbc/JdbcTemplate.java +++ b/jdbc/src/main/java/nextstep/jdbc/JdbcTemplate.java @@ -1,17 +1,68 @@ package nextstep.jdbc; +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; -import javax.sql.DataSource; - public class JdbcTemplate { private static final Logger log = LoggerFactory.getLogger(JdbcTemplate.class); + private static final int FIRST_RESULT_INDEX = 0; private final DataSource dataSource; public JdbcTemplate(final DataSource dataSource) { this.dataSource = dataSource; } + + public int update(final String sql, final Object... args) { + return usePreparedStatement(sql, PreparedStatement::executeUpdate, args); + } + + public List query(final String sql, final RowMapper rowMapper, final Object... args) { + return usePreparedStatement(sql, pstmt -> mapToList(rowMapper, pstmt), args); + } + + private List mapToList(final RowMapper rowMapper, final PreparedStatement pstmt) throws SQLException { + List results = new ArrayList<>(); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) { + T result = rowMapper.run(rs); + results.add(result); + } + + return results; + } + + public T queryForObject(final String sql, final RowMapper rowMapper, final Object... args) { + List results = query(sql, rowMapper, args); + return results.get(FIRST_RESULT_INDEX); + } + + public T usePreparedStatement(final String sql, + final ThrowingFunction function, + final Object... args) { + try (Connection connection = dataSource.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(sql)) { + mapParametersToPreparedStatement(preparedStatement, args); + return function.apply(preparedStatement); + } catch (final SQLException e) { + log.error("error: {}", e); + throw new DataAccessException(e.getMessage(), e); + // TODO: 더 추상화된 예외 메시지를 사용해야함 + } + } + + private void mapParametersToPreparedStatement(final PreparedStatement preparedStatement, final Object[] args) + throws SQLException { + for (int i = 0; i < args.length; i++) { + preparedStatement.setObject(i + 1, args[i]); + } + } } diff --git a/jdbc/src/main/java/nextstep/jdbc/RowMapper.java b/jdbc/src/main/java/nextstep/jdbc/RowMapper.java new file mode 100644 index 0000000000..d481a9ef86 --- /dev/null +++ b/jdbc/src/main/java/nextstep/jdbc/RowMapper.java @@ -0,0 +1,10 @@ +package nextstep.jdbc; + +import java.sql.ResultSet; +import java.sql.SQLException; + +@FunctionalInterface +public interface RowMapper { + + T run(final ResultSet rs) throws SQLException; +} diff --git a/jdbc/src/main/java/nextstep/jdbc/ThrowingFunction.java b/jdbc/src/main/java/nextstep/jdbc/ThrowingFunction.java new file mode 100644 index 0000000000..eb4127ab1a --- /dev/null +++ b/jdbc/src/main/java/nextstep/jdbc/ThrowingFunction.java @@ -0,0 +1,7 @@ +package nextstep.jdbc; + +@FunctionalInterface +public interface ThrowingFunction { + + R apply(final T t) throws E; +}