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

[Spring Core] 안금서 미션 제출합니다. #386

Open
wants to merge 90 commits into
base: goldm0ng
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 66 commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
d888ea0
gradle 의존성 추가
goldm0ng Nov 6, 2024
7adbc1c
<Add> 어드민 페이지 응답 구현
goldm0ng Nov 6, 2024
a7e7b1c
<Add> 핵심 도메인 Reservation 추가
goldm0ng Nov 6, 2024
5ffe0d1
<Add> 컨트롤러 ReservationController 추가
goldm0ng Nov 6, 2024
3fce7dd
<Add> 필수 예약 데이터 누락 관련 예외 MissingReservationDataException 추가
goldm0ng Nov 6, 2024
4e5b6c3
<Add> 예약 찾기 관련 예외 NotFoundReservationException 추가
goldm0ng Nov 6, 2024
45a3092
<Add> 에외 관리 관련 GlobalExceptionHandler 추가
goldm0ng Nov 6, 2024
87cd948
<Add> 미션 단계별 테스트 추가
goldm0ng Nov 6, 2024
f2ceebe
<FIX> controller pakage 추가 및 ReservationController 수정
goldm0ng Nov 13, 2024
0ce07cb
<FIX> domain package 추가 및 도메인 클래스 수정
goldm0ng Nov 13, 2024
b80921f
<ADD> dto package 추가 및 예약 관련 DTO 추가
goldm0ng Nov 13, 2024
b5096b7
<DELETE> 유효성 검사 방법 변경에 따른 사용자 정의 예외 클래스 삭제 및 Handler 재구성
goldm0ng Nov 13, 2024
272e633
<ADD> dto 내에서 유효성 검사를 하기 위한 의존성 추가
goldm0ng Nov 13, 2024
e3ce304
<FIX> 외부에서 예외메세지를 전달하는 방식에서 기본 예외 메세지를 가지고 있는 방식으로 변경
goldm0ng Nov 13, 2024
2855044
<ADD> 예외처리 방식 일부 변경에 따른 Reservation에 관한 예외핸들러 추가
goldm0ng Nov 13, 2024
4c61b9a
-
goldm0ng Nov 13, 2024
3262ef2
<FIX> 도메인 필드 내 final 삭제
goldm0ng Nov 13, 2024
8254291
<FIX> Dto 생성자 추가
goldm0ng Nov 13, 2024
b747795
<ADD> 예약 관련 Repository 인터페이스 추가
goldm0ng Nov 13, 2024
19e40f1
<ADD> 메모리 기반 데이터 관리 구현체 추가
goldm0ng Nov 13, 2024
2bf90d0
<ADD> 예약 비즈니스 관련 Service 추가
goldm0ng Nov 13, 2024
51b6b55
<FIX> repository, service 추가에 따른 controller 재구성
goldm0ng Nov 13, 2024
51aadd1
<ADD> Spring jdbc Starter 의존성 추가
goldm0ng Nov 13, 2024
9ee624c
<ADD> DB 설정 추가
goldm0ng Nov 13, 2024
9d1d2a0
<ADD> 테이블 스키마 정의
goldm0ng Nov 13, 2024
8a1f8cd
<FIX> 1,2,3,4 단계 테스트 네이밍 수정
goldm0ng Nov 13, 2024
2a9ee79
<ADD> 5,6,7 단계 테스트 추가
goldm0ng Nov 13, 2024
3012b26
<FIX> 도메인 기본 생성자 추가
goldm0ng Nov 13, 2024
f0156fa
<FIX> 메모리 기반 데이터 저장소에서 @Repository 삭제
goldm0ng Nov 13, 2024
e72a1d9
<ADD> h2 기반 데이터 관리 용도의 Repository 구현체 추가
goldm0ng Nov 13, 2024
4b98968
<FIX> 미션 흐름에 따른 비즈니스 로직 메서드 순서 바꾸기
goldm0ng Nov 13, 2024
8b552a6
<FIX> DTO->Entity 변환 위치 및 로직 수정
goldm0ng Nov 19, 2024
98eeee3
<FIX> Controller와 RestController 분리
goldm0ng Nov 19, 2024
a293899
<FIX> 클래스 범위 수정, 예외 처리 핸들러 추가 및 패키지 구조 조정
goldm0ng Nov 19, 2024
ee1ec84
<ADD> 페이지 렌더링하는 뷰 컨트롤러에 대한 예외처리 분리
goldm0ng Nov 19, 2024
edf05cd
<FIX> 레이어드 아키텍처에 기반한 패키지 구조 조정
goldm0ng Nov 19, 2024
927c74c
<FIX> DTO->Entity 변환 위치 및 로직 수정
goldm0ng Nov 19, 2024
7be63ff
<FIX> Controller와 RestController 분리
goldm0ng Nov 19, 2024
552f755
<FIX> 클래스 범위 수정, 예외 처리 핸들러 추가 및 패키지 구조 조정
goldm0ng Nov 19, 2024
8ede9a7
<ADD> 페이지 렌더링하는 뷰 컨트롤러에 대한 예외처리 분리
goldm0ng Nov 19, 2024
d6d1e9d
<FIX> 레이어드 아키텍처에 기반한 패키지 구조 조정
goldm0ng Nov 19, 2024
fe2f464
<FIX> DTO -> Entity 변환 위치 변경에 따른 수정
goldm0ng Nov 22, 2024
f5d8642
<FIX> 패키지 구조 변경에 따른 수정
goldm0ng Nov 22, 2024
5f71d55
<FIX> DTO를 record 타입으로 변경
goldm0ng Nov 22, 2024
55a2797
<FIX> 자동 정렬
goldm0ng Nov 22, 2024
795a778
<FIX> 메서드 체이닝 적용
goldm0ng Nov 22, 2024
08fa6f4
<FIX> 예외처리 위치 변경에 따른 수정
goldm0ng Nov 22, 2024
4151de6
<FIX> 패키지 구조 수정
goldm0ng Nov 26, 2024
f42cf40
<ADD> Time Table 추가
goldm0ng Nov 26, 2024
1927a32
<FIX> 패키지 구조 조정에 따른 import 수정 사항
goldm0ng Nov 26, 2024
38998be
<ADD> 시간 관리 페이지 뷰 템플릿과 매핑 추가
goldm0ng Nov 26, 2024
c1a3e00
<ADD> 도메인 객체 Time 및 데이터 전송 객체 TimeDto 추가
goldm0ng Nov 26, 2024
d6f862d
<ADD> 인터페이스 TimeRepository 및 Jdbc 활용 구현체 JdbcTimeRepository 추가
goldm0ng Nov 26, 2024
2f0a216
<ADD> 비즈니스 로직을 수행하는 TimeService 추가
goldm0ng Nov 26, 2024
8db1972
<ADD> 시간 추가/조회/삭제 API를 담당하는 TimeController 추가
goldm0ng Nov 26, 2024
a2b40fc
<ADD> 설정한 시간을 찾지 못 했을 때 발생하는 사용자 정의 예외 추가
goldm0ng Nov 26, 2024
d1aa20d
<ADD> TimeController에서 발생하는 모든 예외를 처리하는 예외 핸들러 추가
goldm0ng Nov 26, 2024
a9c87d7
<ADD> 8단계 테스트 추가
goldm0ng Nov 26, 2024
47eabd6
<FIX> 에약 페이지 파일 수정 (templates/new-reservation.html)
goldm0ng Nov 26, 2024
4f8ec4e
<FIX> 테이블 스키마 재정의
goldm0ng Nov 26, 2024
3f36dff
<FIX> 테이블 스키마 재정의 수정
goldm0ng Nov 27, 2024
6f25741
<FIX> 예약 클래스 멤버 변수 time의 타입 String -> Time 으로 수정
goldm0ng Nov 27, 2024
8d0ac6b
<FIX> 예약 데이터 전송 객체 변수 time 타입 String -> Long 으로 수정
goldm0ng Nov 27, 2024
cff2f53
<FIX> 스키마 재정의에 따른 에약 관련 Repository 수정
goldm0ng Nov 27, 2024
0efc638
<FIX> 도메인 객체의 멤버 변수 타입 변경에 따른 Dto -> Entity 변환 로직 수정
goldm0ng Nov 27, 2024
50eb526
<FIX> 자동정렬 적용
goldm0ng Nov 27, 2024
1a5e85c
<ADD> 잘못된 타입으로 값이 들어왔을 때 발생하는 예외처리 추가 - 400 error
goldm0ng Nov 27, 2024
8da0faf
<ADD> 9단계, 10단계 테스트 코드 추가
goldm0ng Nov 27, 2024
b599e17
<FIX> 기존 예외 핸들러에서 공통 예외 분리
goldm0ng Dec 5, 2024
033d792
<FIX> 예약 시간 관련 도메인 및 Dto 이름 변경 (Time -> ReservationTime)
goldm0ng Dec 5, 2024
f7080fd
<DELETE> -
goldm0ng Dec 5, 2024
6a5885b
<ADD> Spring jdbc Starter 의존성 추가
goldm0ng Nov 13, 2024
5712acf
<ADD> DB 설정 추가
goldm0ng Nov 13, 2024
5208497
<ADD> 테이블 스키마 정의
goldm0ng Nov 13, 2024
bbc0aa7
<FIX> 1,2,3,4 단계 테스트 네이밍 수정
goldm0ng Nov 13, 2024
92555ec
<ADD> 5,6,7 단계 테스트 추가
goldm0ng Nov 13, 2024
3157680
<FIX> 도메인 기본 생성자 추가
goldm0ng Nov 13, 2024
03b7b9e
<FIX> 메모리 기반 데이터 저장소에서 @Repository 삭제
goldm0ng Nov 13, 2024
73a68e4
<ADD> h2 기반 데이터 관리 용도의 Repository 구현체 추가
goldm0ng Nov 13, 2024
d3bda44
<FIX> 미션 흐름에 따른 비즈니스 로직 메서드 순서 바꾸기
goldm0ng Nov 13, 2024
0cfa4d4
<FIX> DTO->Entity 변환 위치 및 로직 수정
goldm0ng Nov 19, 2024
1379add
<FIX> 레이어드 아키텍처에 기반한 패키지 구조 조정
goldm0ng Nov 19, 2024
50f9f7d
<FIX> DTO -> Entity 변환 위치 변경에 따른 수정
goldm0ng Nov 22, 2024
7f41fe9
<FIX> 패키지 구조 변경에 따른 수정
goldm0ng Nov 22, 2024
46d524d
<FIX> DTO를 record 타입으로 변경
goldm0ng Nov 22, 2024
66148ce
<FIX> 자동 정렬
goldm0ng Nov 22, 2024
fb00e38
<FIX> 메서드 체이닝 적용
goldm0ng Nov 22, 2024
f29f0c6
<FIX> 예외처리 위치 변경에 따른 수정
goldm0ng Nov 22, 2024
e739292
Merge branch 'goldmong-jdbc' into goldmong-core
goldm0ng Jan 14, 2025
3b1e132
<FIX> lombok 버전 수정
goldm0ng Jan 14, 2025
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
10 changes: 10 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,18 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.rest-assured:rest-assured:5.3.1'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
compileOnly 'org.projectlombok:lombok:1.18.28'
annotationProcessor 'org.projectlombok:lombok:1.18.28'

