Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JDBC 라이브러리 구현하기 - 1단계] 후추(주찬민) 미션 제출합니다. #313

Merged
merged 9 commits into from
Oct 3, 2023
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,12 @@
# JDBC 라이브러리 구현하기

## 1단계 - JDBC 라이브러리 구현하기

- [x] JDBC Template 구현
- [x] 데이터 변경 쿼리에 대한 메서드
- [x] 단일 객체 조회 쿼리에 대한 메서드
- [x] 복수 객체 조회 쿼리에 대한 메서드

- [x] UserDao 리팩터링


115 changes: 21 additions & 94 deletions app/src/main/java/com/techcourse/dao/UserDao.java
Original file line number Diff line number Diff line change
@@ -1,121 +1,48 @@
package com.techcourse.dao;

import com.techcourse.domain.User;
import org.springframework.jdbc.core.JdbcTemplate;
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;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

public class UserDao {

private static final Logger log = LoggerFactory.getLogger(UserDao.class);
private static final RowMapper<User> USER_ROW_MAPPER = rs -> {
final long userId = rs.getLong("id");
final String account = rs.getString("account");
final String password = rs.getString("password");
final String email = rs.getString("email");
return new User(userId, account, password, email);
};

private final DataSource dataSource;

public UserDao(final DataSource dataSource) {
this.dataSource = dataSource;
}
private final 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);

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) {}
}
final var sql = "INSERT INTO users (account, password, email) VALUES (?, ?, ?)";
jdbcTemplate.update(sql, user.getAccount(), user.getPassword(), user.getEmail());
}

public void update(final User user) {
// todo
final var sql = "UPDATE users SET account = ?, password = ?, email = ? WHERE id = ?";
jdbcTemplate.update(sql, user.getAccount(), user.getPassword(), user.getEmail(), user.getId());
}

public List<User> findAll() {
// todo
return null;
final var 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) {}
}
final var 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;
final var sql = "SELECT id, account, password, email FROM users WHERE account = ?";
return jdbcTemplate.queryForObject(sql, USER_ROW_MAPPER, account);
}
}
108 changes: 76 additions & 32 deletions app/src/test/java/com/techcourse/dao/UserDaoTest.java
Original file line number Diff line number Diff line change
@@ -1,69 +1,113 @@
package com.techcourse.dao;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.SoftAssertions.assertSoftly;

import com.techcourse.config.DataSourceConfig;
import com.techcourse.domain.User;
import com.techcourse.support.jdbc.init.DatabasePopulatorUtils;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;

import static org.assertj.core.api.Assertions.assertThat;

