Skip to content

Commit

Permalink
[JDBC 라이브러리 구현하기 - 1, 2단계] 다니(이다은) 미션 제출합니다. (#19)
Browse files Browse the repository at this point in the history
* docs: README.md 작성

* feat: UserDao 구현

* docs: README.md 작성

* feat: 메소드 추출

* feat: 클래스 추출

* feat: 템플릿 메소드 패턴 적용, 도메인 의존도 제거

* feat: 클래스 추출

* feat: 템플릿 메소드 패턴 적용

* feat: 불필요한 mapRow() 제거

* refactor: try-with-resources 적용

* refactor: RowMapper 인터페이스에 제네릭 사용

* refactor: JdbcTemplate 추상 클래스 -> JdbcTemplate 클래스 변경

* refactor: PreparedStatement 인터페이스에 가변인자 사용

* refactor: executeQuery() 삭제

* docs: README.md 체크

* chore: JaCoCo 설정 추가

* refactor: try-with-resources 적용

* refactor: getUser() -> createUser() 변경

* refactor: query()에 가변인자 추가

* refactor: 부생성자 사용

* test: JdbcTemplate 단위 테스트 작성
  • Loading branch information
da-nyee authored Sep 30, 2021
1 parent eef22fd commit 694b9ba
Show file tree
Hide file tree
Showing 26 changed files with 555 additions and 191 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,6 @@ gen
build

/tomcat.8080/

### JaCoCo ###
app/jacoco
37 changes: 36 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,36 @@
# jwp-dashboard-jdbc
# JDBC 라이브러리 구현하기

<br/>

## JDBC 라이브러리 구현하기

- 웹 서비스를 운영하려면 `데이터 영속성`이 있어야 함
- Java 진영에서는 어플리케이션의 DB 관련 처리를 위해 JDBC API 제공

<br/>

- [x] `UserDao` 구현 👉 `UserDaoTest` 활용하여 진행
- [x] `JdbcTemplate` 구현 👉 중복을 제거하기 위한 라이브러리

<br/>

## 리팩토링

- [x] 메소드 추출
- createQueryForInsert(), createQueryForUpdate()
- setValuesForInsert(User, PreparedStatement), setValuesForUpdate(User, PreparedStatement)
- [x] 클래스 추출
- `InsertJdbcTemplate`, `UpdateJdbcTemplate`
- [x] 템플릿 메소드 패턴 적용
- `JdbcTemplate` (abstract)
- [x] 도메인 의존도 제거
- [x] 클래스 추출
- `SelectJdbcTemplate`
- [x] 템플릿 메소드 패턴 적용
- `JdbcTemplate` (abstract)
- [x] 불필요한 mapRow() 제거
- `PreparedStatementSetter` (interface), `RowMapper` (interface)
- [x] 라이브러리 확장
- `RowMapper` (interface)에 제네릭 사용
- `JdbcTemplate` (abstract) -> `JdbcTemplate`
- `PreparedStatementSetter` (interface)에 가변인자 사용
16 changes: 16 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
id 'application'
id 'org.sonarqube' version '3.3'
id 'idea'
id 'jacoco'
}

