Skip to content

πŸš€ 3단계 - μˆ˜κ°•μ‹ μ²­(DB 적용) #756

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

Open
wants to merge 2 commits into
base: gukin-han
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
42 changes: 42 additions & 0 deletions src/main/java/nextstep/courses/domain/EnrolledStudent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package nextstep.courses.domain;

import java.time.LocalDateTime;

public class EnrolledStudent {

Choose a reason for hiding this comment

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

ꡳ이 Enrolledλ₯Ό 뢙일 μ΄μœ κ°€ μžˆμ„κΉŒμš”?
Studentλ‘œλ§ŒμœΌλ‘œλ„ μΆ©λΆ„νžˆ 도메인 μ„€λͺ…이 κ°€λŠ₯ν•΄ λ³΄μ—¬μ„œμš”~

private Long id;

private String userId;

Choose a reason for hiding this comment

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

객체지ν–₯적으둜 Userλ₯Ό κ°€μ§€κ³  있게 ν•˜λ©΄ μ–΄λ–¨κΉŒμš”?


private Session session;

private LocalDateTime enrolledAt;

public EnrolledStudent(String userId, Session session, LocalDateTime enrolledAt) {
this.userId = userId;
this.session = session;
this.enrolledAt = enrolledAt;
}

public EnrolledStudent(Long id, String userId, Session session, LocalDateTime enrolledAt) {
this.id = id;
this.userId = userId;
this.session = session;
this.enrolledAt = enrolledAt;
}

public Long getId() {
return id;
}

public String getUserId() {
return userId;
}

public Session getSession() {
return session;
}

public LocalDateTime getEnrolledAt() {
return enrolledAt;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package nextstep.courses.domain;

public interface EnrolledStudentRepository {
void save(EnrolledStudent enrolledStudent);
}
22 changes: 0 additions & 22 deletions src/main/java/nextstep/courses/domain/EnrollmentHistory.java

This file was deleted.

This file was deleted.

12 changes: 6 additions & 6 deletions src/main/java/nextstep/courses/domain/Session.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ public class Session {

private Long capacity;

private final List<EnrollmentHistory> enrollments = new ArrayList<>();
private final List<EnrolledStudent> enrolledStudents = new ArrayList<>();


private Session(Long id, LocalDateTime createdAt, LocalDateTime updatedAt, CoverImage coverImage, SessionType sessionType, SessionStatus sessionStatus, Long price, Long capacity) {
public Session(Long id, LocalDateTime createdAt, LocalDateTime updatedAt, CoverImage coverImage, SessionType sessionType, SessionStatus sessionStatus, Long price, Long capacity) {
this.id = id;
this.createdAt = createdAt;
this.updatedAt = updatedAt;
Expand Down Expand Up @@ -76,13 +76,13 @@ public void open() {
this.sessionStatus = SessionStatus.OPEN;
}

public EnrollmentHistory enroll(NsUser user, Long amount, LocalDateTime enrolledAt) {
public EnrolledStudent enroll(NsUser user, Long amount, LocalDateTime enrolledAt) {
validateSessionStatus();
validateSessionPrice(amount);
validateSessionCapacity();

EnrollmentHistory history = new EnrollmentHistory(user, this, enrolledAt);
enrollments.add(history);
EnrolledStudent history = new EnrolledStudent(user.getUserId(), this, enrolledAt);
enrolledStudents.add(history);
return history;
}

Expand All @@ -109,6 +109,6 @@ public Long getId() {
}

private boolean isFull() {
return sessionType.isPaid() && enrollments.size() >= capacity;
return sessionType.isPaid() && enrolledStudents.size() >= capacity;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package nextstep.courses.infrastructure;

import nextstep.courses.domain.EnrolledStudent;
import nextstep.courses.domain.EnrolledStudentRepository;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.stereotype.Repository;

@Repository
public class JdbcEnrolledStudentRepository implements EnrolledStudentRepository {

private final JdbcOperations jdbcTemplate;

public JdbcEnrolledStudentRepository(JdbcOperations jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

@Override
public void save(EnrolledStudent enrolledStudent) {
String sql = "INSERT INTO enrolled_student (session_id, user_id, enrolled_at) VALUES (?, ?, ?)";
jdbcTemplate.update(
sql,
enrolledStudent.getSession().getId(), // session κ°μ²΄μ—μ„œ id 꺼냄

Choose a reason for hiding this comment

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

λ””λ―Έν„°μ˜ 법칙을 μœ„λ°˜ν•œκ²ƒ κ°™μŠ΅λ‹ˆλ‹€.
λ”°λ‘œ Id만 λΉΌλŠ” getterλ₯Ό λ§Œλ“œμ‹œλ©΄ μ–΄λ–¨κΉŒμš”?

enrolledStudent.getId(),
enrolledStudent.getEnrolledAt()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package nextstep.courses.infrastructure;

import nextstep.courses.domain.*;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import java.sql.Timestamp;
import java.time.LocalDateTime;

@Repository
public class JdbcSessionRepository implements SessionRepository {

private final JdbcOperations jdbcTemplate;

public JdbcSessionRepository(JdbcOperations jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

@Override
public Session findById(Long sessionId) {
String sql = "SELECT id, created_at, updated_at, cover_image_size, cover_image_type, cover_image_width, cover_image_height, session_type, session_status, price, capacity FROM session WHERE id = ?";
return jdbcTemplate.queryForObject(sql, sessionRowMapper(), sessionId);
}

private RowMapper<Session> sessionRowMapper() {
return (rs, rowNum) -> {
CoverImage coverImage = new CoverImage(
rs.getInt("cover_image_size"),
ImageType.valueOf(rs.getString("cover_image_type")),
rs.getInt("cover_image_width"),
rs.getInt("cover_image_height")
);
Comment on lines +28 to +33

Choose a reason for hiding this comment

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

CoverImageκ°€ μž¬μ‚¬μš©λ  일이 μ—†μ„κΉŒμš”?
μ •κ·œν™” κ΄€μ μ—μ„œ ν•œλ²ˆ κ³ λ―Όν•΄λ³΄μ…¨μœΌλ©΄ μ’‹κ² μŠ΅λ‹ˆλ‹€.

return new Session(
rs.getLong("id"),
toLocalDateTime(rs.getTimestamp("created_at")),
toLocalDateTime(rs.getTimestamp("updated_at")),
coverImage,
SessionType.valueOf(rs.getString("session_type")),
SessionStatus.valueOf(rs.getString("session_status")),
rs.getLong("price"),
rs.getObject("capacity", Long.class)
);
};
}

private LocalDateTime toLocalDateTime(Timestamp timestamp) {
if (timestamp == null) {
return null;
}
return timestamp.toLocalDateTime();
}

}
14 changes: 7 additions & 7 deletions src/main/java/nextstep/courses/service/EnrollmentService.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package nextstep.courses.service;

import nextstep.common.exception.UserNotFoundException;
import nextstep.courses.domain.EnrollmentHistory;
import nextstep.courses.domain.EnrollmentHistoryRepository;
import nextstep.courses.domain.EnrolledStudent;
import nextstep.courses.domain.EnrolledStudentRepository;
import nextstep.courses.domain.Session;
import nextstep.courses.domain.SessionRepository;
import nextstep.payments.domain.Payment;
Expand All @@ -17,22 +17,22 @@ public class EnrollmentService {
private final SessionRepository sessionRepository;
private final UserRepository userRepository;
private final PaymentRepository paymentRepository;
private final EnrollmentHistoryRepository enrollmentHistoryRepository;
private final EnrolledStudentRepository enrolledStudentRepository;

public EnrollmentService(SessionRepository sessionRepository, UserRepository userRepository, PaymentRepository paymentRepository, EnrollmentHistoryRepository enrollmentHistoryRepository) {
public EnrollmentService(SessionRepository sessionRepository, UserRepository userRepository, PaymentRepository paymentRepository, EnrolledStudentRepository enrolledStudentRepository) {
this.sessionRepository = sessionRepository;
this.userRepository = userRepository;
this.paymentRepository = paymentRepository;
this.enrollmentHistoryRepository = enrollmentHistoryRepository;
this.enrolledStudentRepository = enrolledStudentRepository;
}

public void enroll(Long sessionId, String userId, Long paymentId) {
Session session = sessionRepository.findById(sessionId);
NsUser user = userRepository.findByUserId(userId)
.orElseThrow(UserNotFoundException::new);
Payment payment = paymentRepository.findById(paymentId);
EnrollmentHistory enrollmentHistory = session.enroll(user, payment.getAmount(), LocalDateTime.now());
enrollmentHistoryRepository.save(enrollmentHistory);
EnrolledStudent enrolledStudent = session.enroll(user, payment.getAmount(), LocalDateTime.now());
enrolledStudentRepository.save(enrolledStudent);
}

}
30 changes: 24 additions & 6 deletions src/main/resources/data.sql
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
INSERT INTO ns_user (id, user_id, password, name, email, created_at) values (1, 'javajigi', 'test', 'μžλ°”μ§€κΈ°', '[email protected]', CURRENT_TIMESTAMP());
INSERT INTO ns_user (id, user_id, password, name, email, created_at) values (2, 'sanjigi', 'test', 'μ‚°μ§€κΈ°', '[email protected]', CURRENT_TIMESTAMP());
INSERT INTO ns_user (id, user_id, password, name, email, created_at)
values (1, 'javajigi', 'test', 'μžλ°”μ§€κΈ°', '[email protected]', CURRENT_TIMESTAMP());
INSERT INTO ns_user (id, user_id, password, name, email, created_at)
values (2, 'sanjigi', 'test', 'μ‚°μ§€κΈ°', '[email protected]', CURRENT_TIMESTAMP());

INSERT INTO question (id, writer_id, title, contents, created_at, deleted) VALUES (1, 1, 'κ΅­λ‚΄μ—μ„œ Ruby on Rails와 Playκ°€ ν™œμ„±ν™”λ˜κΈ° νž˜λ“  μ΄μœ λŠ” 뭘까?', 'Ruby on Rails(μ΄ν•˜ RoR)λŠ” 2006λ…„ μ¦ˆμŒμ— 정말 뜨겁게 λ‹¬μ•„μ˜¬λžλ‹€κ°€ 금방 가라 μ•‰μ•˜λ‹€. Play ν”„λ ˆμž„μ›Œν¬λŠ” 정말 ν•œ μˆœκ°„ μž μ‹œ λˆˆμ— λœ¨μ΄λ‹€κ°€ 사라져 버렸닀. RoRκ³Ό Play 기반으둜 κ°œλ°œμ„ 해보면 정말 생산성이 λ†’μœΌλ©°, μ›Ή ν”„λ‘œκ·Έλž˜λ°μ΄ μž¬λ―ΈμžˆκΈ°κΉŒμ§€ ν•˜λ‹€. Spring MVC + JPA(Hibernate) 기반으둜 μ§„ν–‰ν•˜λ©΄ μ„€μ •ν•  뢀뢄도 많고, 기본으둜 μ§€μ›ν•˜μ§€ μ•ŠλŠ” κΈ°λŠ₯도 λ§Žμ•„ RoRκ³Ό Playμ—μ„œ 기본적으둜 μ§€μ›ν•˜λŠ” κΈ°λŠ₯을 μ„œλΉ„μŠ€ν•˜λ €λ©΄ 좔가적인 개발이 ν•„μš”ν•˜λ‹€.', CURRENT_TIMESTAMP(), false);
INSERT INTO question (id, writer_id, title, contents, created_at, deleted)
VALUES (1, 1, 'κ΅­λ‚΄μ—μ„œ Ruby on Rails와 Playκ°€ ν™œμ„±ν™”λ˜κΈ° νž˜λ“  μ΄μœ λŠ” 뭘까?',
'Ruby on Rails(μ΄ν•˜ RoR)λŠ” 2006λ…„ μ¦ˆμŒμ— 정말 뜨겁게 λ‹¬μ•„μ˜¬λžλ‹€κ°€ 금방 가라 μ•‰μ•˜λ‹€. Play ν”„λ ˆμž„μ›Œν¬λŠ” 정말 ν•œ μˆœκ°„ μž μ‹œ λˆˆμ— λœ¨μ΄λ‹€κ°€ 사라져 버렸닀. RoRκ³Ό Play 기반으둜 κ°œλ°œμ„ 해보면 정말 생산성이 λ†’μœΌλ©°, μ›Ή ν”„λ‘œκ·Έλž˜λ°μ΄ μž¬λ―ΈμžˆκΈ°κΉŒμ§€ ν•˜λ‹€. Spring MVC + JPA(Hibernate) 기반으둜 μ§„ν–‰ν•˜λ©΄ μ„€μ •ν•  뢀뢄도 많고, 기본으둜 μ§€μ›ν•˜μ§€ μ•ŠλŠ” κΈ°λŠ₯도 λ§Žμ•„ RoRκ³Ό Playμ—μ„œ 기본적으둜 μ§€μ›ν•˜λŠ” κΈ°λŠ₯을 μ„œλΉ„μŠ€ν•˜λ €λ©΄ 좔가적인 개발이 ν•„μš”ν•˜λ‹€.',
CURRENT_TIMESTAMP(), false);

INSERT INTO answer (writer_id, contents, created_at, question_id, deleted) VALUES (1, 'http://underscorejs.org/docs/underscore.html Underscore.js κ°•μΆ”ν•©λ‹ˆλ‹€! 쓸일도 많고, μ½”λ“œλ„ κΈΈμ§€ μ•Šκ³ , μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ μ–Έμ–΄λ‚˜ κΈ°λ³Έ APIλ₯Ό λ³΄μ™„ν•˜λŠ” κΈ°λŠ₯듀이라 μžλ°”μŠ€ν¬λ¦½νŠΈ 이해에 도움이 λ©λ‹ˆλ‹€. 무엇보닀 라이브러리 μžμ²΄κ°€ μ•„μ£Ό μœ μš©ν•©λ‹ˆλ‹€.', CURRENT_TIMESTAMP(), 1, false);
INSERT INTO answer (writer_id, contents, created_at, question_id, deleted)
VALUES (1,
'http://underscorejs.org/docs/underscore.html Underscore.js κ°•μΆ”ν•©λ‹ˆλ‹€! 쓸일도 많고, μ½”λ“œλ„ κΈΈμ§€ μ•Šκ³ , μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ μ–Έμ–΄λ‚˜ κΈ°λ³Έ APIλ₯Ό λ³΄μ™„ν•˜λŠ” κΈ°λŠ₯듀이라 μžλ°”μŠ€ν¬λ¦½νŠΈ 이해에 도움이 λ©λ‹ˆλ‹€. 무엇보닀 라이브러리 μžμ²΄κ°€ μ•„μ£Ό μœ μš©ν•©λ‹ˆλ‹€.',
CURRENT_TIMESTAMP(), 1, false);

INSERT INTO answer (writer_id, contents, created_at, question_id, deleted) VALUES (2, 'μ–Έλ”μŠ€μ½”μ–΄ κ°•λ ₯ μΆ”μ²œλ“œλ €μš”. λ‹€λ§Œ μ΅œμ‹  버전을 κ³΅λΆ€ν•˜λŠ” κ²ƒλ³΄λ‹€λŠ” 0.10.0 버전뢀터 λ³΄λŠ”κ²Œ 더 μ’‹λ”κ΅°μš”. μ½”λ“œμ˜ λ³€μ²œμ‚¬λ„ μ•Œ 수 있고, μ΅œμ ν™”λ˜μ§€ μ•Šμ€ μ½”λ“œλ“€μ΄ κΈ°λŠ₯은 κ·ΈλŒ€λ‘œ 두고 μ΅œμ ν™”λ˜μ–΄ κ°€λŠ” κ±Έ 보면 μž¬λ―Έκ°€ μžˆμŠ΅λ‹ˆλ‹€ :)', CURRENT_TIMESTAMP(), 1, false);
INSERT INTO answer (writer_id, contents, created_at, question_id, deleted)
VALUES (2,
'μ–Έλ”μŠ€μ½”μ–΄ κ°•λ ₯ μΆ”μ²œλ“œλ €μš”. λ‹€λ§Œ μ΅œμ‹  버전을 κ³΅λΆ€ν•˜λŠ” κ²ƒλ³΄λ‹€λŠ” 0.10.0 버전뢀터 λ³΄λŠ”κ²Œ 더 μ’‹λ”κ΅°μš”. μ½”λ“œμ˜ λ³€μ²œμ‚¬λ„ μ•Œ 수 있고, μ΅œμ ν™”λ˜μ§€ μ•Šμ€ μ½”λ“œλ“€μ΄ κΈ°λŠ₯은 κ·ΈλŒ€λ‘œ 두고 μ΅œμ ν™”λ˜μ–΄ κ°€λŠ” κ±Έ 보면 μž¬λ―Έκ°€ μžˆμŠ΅λ‹ˆλ‹€ :)',
CURRENT_TIMESTAMP(), 1, false);

INSERT INTO question (id, writer_id, title, contents, created_at, deleted) VALUES (2, 2, 'runtime 에 reflect λ°œλ™ 주체 객체가 λ­”μ§€ μ•Œ 방법이 μžˆμ„κΉŒμš”?', '섀계λ₯Ό ν¬ν•œν•˜κ²Œ ν•˜λŠ” λ°”λžŒμ— 꼬인 λ¬Έμ œκ°™κΈ΄ ν•©λ‹ˆλ‹€λ§Œ. μ—¬μ­™μŠ΅λ‹ˆλ‹€. 상황은 mybatis select 싀행될 μ‹œμ— return object 의 getter κ°€ ν˜ΈμΆœλ˜λ©΄μ„œμΈλ°μš”. getter μ•ˆμ— λ‹€λ₯Έ property 에 μ˜μ‘΄μ€‘μΈ μ½”λ“œκ°€ μ‚½μž…λ˜μ–΄ μžˆμ–΄μ„œ, λ§Œμ•½ λ‹€λ₯Έ mybatis select ꡬ문에 ν•΄λ‹Ή property κ°€ μ—†λ‹€λ©΄ exception 이 λ°œμƒν•˜κ²Œ λ©λ‹ˆλ‹€.', CURRENT_TIMESTAMP(), false);
INSERT INTO question (id, writer_id, title, contents, created_at, deleted)
VALUES (2, 2, 'runtime 에 reflect λ°œλ™ 주체 객체가 λ­”μ§€ μ•Œ 방법이 μžˆμ„κΉŒμš”?',
'섀계λ₯Ό ν¬ν•œν•˜κ²Œ ν•˜λŠ” λ°”λžŒμ— 꼬인 λ¬Έμ œκ°™κΈ΄ ν•©λ‹ˆλ‹€λ§Œ. μ—¬μ­™μŠ΅λ‹ˆλ‹€. 상황은 mybatis select 싀행될 μ‹œμ— return object 의 getter κ°€ ν˜ΈμΆœλ˜λ©΄μ„œμΈλ°μš”. getter μ•ˆμ— λ‹€λ₯Έ property 에 μ˜μ‘΄μ€‘μΈ μ½”λ“œκ°€ μ‚½μž…λ˜μ–΄ μžˆμ–΄μ„œ, λ§Œμ•½ λ‹€λ₯Έ mybatis select ꡬ문에 ν•΄λ‹Ή property κ°€ μ—†λ‹€λ©΄ exception 이 λ°œμƒν•˜κ²Œ λ©λ‹ˆλ‹€.',
CURRENT_TIMESTAMP(), false);

insert into session (id, created_at, updated_at, cover_image_size, cover_image_type, cover_image_width,
cover_image_height, session_type, session_status, price, capacity)
values (1, now(), now(), 500000, 'JPG', 450, 300, 'PAID', 'OPEN', 10000, 100);
88 changes: 59 additions & 29 deletions src/main/resources/schema.sql
Original file line number Diff line number Diff line change
@@ -1,50 +1,80 @@
create table course (
id bigint generated by default as identity,
title varchar(255) not null,
creator_id bigint not null,
created_at timestamp not null,
create table course
(
id bigint generated by default as identity,
title varchar(255) not null,
creator_id bigint not null,
created_at timestamp not null,
updated_at timestamp,
primary key (id)
);

create table ns_user (
id bigint generated by default as identity,
user_id varchar(20) not null,
password varchar(20) not null,
name varchar(20) not null,
email varchar(50),
created_at timestamp not null,
create table ns_user
(
id bigint generated by default as identity,
user_id varchar(20) not null,
password varchar(20) not null,
name varchar(20) not null,
email varchar(50),
created_at timestamp not null,
updated_at timestamp,
primary key (id)
);

create table question (
id bigint generated by default as identity,
created_at timestamp not null,
create table question
(
id bigint generated by default as identity,
created_at timestamp not null,
updated_at timestamp,
contents clob,
deleted boolean not null,
title varchar(100) not null,
writer_id bigint,
deleted boolean not null,
title varchar(100) not null,
writer_id bigint,
primary key (id)
);

create table answer (
id bigint generated by default as identity,
created_at timestamp not null,
updated_at timestamp,
create table answer
(
id bigint generated by default as identity,
created_at timestamp not null,
updated_at timestamp,
contents clob,
deleted boolean not null,
deleted boolean not null,
question_id bigint,
writer_id bigint,
writer_id bigint,
primary key (id)
);

create table delete_history (
id bigint not null,
content_id bigint,
content_type varchar(255),
created_date timestamp,
create table delete_history
(
id bigint not null,
content_id bigint,
content_type varchar(255),
created_date timestamp,
deleted_by_id bigint,
primary key (id)
);

create table session
(
id bigint generated by default as identity,
created_at timestamp not null,
updated_at timestamp,
cover_image_size int not null,
cover_image_type varchar(20) not null,
cover_image_width int not null,
cover_image_height int not null,
session_type varchar(20) not null,
session_status varchar(20) not null,
price bigint not null,
capacity bigint,
primary key (id)
);

create table enrolled_student
(
id bigint generated by default as identity,
session_id bigint not null,
user_id varchar(20) not null,
enrolled_at timestamp not null,
primary key (id)
);
Loading