Skip to content
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
39413ad
refactor: 한글 경로 인식문제 해결
KJunseo Sep 18, 2021
3cafb13
feat: findAll() 구현
KJunseo Sep 18, 2021
26a31be
feat: findByAccount 구현
KJunseo Sep 18, 2021
ce54a46
feat: update 구현
KJunseo Sep 18, 2021
161a287
docs: 초기 todo 문서화
KJunseo Sep 19, 2021
7256776
feat: property 파일로 db 연결 정보 관리
KJunseo Sep 19, 2021
c642a8a
refactor: update, insert 메서드 분리
KJunseo Sep 20, 2021
1ab140d
refactor: update, insert 클래스 분리
KJunseo Sep 20, 2021
355eef2
refactor: update, insert 클래스 추상 클래스로 중복 추출
KJunseo Sep 20, 2021
2978eb9
refactor: select 클래스 분리
KJunseo Sep 20, 2021
759e854
refactor: JdbcTemplate에 SelectJdbcTemplate 합치기
KJunseo Sep 20, 2021
d3e886f
refactor: 사용하지 않는 클래스 제거 & 패키지 구조 정리
KJunseo Sep 20, 2021
547ecfa
refactor: SQLException을 Unchecked Exception으로 관리
KJunseo Sep 20, 2021
5fb5494
refactor: RowMapper 제네릭 사용
KJunseo Sep 20, 2021
ba0b062
refactor: PreparedStatementSetter 가변인자 사용
KJunseo Sep 20, 2021
1c6dd47
test: findAll 검증 추가
KJunseo Sep 20, 2021
0f35ef3
feat: 이메일로 조회 추가
KJunseo Sep 20, 2021
8d9e6e8
refactor: 빌더 패턴 적용
KJunseo Sep 20, 2021
583ce68
refactor: 리스트 반환 메서드에 set value 로직 추가
KJunseo Sep 20, 2021
324df84
refactor: JdbcTemplate 중복 리팩토링
KJunseo Sep 20, 2021
89764bf
refactor: DatabasePopulatorUtils 리팩토링
KJunseo Sep 20, 2021
4baf362
refactor: InMemoryRepository 대신 UserDao 사용
KJunseo Sep 21, 2021
41544f7
refactor: 어색한 테스트 제거
KJunseo Sep 21, 2021
7727116
refactor: 업데이트 시 executeUpdate() 값 반환
KJunseo Sep 21, 2021
635aab0
refactor: 불필요한 query 메서드 줄이기
KJunseo Sep 21, 2021
242709c
test: jdbcTemplate 테스트 추가
KJunseo Sep 24, 2021
3f5d0f2
refactor: 특정 id값 주입 제거
KJunseo Sep 24, 2021
45e4a7e
test: SQLException 발생시 commit 되지 않음
KJunseo Sep 24, 2021
08434e1
refactor: PreparedStatementSetter 구현체 제거
KJunseo Sep 25, 2021
b69f10b
refactor: 간단하게 userDao 생성자 주입받기
KJunseo Sep 26, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,13 @@
# jwp-dashboard-jdbc