implementation 'org.springframework.boot:spring-boot-starter-validation'

implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'com.h2database:h2'
}

test {
useJUnitPlatform()
}

21 changes: 21 additions & 0 deletions src/main/java/roomescape/MainPageController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package roomescape;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MainPageController {

@GetMapping("/")
public String showHomePage() {
return "home";
}

@GetMapping("/reservation")
public String showReservationForm() {
return "new-reservation";
}

@GetMapping("/time")
public String showTimeForm() { return "time"; }
}
1 change: 0 additions & 1 deletion src/main/java/roomescape/RoomescapeApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@ public class RoomescapeApplication {
public static void main(String[] args) {
SpringApplication.run(RoomescapeApplication.class, args);
}

}
42 changes: 42 additions & 0 deletions src/main/java/roomescape/business/ReservationService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package roomescape.business;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import roomescape.domain.Reservation;
import roomescape.domain.ReservationTime;
import roomescape.persistence.JdbcReservationRepository;
import roomescape.persistence.JdbcReservationTimeRepository;
import roomescape.presentation.dto.ReservationDto;

import java.util.List;

@Service
@RequiredArgsConstructor
public class ReservationService {

private final JdbcReservationRepository reservationRepository;
private final JdbcReservationTimeRepository timeRepository;

public Reservation addReservation(ReservationDto reservationDto) {
Reservation reservation = convertToReservationEntity(reservationDto);
return reservationRepository.save(reservation);
}

public List<Reservation> checkReservations() {
return reservationRepository.findAll();
}

public void deleteReservation(Long reservationId) {
reservationRepository.delete(reservationId);
}

private Reservation convertToReservationEntity(ReservationDto reservationDto) {
ReservationTime time = convertToTimeEntity(reservationDto);
return new Reservation(null, reservationDto.name(), reservationDto.date(), time);
}

private ReservationTime convertToTimeEntity(ReservationDto reservationDto) {
Long timeId = reservationDto.time();
return timeRepository.findById(timeId);
}
}
34 changes: 34 additions & 0 deletions src/main/java/roomescape/business/ReservationTimeService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package roomescape.business;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import roomescape.domain.ReservationTime;
import roomescape.persistence.JdbcReservationTimeRepository;
import roomescape.presentation.dto.ReservationTimeDto;