@SuppressWarnings("NonAsciiCharacters")
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
class UserDaoTest {

private JdbcTemplate jdbcTemplate;
private User user;
private UserDao userDao;

@BeforeEach
void setup() {
DatabasePopulatorUtils.execute(DataSourceConfig.getInstance());
jdbcTemplate = new JdbcTemplate(DataSourceConfig.getInstance());
userDao = new UserDao(jdbcTemplate);

userDao = new UserDao(DataSourceConfig.getInstance());
final var user = new User("gugu", "password", "[email protected]");
userDao.insert(user);
userDao.insert(new User("gugu", "password", "[email protected]"));
user = userDao.findByAccount("gugu");
}

@Test
void findAll() {
final var users = userDao.findAll();

assertThat(users).isNotEmpty();
void 모든_회원을_조회한다() {
// when
final List<User> users = userDao.findAll();

// then
assertSoftly(softly -> {
softly.assertThat(users).hasSize(1);
final User user = users.get(0);

softly.assertThat(user.getAccount()).isEqualTo("gugu");
softly.assertThat(user.getPassword()).isEqualTo("password");
softly.assertThat(user.getEmail()).isEqualTo("[email protected]");
});
Combi153 marked this conversation as resolved.
Show resolved Hide resolved
}

@Test
void findById() {
final var user = userDao.findById(1L);

assertThat(user.getAccount()).isEqualTo("gugu");
void ID로_회원을_조회한다() {
// when
final User foundUser = userDao.findById(user.getId());

// then
assertSoftly(softly -> {
softly.assertThat(foundUser.getAccount()).isEqualTo("gugu");
softly.assertThat(foundUser.getPassword()).isEqualTo("password");
softly.assertThat(foundUser.getEmail()).isEqualTo("[email protected]");
});
}

@Test
void findByAccount() {
final var account = "gugu";
final var user = userDao.findByAccount(account);

assertThat(user.getAccount()).isEqualTo(account);
void 계정으로_회원을_조회한다() {
// when
final User foundUser = userDao.findByAccount(user.getAccount());

// then
assertSoftly(softly -> {
softly.assertThat(foundUser.getAccount()).isEqualTo("gugu");
softly.assertThat(foundUser.getPassword()).isEqualTo("password");
softly.assertThat(foundUser.getEmail()).isEqualTo("[email protected]");
});
}

@Test
void insert() {
final var account = "insert-gugu";
final var user = new User(account, "password", "[email protected]");
userDao.insert(user);

final var actual = userDao.findById(2L);

assertThat(actual.getAccount()).isEqualTo(account);
void 회원을_정보를_입력한다() {
// given
final var account = "huchu";
final User huchu = new User(account, "password", "[email protected]");

// when
userDao.insert(huchu);

// then
final User foundUser = userDao.findByAccount(account);
assertSoftly(softly -> {
softly.assertThat(foundUser.getAccount()).isEqualTo("huchu");
softly.assertThat(foundUser.getPassword()).isEqualTo("password");
softly.assertThat(foundUser.getEmail()).isEqualTo("[email protected]");
});
}

@Test
void update() {
final var newPassword = "password99";
final var user = userDao.findById(1L);
user.changePassword(newPassword);
void 회원_정보를_수정한다() {
// given
user.changePassword("newPassword");

// when
userDao.update(user);

final var actual = userDao.findById(1L);
// then
final User changedUser = userDao.findByAccount(user.getAccount());
assertThat(changedUser.getPassword()).isEqualTo("newPassword");
}

assertThat(actual.getPassword()).isEqualTo(newPassword);
@AfterEach
void tearDown() {
final String deleteSql = "DELETE FROM users";
jdbcTemplate.update(deleteSql);
}
}
76 changes: 74 additions & 2 deletions jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
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 javax.annotation.Nullable;
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);
Expand All @@ -14,4 +20,70 @@ public class JdbcTemplate {
public JdbcTemplate(final DataSource dataSource) {
this.dataSource = dataSource;
}

public int update(String sql, Object... args) {
try (
Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)
) {
log.debug("query : {}", sql);

setParameters(pstmt, args);
Combi153 marked this conversation as resolved.
Show resolved Hide resolved

return pstmt.executeUpdate();
} catch (SQLException e) {
log.error(e.getMessage(), e);
throw new RuntimeException(e);
}
}

private void setParameters(PreparedStatement pstmt, Object[] args) throws SQLException {
for (int i = 0; i < args.length; i++) {
pstmt.setObject(i + 1, args[i]);
}
}

@Nullable
public <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args) {
try (
Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)
) {
log.debug("query : {}", sql);

setParameters(pstmt, args);

try (ResultSet resultSet = pstmt.executeQuery()) {
Combi153 marked this conversation as resolved.
Show resolved Hide resolved
if (resultSet.next()) {
return rowMapper.mapRow(resultSet);
}
Combi153 marked this conversation as resolved.
Show resolved Hide resolved
}
return null;
} catch (SQLException e) {
log.error(e.getMessage(), e);
throw new RuntimeException(e);
}
}

public <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args) {
try (
Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)
) {
log.debug("query : {}", sql);

setParameters(pstmt, args);

try (ResultSet resultSet = pstmt.executeQuery()) {
List<T> results = new ArrayList<>();
while (resultSet.next()) {
results.add(rowMapper.mapRow(resultSet));
}
return results;
}
} catch (SQLException e) {
log.error(e.getMessage(), e);
throw new RuntimeException(e);
}
}
}
Loading
Loading