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 라이브러리 구현하기 - 4단계] 여우(조승현) 미션 제출합니다. #602

Merged
merged 7 commits into from
Oct 12, 2023
Merged
34 changes: 15 additions & 19 deletions app/src/main/java/com/techcourse/dao/UserDaoWithJdbcTemplate.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.techcourse.domain.User;
import com.techcourse.repository.UserRepository;
import java.sql.Connection;
import java.util.List;
import java.util.Optional;
import javax.sql.DataSource;
Expand All @@ -17,37 +16,34 @@ public UserDaoWithJdbcTemplate(final DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}

public void insert(final Connection connection, final User user) {
@Override
public void insert(final User user) {
final var sql = "insert into users (account, password, email) values (?, ?, ?)";
jdbcTemplate.update(connection, sql, user.getAccount(), user.getPassword(), user.getEmail());
jdbcTemplate.update(sql, user.getAccount(), user.getPassword(), user.getEmail());
}

public void update(final Connection connection, final User user) {
@Override
public void update(final User user) {
final String sql = "update users set (account, password, email) = (?, ?, ?) where id = ?";
jdbcTemplate.update(connection, sql, user.getAccount(), user.getPassword(), user.getEmail(), user.getId());
jdbcTemplate.update(sql, user.getAccount(), user.getPassword(), user.getEmail(), user.getId());
}

public List<User> findAll(final Connection connection) {
@Override
public List<User> findAll() {
final String sql = "select * from users";
return jdbcTemplate.query(connection, sql, getUserRowMapper());
return jdbcTemplate.query(sql, getUserRowMapper());
}

public User findById(final Connection connection, final Long id) {
@Override
public Optional<User> findById(final Long id) {
final var sql = "select id, account, password, email from users where id = ?";
final Optional<User> user = jdbcTemplate.queryForObject(connection, sql, getUserRowMapper(), id);
if (user.isEmpty()) {
throw new RuntimeException("유저 없음!");
}
return user.get();
return jdbcTemplate.queryForObject(sql, getUserRowMapper(), id);
}

public User findByAccount(final Connection connection, final String account) {
@Override
public Optional<User> findByAccount(final String account) {
final var sql = "select id, account, password, email from users where account = ?";
final Optional<User> user = jdbcTemplate.queryForObject(connection, sql, getUserRowMapper(), account);
if (user.isEmpty()) {
throw new RuntimeException("유저 없음!");
}
return user.get();
return jdbcTemplate.queryForObject(sql, getUserRowMapper(), account);
}

private static RowMapper<User> getUserRowMapper() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.techcourse.dao;

import com.techcourse.domain.User;
import com.techcourse.repository.UserRepository;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -9,64 +10,65 @@
import org.springframework.jdbc.core.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

public class UserDaoWithNamedParameterJdbcTemplate {
public class UserDaoWithNamedParameterJdbcTemplate implements UserRepository {
public static final String ACCOUNT = "account";
public static final String PASSWORD = "password";
public static final String EMAIL = "email";
public static final String ID = "id";
Comment on lines +14 to +17

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

상수화 굿 👍

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SonarLint가 이런 거 정말 잘 짚어주더라구요! 구구 짱 🙌🏻

private final NamedParameterJdbcTemplate jdbcTemplate;

public UserDaoWithNamedParameterJdbcTemplate(final DataSource dataSource) {
this.jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}

@Override
public void insert(final User user) {
final var sql = "insert into users (account, password, email) values (:account, :password, :email)";
final HashMap<String, Object> parameters = new HashMap<>();
parameters.put("account", user.getAccount());
parameters.put("password", user.getPassword());
parameters.put("email", user.getEmail());
parameters.put(ACCOUNT, user.getAccount());
parameters.put(PASSWORD, user.getPassword());
parameters.put(EMAIL, user.getEmail());
jdbcTemplate.update(sql, parameters);
}

@Override
public void update(final User user) {
final String sql = "update users set (account, password, email) = (:account, :password, :email) where id = :id";
final HashMap<String, Object> parameters = new HashMap<>();
parameters.put("account", user.getAccount());
parameters.put("password", user.getPassword());
parameters.put("email", user.getEmail());
parameters.put("id", user.getId());
parameters.put(ACCOUNT, user.getAccount());
parameters.put(PASSWORD, user.getPassword());
parameters.put(EMAIL, user.getEmail());
parameters.put(ID, user.getId());
jdbcTemplate.update(sql, parameters);
}

@Override
public List<User> findAll() {
final String sql = "select * from users";
return jdbcTemplate.query(sql, getUserRowMapper(), Map.of());
}

public User findById(final Long id) {
@Override
public Optional<User> findById(final Long id) {
final var sql = "select id, account, password, email from users where id = :id";
final HashMap<String, Object> parameters = new HashMap<>();
parameters.put("id", id);
final Optional<User> user = jdbcTemplate.queryForObject(sql, getUserRowMapper(), parameters);
if (user.isEmpty()) {
throw new RuntimeException("유저 없음!");
}
return user.get();
parameters.put(ID, id);
return jdbcTemplate.queryForObject(sql, getUserRowMapper(), parameters);
}

public User findByAccount(final String account) {
@Override
public Optional<User> findByAccount(final String account) {
final var sql = "select id, account, password, email from users where account = :account";
final HashMap<String, Object> parameters = new HashMap<>();
parameters.put("account", account);
final Optional<User> user = jdbcTemplate.queryForObject(sql, getUserRowMapper(), parameters);
if (user.isEmpty()) {
throw new RuntimeException("유저 없음!");
}
return user.get();
parameters.put(ACCOUNT, account);
return jdbcTemplate.queryForObject(sql, getUserRowMapper(), parameters);
}

private static RowMapper<User> getUserRowMapper() {
return (rs, rowNum) -> new User(
rs.getLong("id"),
rs.getString("account"),
rs.getString("password"),
rs.getString("email"));
rs.getLong(ID),
rs.getString(ACCOUNT),
rs.getString(PASSWORD),
rs.getString(EMAIL));
}
}
6 changes: 2 additions & 4 deletions app/src/main/java/com/techcourse/dao/UserHistoryDao.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.techcourse.dao;

import com.techcourse.domain.UserHistory;
import java.sql.Connection;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;
Expand All @@ -14,10 +13,9 @@ public UserHistoryDao(final DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}

public void log(final Connection connection, final UserHistory userHistory) {
public void log(final UserHistory userHistory) {
final var sql = "insert into user_history (user_id, account, password, email, created_at, created_by) values (?, ?, ?, ?, ?, ?)";
jdbcTemplate.update(connection,
sql,
jdbcTemplate.update(sql,
userHistory.getUserId(),
userHistory.getAccount(),
userHistory.getPassword(),
Expand Down
12 changes: 6 additions & 6 deletions app/src/main/java/com/techcourse/repository/UserRepository.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package com.techcourse.repository;

import com.techcourse.domain.User;
import java.sql.Connection;
import java.util.List;
import java.util.Optional;

public interface UserRepository {

void insert(final Connection connection, final User user);
void insert(final User user);

void update(final Connection connection, final User user);
void update(final User user);

List<User> findAll(final Connection connection);
List<User> findAll();

User findById(final Connection connection, final Long id);
Optional<User> findById(final Long id);

User findByAccount(final Connection connection, final String account);
Optional<User> findByAccount(final String account);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.techcourse.service;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.dao.SQLTransactionRollbackException;
import org.springframework.jdbc.datasource.DataSourceUtils;

public class TransactionProxyHandler implements InvocationHandler {

private final Object target;
private final DataSource dataSource;

public TransactionProxyHandler(final Object target, final DataSource dataSource) {
this.target = target;
this.dataSource = dataSource;
}

@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
final Connection connection = DataSourceUtils.getConnection(dataSource);
try {
connection.setAutoCommit(false);
final Object result = method.invoke(target, args);
connection.commit();

return result;
} catch (RuntimeException | SQLException e) {
throw handleTransactionFailure(connection, e);
} finally {
DataSourceUtils.releaseConnection(connection, dataSource);
}
}
Comment on lines +21 to +35

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 프록시를 사용하셨군요! 덕분에 새로운 걸 배워갑니다. 🙇‍♀️


private Exception handleTransactionFailure(final Connection connection, final Exception e) {
try {
connection.rollback();
return e;
} catch (SQLException ex) {
return new SQLTransactionRollbackException(ex);
}
}
}
52 changes: 4 additions & 48 deletions app/src/main/java/com/techcourse/service/UserService.java
Original file line number Diff line number Diff line change
@@ -1,55 +1,11 @@
package com.techcourse.service;

import com.techcourse.dao.UserDaoWithJdbcTemplate;
import com.techcourse.dao.UserHistoryDao;
import com.techcourse.domain.User;
import com.techcourse.domain.UserHistory;
import java.sql.Connection;
import java.sql.SQLException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.SQLTransactionRollbackException;

public class UserService {
public interface UserService {
User findById(final long id);

private final UserDaoWithJdbcTemplate userDao;
private final UserHistoryDao userHistoryDao;
private final Connection connection;
void insert(final User user);

public UserService(final Connection connection, final UserDaoWithJdbcTemplate userDao, final UserHistoryDao userHistoryDao) {
this.connection = connection;
this.userDao = userDao;
this.userHistoryDao = userHistoryDao;
}

public User findById(final long id) {
return userDao.findById(connection, id);
}

public void insert(final User user) {
userDao.insert(connection, user);
}

public void changePassword(final long id, final String newPassword, final String createBy) {
try {
connection.setAutoCommit(false);

final var user = findById(id);
user.changePassword(newPassword);
userDao.update(connection, user);
userHistoryDao.log(connection, new UserHistory(user, createBy));

connection.commit();
} catch (RuntimeException | SQLException e) {
handleTransactionFailure(e);
}
}

private void handleTransactionFailure(final Exception e) {
try {
connection.rollback();
throw new DataAccessException(e);
} catch (SQLException ex) {
throw new SQLTransactionRollbackException(ex);
}
}
void changePassword(final long id, final String newPassword, final String createBy);
}
40 changes: 40 additions & 0 deletions app/src/main/java/com/techcourse/service/UserServiceImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.techcourse.service;

import com.techcourse.dao.UserDaoWithJdbcTemplate;
import com.techcourse.dao.UserHistoryDao;
import com.techcourse.domain.User;
import com.techcourse.domain.UserHistory;
import java.util.Optional;

public class UserServiceImpl implements UserService {

private final UserDaoWithJdbcTemplate userDao;
private final UserHistoryDao userHistoryDao;

public UserServiceImpl(final UserDaoWithJdbcTemplate userDao, final UserHistoryDao userHistoryDao) {
this.userDao = userDao;
this.userHistoryDao = userHistoryDao;
}

@Override
public User findById(final long id) {
final Optional<User> user = userDao.findById(id);
if (user.isEmpty()) {
throw new IllegalArgumentException("회원을 찾을 수 없음");
}
return user.get();
}

@Override
public void insert(final User user) {
userDao.insert(user);
}

@Override
public void changePassword(final long id, final String newPassword, final String createBy) {
final var user = findById(id);
user.changePassword(newPassword);
userDao.update(user);
userHistoryDao.log(new UserHistory(user, createBy));
}
}
Loading
Loading