import java.util.List;

@Service
@RequiredArgsConstructor
public class ReservationTimeService {

private final JdbcReservationTimeRepository repository;

public ReservationTime addTime(ReservationTimeDto reservationTimeDto) {
ReservationTime time = convertToEntity(reservationTimeDto);
return repository.save(time);
}

public List<ReservationTime> checkTimes() {
return repository.findAll();
}

public void deleteTime(Long timeId) {
repository.delete(timeId);
}

private ReservationTime convertToEntity(ReservationTimeDto reservationTimeDto) {
return new ReservationTime(null, reservationTimeDto.time());
}

}
26 changes: 26 additions & 0 deletions src/main/java/roomescape/domain/Reservation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package roomescape.domain;

import lombok.Getter;

@Getter
public class Reservation {

private Long id;
private String name;
private String date;
private ReservationTime time;

public Reservation() {
}

public Reservation(Long id, String name, String date, ReservationTime time) {
this.id = id;
this.name = name;
this.date = date;
this.time = time;
}

public void setId(Long id) {
this.id = id;
}
}
18 changes: 18 additions & 0 deletions src/main/java/roomescape/domain/ReservationTime.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package roomescape.domain;

import lombok.Getter;

@Getter
public class ReservationTime {

private Long id;
private String time;

public ReservationTime() {
}

public ReservationTime(Long id, String time) {
this.id = id;
this.time = time;
}
}
39 changes: 39 additions & 0 deletions src/main/java/roomescape/exception/GeneralExceptionHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package roomescape.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
@Slf4j
public class GeneralExceptionHandler {

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException e) {
Map<String, String> errors = new HashMap<>();

for (FieldError error : e.getBindingResult().getFieldErrors()) {
errors.put(error.getField(), error.getDefaultMessage());
log.info("validation error on field {} : {}", error.getField(), error.getDefaultMessage());
}

return ResponseEntity.badRequest().body(errors);
}