## TODO
- [x] property 파일로 db 연결 정보 관리
- [x] update, insert 메서드 분리
- [x] UpdateJdbcTemplate, InsertJdbcTemplate 클래스 분리
- [x] UpdateJdbcTemplate, InsertJdbcTemplate 중복 추상클래스(JdbcTemplate)로 제거
- [x] SelectJdbcTemplate 클래스 분리
- [x] JdbcTemplate에 SelectJdbcTemplate 합치기
- [x] mapRow, setValues 인터페이스 분리
- [x] SQLException Unchecked Exception으로 관리
- [x] RowMapper 제네릭 사용
- [x] PreparedStatementSetter 가변인자 사용
2 changes: 2 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ dependencies {

implementation 'com.h2database:h2:1.4.200'

testImplementation 'org.mockito:mockito-core:3.12.4'

testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.3'
testImplementation 'org.mockito:mockito-core:3.12.3'
testImplementation 'org.assertj:assertj-core:3.20.2'
Expand Down
27 changes: 0 additions & 27 deletions app/src/main/java/com/techcourse/config/DataSourceConfig.java

This file was deleted.

29 changes: 17 additions & 12 deletions app/src/main/java/com/techcourse/controller/LoginController.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.techcourse.controller;

import com.techcourse.dao.UserDao;
import com.techcourse.domain.User;
import com.techcourse.repository.InMemoryUserRepository;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import nextstep.jdbc.datasource.DataSourceConfig;
import nextstep.jdbc.exception.DataAccessException;
import nextstep.mvc.view.JspView;
import nextstep.mvc.view.ModelAndView;
import nextstep.web.annotation.Controller;
Expand All @@ -18,14 +21,16 @@ public class LoginController {

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

private final UserDao userDao = new UserDao(DataSourceConfig.getInstance());

Choose a reason for hiding this comment

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

필드 주입도 문제가 없겠지만. @Inject 를 통한 생성자 주입도 고민해보면 좋을 것 같습니다.
저도 이부분은 명확하지는 않지만 저는 ControllerScanner에서 @Inject@Repository 를 활용하여 주입하도록 하였습니다. 한 번 고민해보시고 이부분도 의견 나누면 좋을 것 같아여


@RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView view(HttpServletRequest request, HttpServletResponse response) {
return UserSession.getUserFrom(request.getSession())
.map(user -> {
log.info("logged in {}", user.getAccount());
return redirect("/index.jsp");
})
.orElse(new ModelAndView(new JspView("/login.jsp")));
.map(user -> {
log.info("logged in {}", user.getAccount());
return redirect("/index.jsp");
})
.orElse(new ModelAndView(new JspView("/login.jsp")));
}

@RequestMapping(value = "/login", method = RequestMethod.POST)
Expand All @@ -34,12 +39,12 @@ public ModelAndView login(HttpServletRequest request, HttpServletResponse respon
return redirect("/index.jsp");
}

return InMemoryUserRepository.findByAccount(request.getParameter("account"))
.map(user -> {
log.info("User : {}", user);
return login(request, user);
})
.orElse(redirect("/401.jsp"));
try {
User user = userDao.findByAccount(request.getParameter("account"));
return login(request, user);
} catch (DataAccessException e) {
return redirect("/401.jsp");
}
}

private ModelAndView login(HttpServletRequest request, User user) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.techcourse.controller;

import com.techcourse.dao.UserDao;
import com.techcourse.domain.User;
import com.techcourse.repository.InMemoryUserRepository;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import nextstep.jdbc.datasource.DataSourceConfig;
import nextstep.mvc.view.JspView;
import nextstep.mvc.view.ModelAndView;
import nextstep.web.annotation.Controller;
Expand All @@ -13,13 +15,16 @@
@Controller
public class RegisterController {

private final UserDao userDao = new UserDao(DataSourceConfig.getInstance());

@RequestMapping(value = "/register", method = RequestMethod.POST)
public ModelAndView register(HttpServletRequest request, HttpServletResponse response) {
final User user = new User(2,
final User user = new User(
request.getParameter("account"),
request.getParameter("password"),
request.getParameter("email"));
InMemoryUserRepository.save(user);

userDao.insert(user);

return new ModelAndView(new JspView("redirect:/index.jsp"));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.techcourse.controller;

import com.techcourse.dao.UserDao;
import com.techcourse.domain.User;
import com.techcourse.repository.InMemoryUserRepository;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import nextstep.jdbc.datasource.DataSourceConfig;
import nextstep.mvc.view.JsonView;
import nextstep.mvc.view.ModelAndView;
import nextstep.web.annotation.Controller;
Expand All @@ -17,14 +19,15 @@ public class UserController {

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

private final UserDao userDao = new UserDao(DataSourceConfig.getInstance());

@RequestMapping(value = "/api/user", method = RequestMethod.GET)
public ModelAndView show(HttpServletRequest request, HttpServletResponse response) {
final String account = request.getParameter("account");
log.debug("user id : {}", account);

final ModelAndView modelAndView = new ModelAndView(new JsonView());
final User user = InMemoryUserRepository.findByAccount(account)
.orElseThrow();
final User user = userDao.findByAccount(account);

modelAndView.addObject("user", user);
return modelAndView;
Expand Down
114 changes: 27 additions & 87 deletions app/src/main/java/com/techcourse/dao/UserDao.java
Original file line number Diff line number Diff line change
@@ -1,116 +1,56 @@
package com.techcourse.dao;

import java.util.List;
import javax.sql.DataSource;

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 nextstep.jdbc.JdbcTemplate;
import nextstep.jdbc.RowMapper;

public class UserDao {

private static final Logger log = LoggerFactory.getLogger(UserDao.class);
private static final RowMapper<User> USER_ROW_MAPPER =
resultSet -> new User(
resultSet.getLong("id"),
resultSet.getString("account"),
resultSet.getString("password"),
resultSet.getString("email")
);

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) {}
}
jdbcTemplate.update(sql, user.getAccount(), user.getPassword(), user.getEmail());
}

public void update(User user) {
// todo
final String 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 String sql = "select * from users";
return jdbcTemplate.query(sql, USER_ROW_MAPPER);
}

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) {}
}
return jdbcTemplate.queryForObject(sql, USER_ROW_MAPPER, id);
}

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

public User findByEmail(String email) {
final String sql = "select id, account, password, email from users where email = ?";
return jdbcTemplate.queryForObject(sql, USER_ROW_MAPPER, email);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.techcourse.support.context;

import com.techcourse.config.DataSourceConfig;
import nextstep.jdbc.datasource.DataSourceConfig;
import com.techcourse.support.jdbc.init.DatabasePopulatorUtils;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,47 +1,41 @@
package com.techcourse.support.jdbc.init;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;

import nextstep.jdbc.exception.DataAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DatabasePopulatorUtils {

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

public static void execute(DataSource dataSource) {
Connection connection = null;
Statement statement = null;
try {
final URL url = DatabasePopulatorUtils.class.getClassLoader().getResource("schema.sql");
final File file = new File(url.getFile());
final String sql = Files.readString(file.toPath());
connection = dataSource.getConnection();
statement = connection.createStatement();
try (Connection conn = dataSource.getConnection();
Statement statement = conn.createStatement()) {
final String sql = getInitSchema();
statement.execute(sql);
} catch (NullPointerException | IOException | SQLException e) {
} catch (SQLException e) {
throw new DataAccessException(e.getMessage());
} catch (URISyntaxException | IOException e) {
Comment on lines +23 to +29

Choose a reason for hiding this comment

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

기본적으로 제공되는 코드도 리팩토링 하셨군요 👍

log.error(e.getMessage(), e);
} finally {
try {
if (statement != null) {
statement.close();
}
} catch (SQLException ignored) {}

try {
if (connection != null) {
connection.close();
}
} catch (SQLException ignored) {}
}
}

private static String getInitSchema() throws URISyntaxException, IOException {
final URL url = DatabasePopulatorUtils.class.getClassLoader().getResource("schema.sql");
final File file = Paths.get(url.toURI()).toFile();
return Files.readString(file.toPath());
}

private DatabasePopulatorUtils() {}
}
3 changes: 3 additions & 0 deletions app/src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
datasource.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;
datasource.username=
datasource.password=
Comment on lines +1 to +3

Choose a reason for hiding this comment

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

오 application.properties로 설정할 수 있도록 구현하셨네요. 좋은 아이디어인것 같습니다

Loading