diff --git a/app/src/main/java/com/techcourse/dao/UserDao.java b/app/src/main/java/com/techcourse/dao/UserDao.java index 2c1bbe33a0..b27e0f6c74 100644 --- a/app/src/main/java/com/techcourse/dao/UserDao.java +++ b/app/src/main/java/com/techcourse/dao/UserDao.java @@ -1,5 +1,6 @@ package com.techcourse.dao; +import com.techcourse.config.DataSourceConfig; import com.techcourse.domain.User; import java.util.ArrayList; import org.springframework.jdbc.core.JdbcTemplate; @@ -18,61 +19,26 @@ public class UserDao { private static final Logger log = LoggerFactory.getLogger(UserDao.class); - private final DataSource dataSource; + private final JdbcTemplate jdbcTemplate; - public UserDao(final DataSource dataSource) { - this.dataSource = dataSource; - } public UserDao(final JdbcTemplate jdbcTemplate) { - this.dataSource = null; + this.jdbcTemplate = new JdbcTemplate(DataSourceConfig.getInstance()); } public void insert(final User user) { final var sql = "insert into users (account, password, email) values (?, ?, ?)"; - execute(sql, user.getAccount(), user.getPassword(), user.getEmail()); - } - - private void execute(String sql, Object... parameters) { - Connection conn = null; - PreparedStatement pstmt = null; - try { - conn = dataSource.getConnection(); - pstmt = conn.prepareStatement(sql); - - log.debug("query : {}", sql); - - for (int i = 0; i < parameters.length; i++) { - pstmt.setObject(i + 1, parameters[i]); - } - - 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) {} - } + jdbcTemplate.execute(sql, user.getAccount(), user.getPassword(), user.getEmail()); } public void update(final User user) { final var sql = "update users set password = ?, email = ?, account = ? where id = ?"; - execute(sql, user.getPassword(), user.getEmail(), user.getAccount(), user.getId()); + jdbcTemplate.execute(sql, user.getPassword(), user.getEmail(), user.getAccount(), user.getId()); } public List findAll() { final var sql = "select id, account, password, email from users"; - return query(sql, (rs, rowNum) -> new User(rs.getLong("id"), + return jdbcTemplate.query(sql, (rs, rowNum) -> new User(rs.getLong("id"), rs.getString("account"), rs.getString("password"), rs.getString("email"))); @@ -80,69 +46,15 @@ public List findAll() { public User findById(final Long id) { final var sql = "select id, account, password, email from users where id = ?"; - return queryForObject(sql, (rs, rowNum) -> new User(rs.getLong("id"), + return jdbcTemplate.queryForObject(sql, (rs, rowNum) -> new User(rs.getLong("id"), rs.getString("account"), rs.getString("password"), rs.getString("email")), id); } - private T queryForObject(String sql, RowMapper rowMapper, Object... params) { - List query = query(sql, rowMapper, params); - if (query.size() > 1) { - throw new RuntimeException("too many result"); - } - if (query.isEmpty()) { - return null; - } - return query.get(0); - } - - private List query(String sql, RowMapper rowMapper, Object... parameters) { - Connection conn = null; - PreparedStatement pstmt = null; - ResultSet rs = null; - try { - conn = dataSource.getConnection(); - pstmt = conn.prepareStatement(sql); - for (int i = 0; i < parameters.length; i++) { - pstmt.setObject(i + 1, parameters[i]); - } - rs = pstmt.executeQuery(); - - log.debug("query : {}", sql); - - final List results = new ArrayList<>(); - if (rs.next()) { - results.add(rowMapper.mapRow(rs, 0)); - } - return results; - } 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) {} - } - } - public User findByAccount(final String account) { final var sql = "select id, account, password, email from users where account = ?"; - return queryForObject(sql, (rs, rowNum) -> new User(rs.getLong("id"), + return jdbcTemplate.queryForObject(sql, (rs, rowNum) -> new User(rs.getLong("id"), rs.getString("account"), rs.getString("password"), rs.getString("email")), 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..7e9cc2b01a 100644 --- a/app/src/test/java/com/techcourse/dao/UserDaoTest.java +++ b/app/src/test/java/com/techcourse/dao/UserDaoTest.java @@ -5,6 +5,7 @@ import com.techcourse.support.jdbc.init.DatabasePopulatorUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.jdbc.core.JdbcTemplate; import static org.assertj.core.api.Assertions.assertThat; @@ -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("gugu", "password", "hkkang@woowahan.com"); userDao.insert(user); } diff --git a/jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java b/jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java index 52a0d30a17..7baee7f2a2 100644 --- a/jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java +++ b/jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java @@ -1,5 +1,11 @@ package org.springframework.jdbc.core; +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 org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,4 +20,90 @@ public class JdbcTemplate { public JdbcTemplate(final DataSource dataSource) { this.dataSource = dataSource; } + + public void execute(String sql, Object... parameters) { + Connection conn = null; + PreparedStatement pstmt = null; + try { + conn = dataSource.getConnection(); + pstmt = conn.prepareStatement(sql); + + log.debug("query : {}", sql); + + for (int i = 0; i < parameters.length; i++) { + pstmt.setObject(i + 1, parameters[i]); + } + + 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 queryForObject(String sql, RowMapper rowMapper, Object... params) { + List query = query(sql, rowMapper, params); + if (query.size() > 1) { + throw new RuntimeException("too many result"); + } + if (query.isEmpty()) { + return null; + } + return query.get(0); + } + + public List query(String sql, RowMapper rowMapper, Object... parameters) { + Connection conn = null; + PreparedStatement pstmt = null; + ResultSet rs = null; + try { + conn = dataSource.getConnection(); + pstmt = conn.prepareStatement(sql); + for (int i = 0; i < parameters.length; i++) { + pstmt.setObject(i + 1, parameters[i]); + } + rs = pstmt.executeQuery(); + + log.debug("query : {}", sql); + + final List results = new ArrayList<>(); + if (rs.next()) { + results.add(rowMapper.mapRow(rs, 0)); + } + return results; + } 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/jdbc/src/main/java/org/springframework/jdbc/core/RowMapper.java b/jdbc/src/main/java/org/springframework/jdbc/core/RowMapper.java new file mode 100644 index 0000000000..7fee249381 --- /dev/null +++ b/jdbc/src/main/java/org/springframework/jdbc/core/RowMapper.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.core; + +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * An interface used by {@link JdbcTemplate} for mapping rows of a + * {@link ResultSet} on a per-row basis. Implementations of this + * interface perform the actual work of mapping each row to a result object, + * but don't need to worry about exception handling. + * {@link SQLException SQLExceptions} will be caught and handled + * by the calling JdbcTemplate. + * + *

Typically used either for {@link JdbcTemplate}'s query methods + * or for out parameters of stored procedures. RowMapper objects are + * typically stateless and thus reusable; they are an ideal choice for + * implementing row-mapping logic in a single place. + * + *

Alternatively, consider subclassing + * {@code jdbc.object} package: Instead of working with separate + * JdbcTemplate and RowMapper objects, you can build executable query + * objects (containing row-mapping logic) in that style. + * + * @author Thomas Risberg + * @author Juergen Hoeller + * @param the result type + * @see JdbcTemplate + */ +@FunctionalInterface +public interface RowMapper { + + /** + * Implementations must implement this method to map each row of data + * in the ResultSet. This method should not call {@code next()} on + * the ResultSet; it is only supposed to map values of the current row. + * @param rs the ResultSet to map (pre-initialized for the current row) + * @param rowNum the number of the current row + * @return the result object for the current row (maybe {@code null}) + * @throws SQLException if an SQLException is encountered getting + * column values (that is, there's no need to catch SQLException) + */ + T mapRow(ResultSet rs, int rowNum) throws SQLException; + +}