@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<String> handleInvalidTypeException(HttpMessageNotReadableException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}

@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception e) {
return ResponseEntity.internalServerError().body(e.getMessage());
}
}
16 changes: 16 additions & 0 deletions src/main/java/roomescape/exception/MainPageExceptionHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package roomescape.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import roomescape.MainPageController;

@Slf4j
@ControllerAdvice(assignableTypes = MainPageController.class)
public class MainPageExceptionHandler {
@ExceptionHandler(Exception.class)
public String handleException(Exception e) {
log.error("error: " + e.getMessage());
return "error/500"; //view 렌더링 페이지는 만들지 않음!
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package roomescape.exception;

public class NotFoundReservationException extends RuntimeException {

private static final String NOT_FOUND_RESERVATION_MESSAGE = "예악을 찾을 수 없습니다.";

public NotFoundReservationException() {
super(NOT_FOUND_RESERVATION_MESSAGE);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package roomescape.exception;

public class NotFoundReservationTimeException extends RuntimeException {

private static final String NOT_FOUND_TIME_MESSAGE = "시간을 찾을 수 없습니다.";

public NotFoundReservationTimeException(){
super(NOT_FOUND_TIME_MESSAGE);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package roomescape.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import roomescape.presentation.ReservationController;

@Slf4j
@ControllerAdvice(assignableTypes = ReservationController.class)
public class ReservationExceptionHandler {

@ExceptionHandler(NotFoundReservationException.class)
public ResponseEntity<String> handleNotFoundReservationException(NotFoundReservationException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package roomescape.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import roomescape.presentation.ReservationTimeController;

@Slf4j
@ControllerAdvice(assignableTypes = ReservationTimeController.class)
public class ReservationTimeExceptionHandler {

@ExceptionHandler(NotFoundReservationTimeException.class)
public ResponseEntity<String> handleNotFoundTimeException(NotFoundReservationTimeException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package roomescape.persistence;

import lombok.RequiredArgsConstructor;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import roomescape.domain.Reservation;
import roomescape.domain.ReservationTime;
import roomescape.exception.NotFoundReservationException;

import java.sql.PreparedStatement;
import java.util.List;

@Repository
@RequiredArgsConstructor
public class JdbcReservationRepository implements ReservationRepository {

private final JdbcTemplate jdbcTemplate;

@Override
public Reservation save(Reservation reservation) {
String sql = "insert into reservation (name, date, time_id) values (?,?,?)";

KeyHolder keyHolder = new GeneratedKeyHolder();

jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(sql, new String[]{"id"});
ps.setString(1, reservation.getName());
ps.setString(2, reservation.getDate());
ps.setLong(3, reservation.getTime().getId());
return ps;
}, keyHolder);

Long generatedAutoId = keyHolder.getKey().longValue();
return new Reservation(generatedAutoId, reservation.getName(), reservation.getDate(), reservation.getTime());
}

@Override
public Reservation findById(Long reservationId) {
String sql = "select id, name, date, time_id from reservation where id = ?";

try {
return jdbcTemplate.queryForObject(sql, reservationMapperForFindById(), reservationId);
} catch (EmptyResultDataAccessException e) {
throw new NotFoundReservationException();
}
}

@Override
public List<Reservation> findAll() {
String sql = "select \n" +
" r.id as reservation_id, \n" +
" r.name, \n" +
" r.date, \n" +
" t.id as time_id, \n" +
" t.time as time_value \n" +
"from reservation as r inner join time as t on r.time_id = t.id";

return jdbcTemplate.query(sql, reservationMapperForFindAll());
}

@Override
public void delete(Long reservationId) {
Reservation deletedReservation = this.findById(reservationId);

String sql = "delete from reservation where id = ?";
jdbcTemplate.update(sql, deletedReservation.getId());
}

private RowMapper<Reservation> reservationMapperForFindById() {
return ((rs, rowNum) -> {

ReservationTime time = new ReservationTime(rs.getLong("time_id"), null);

return new Reservation(
rs.getLong("id"),
rs.getString("name"),
rs.getString("date"),
time);
});
}

private RowMapper<Reservation> reservationMapperForFindAll() {
return ((rs, rowNum) -> {

ReservationTime time = new ReservationTime(rs.getLong("time_id"), rs.getString("time_value"));

return new Reservation(
rs.getLong("id"),
rs.getString("name"),
rs.getString("date"),
time
);
});
}
}
Loading