application {
Expand Down Expand Up @@ -47,6 +48,20 @@ dependencies {

tasks.named('test') {
useJUnitPlatform()

finalizedBy(jacocoTestReport)
}

jacoco {
toolVersion = "0.8.5"
}

jacocoTestReport {
reports {
xml.enabled true

xml.destination(new File("jacoco/jacoco.xml"))
}
}

sonarqube {
Expand All @@ -55,5 +70,6 @@ sonarqube {
property "sonar.projectKey", "woowacourse_jwp-dashboard-jdbc"
property "sonar.organization", "woowacourse"
property "sonar.host.url", "https://sonarcloud.io"
property "sonar.coverage.jacoco.xmlReportPaths", "jacoco/jacoco.xml"
}
}
19 changes: 11 additions & 8 deletions app/src/main/java/com/techcourse/config/DataSourceConfig.java
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
package com.techcourse.config;

import org.h2.jdbcx.JdbcDataSource;

import java.util.Objects;
import javax.sql.DataSource;
import org.h2.jdbcx.JdbcDataSource;

public class DataSourceConfig {

private static javax.sql.DataSource INSTANCE;
private static DataSource instance;

public static javax.sql.DataSource getInstance() {
if (Objects.isNull(INSTANCE)) {
INSTANCE = createJdbcDataSource();
public static DataSource getInstance() {
if (Objects.isNull(instance)) {
instance = createJdbcDataSource();
}
return INSTANCE;
return instance;
}

private static JdbcDataSource createJdbcDataSource() {
final JdbcDataSource jdbcDataSource = new JdbcDataSource();

jdbcDataSource.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;");
jdbcDataSource.setUser("");
jdbcDataSource.setPassword("");

return jdbcDataSource;
}

private DataSourceConfig() {}
private DataSourceConfig() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class RegisterController {

@RequestMapping(value = "/register", method = RequestMethod.POST)
public ModelAndView register(HttpServletRequest request, HttpServletResponse response) {
final User user = new User(2,
final User user = new User(2L,
request.getParameter("account"),
request.getParameter("password"),
request.getParameter("email"));
Expand Down
110 changes: 22 additions & 88 deletions app/src/main/java/com/techcourse/dao/UserDao.java
Original file line number Diff line number Diff line change
@@ -1,116 +1,50 @@
package com.techcourse.dao;

import com.techcourse.domain.User;
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 javax.sql.DataSource;
import nextstep.jdbc.JdbcTemplate;

public class UserDao {

private static final Logger log = LoggerFactory.getLogger(UserDao.class);

private final DataSource dataSource;
private final JdbcTemplate jdbcTemplate;

public UserDao(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplate = new JdbcTemplate(dataSource);
}

public void insert(User user) {
final String 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(User user) {
// todo
String sql = "update users set password = ? where id = ?";
jdbcTemplate.update(sql, user.getPassword(), user.getId());
}

public List<User> findAll() {
// todo
return null;
String sql = "select id, account, password, email from users";
return jdbcTemplate.query(sql, this::createUser);
}

public User findById(Long id) {
final String 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, this::createUser, id);
}

public User findByAccount(String account) {
// todo
return null;
String sql = "select id, account, password, email from users where account = ?";
return jdbcTemplate.queryForObject(sql, this::createUser, account);
}

private User createUser(ResultSet rs) throws SQLException {
return new User(
rs.getLong("id"),
rs.getString("account"),
rs.getString("password"),
rs.getString("email"));
}
}
22 changes: 10 additions & 12 deletions app/src/main/java/com/techcourse/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@

public class User {

private Long id;
private final Long id;
private final String account;
private String password;
private final String email;

public User(long id, String account, String password, String email) {
this.id = id;
this.account = account;
this.password = password;
this.email = email;
public User(String account, String password, String email) {
this(null, account, password, email);
}

public User(String account, String password, String email) {
public User(Long id, String account, String password, String email) {
this.id = id;
this.account = account;
this.password = password;
this.email = email;
Expand Down Expand Up @@ -47,10 +45,10 @@ public String getPassword() {
@Override
public String toString() {
return "User{" +
"id=" + id +
", account='" + account + '\'' +
", email='" + email + '\'' +
", password='" + password + '\'' +
'}';
"id=" + id +
", account='" + account + '\'' +
", email='" + email + '\'' +
", password='" + password + '\'' +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class InMemoryUserRepository {
private static final Map<String, User> database = new ConcurrentHashMap<>();

static {
final User user = new User(1, "gugu", "password", "hkkang@woowahan.com");
final User user = new User(1L, "gugu", "password", "hkkang@woowahan.com");
database.put(user.getAccount(), user);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.techcourse.support.context;

import com.techcourse.config.DataSourceConfig;
import com.techcourse.support.jdbc.init.DatabasePopulatorUtils;
import com.techcourse.support.jdbc.init.DatabasePopulatingUtils;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.annotation.WebListener;
Expand All @@ -11,6 +11,6 @@ public class ContextLoaderListener implements ServletContextListener {

@Override
public void contextInitialized(ServletContextEvent sce) {
DatabasePopulatorUtils.execute(DataSourceConfig.getInstance());
DatabasePopulatingUtils.execute(DataSourceConfig.getInstance());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.techcourse.support.jdbc.init;

import java.io.File;
import java.net.URL;
import java.nio.file.Files;
import java.sql.Connection;
import java.sql.Statement;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DatabasePopulatingUtils {

private static final Logger LOG = LoggerFactory.getLogger(DatabasePopulatingUtils.class);

private DatabasePopulatingUtils() {
}

public static void execute(DataSource dataSource) {
try (
Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement()
) {
final URL url = DatabasePopulatingUtils.class
.getClassLoader()
.getResource("schema.sql");
final File file = new File(url.getFile());
final String sql = Files.readString(file.toPath());

statement.execute(sql);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
}
}
Loading

0 comments on commit 694b9ba

Please sign in to comment.