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] 이동호 미션 제출합니다. #264

Open
wants to merge 21 commits into
base: plusultracode
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
06583e5
Docs: readme 작성
PlusUltraCode May 12, 2024
fbdc5c1
feat: 1단계 화면 추가
PlusUltraCode May 12, 2024
0c9f3db
feat: 2단계 예약 조회 추가
PlusUltraCode May 12, 2024
2c704f1
feat: 3단계 예약 추가/취소 추가
PlusUltraCode May 12, 2024
6443dcd
feat: 4단계 예외처리 추가
PlusUltraCode May 12, 2024
2207bf3
Update README.md
PlusUltraCode May 12, 2024
1f39026
Merge remote-tracking branch 'origin/main'
PlusUltraCode May 13, 2024
e903bef
refactor: 모든코드 리펙토링
PlusUltraCode May 19, 2024
098b99c
feat : 6단계 gradle, schema, DB 설정 완료
PlusUltraCode May 20, 2024
6cb8adc
feat : 6단계 데이터 조회 완료
PlusUltraCode May 20, 2024
cf79545
feat : 7단계 데이터 추가/삭제 완료
PlusUltraCode May 20, 2024
a5aa063
Update README.md
PlusUltraCode May 20, 2024
1f92290
feat : DAO => ReservationRepository 및 Impl 로 대체 + Serivce 객체 구현
PlusUltraCode May 26, 2024
6ea0ac4
feat : KeyHolder 반영 완료.
PlusUltraCode May 26, 2024
89ae934
refractor : 리펙토링 완료.
PlusUltraCode May 26, 2024
9f0e681
Merge remote-tracking branch 'origin/main2' into main2
PlusUltraCode May 26, 2024
90ea520
feat : 8단계 시간관리 완료
PlusUltraCode May 26, 2024
7e002f3
feat : 9 완료 및 10 계층화 완료
PlusUltraCode May 27, 2024
0be43a7
feat : convention 수정
PlusUltraCode May 27, 2024
c859908
feat : testing 완료
PlusUltraCode May 27, 2024
6c59295
refator : 오류 해결 및 코드리뷰 반영 완료!!
PlusUltraCode Jun 3, 2024
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

Choose a reason for hiding this comment

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

저는 @GetMapping(value = "/reservations"), @PostMapping(value = "/reservations"), @DeleteMapping(value = "/reservations/{id}") 부분에서 "/reservations"가 중복되는걸 줄여주고 싶어서
@controller 어노테이션 위에 RequestMapping("/reservations")를 적어주었습니다.

이렇게 하면 중복되는 부분은 제거되어
@GetMapping(value = "/reservations") -> @GetMapping
@PostMapping(value = "/reservations") -> @PostMapping
@DeleteMapping(value = "/reservations/{id}") -> @DeleteMapping("/{id})
조금 더 간결하게 짤 수 있었던 거 같아요.

Copy link
Author

Choose a reason for hiding this comment

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

@RequsetMapping("/reservaations")를 사용하니
해당 클래스 안에 있는 @GetMapping @PostMapping에
중복되는 "/reservations"을 없앨 수 있게 되었습니다.

감사합니다 ^^

Original file line number Diff line number Diff line change
@@ -1,63 +1,53 @@
package roomescape.reservation.controller;


import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import roomescape.reservation.db.ReservationEntity;
import roomescape.reservation.model.ReservationRequest;
import roomescape.reservation.dto.ReservationRequest;
import roomescape.reservation.dto.ReservationResponse;
import roomescape.reservation.service.ReservationService;

import javax.net.ssl.SSLEngineResult;
import java.net.URI;
import java.util.List;

@Controller
@RestController
@RequiredArgsConstructor
public class ReservationApiController {

private final ReservationService reservationService;

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

@GetMapping("/reservations")
public ResponseEntity<List<ReservationEntity>> reservations() {

List<ReservationEntity> lists = reservationService.findAllList();
public ResponseEntity<List<ReservationResponse>> reservations() {
List<ReservationResponse> responseList = reservationService.findAllReservations();

return ResponseEntity.status(HttpStatus.OK)
.body(lists);
return ResponseEntity
.status(HttpStatus.OK)
.body(responseList);
}

@PostMapping("/reservations")
public ResponseEntity<ReservationEntity> createReservation(
public ResponseEntity<ReservationResponse> addReservation(
@Valid
@RequestBody ReservationRequest reservationRequest
) {

ReservationEntity reservationEntity = reservationService.insertReservation(reservationRequest);
ReservationResponse response = reservationService.addReservation(reservationRequest);


HttpHeaders headers = new HttpHeaders();
headers.setLocation(URI.create("/reservations/" + Long.toString(reservationEntity.getId())));

return ResponseEntity.status(HttpStatus.CREATED)
.headers(headers)
.body(reservationEntity);
return ResponseEntity.created(URI.create("/reservations/" + response.getId()))
.body(response);
}

@DeleteMapping("/reservations/{id}")
public ResponseEntity<Void> deleteReservation(
@PathVariable Long id
) {
reservationService.cancelReservation(id);

reservationService.deleteReservation(id);

return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
return ResponseEntity.noContent()
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package roomescape.reservation.controller;


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

@Controller
public class ReservationController {

@GetMapping("/reservation")
public String reservation() {
return "new-reservation";
}
}
11 changes: 2 additions & 9 deletions src/main/java/roomescape/reservation/db/ReservationEntity.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
package roomescape.reservation.db;

import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import roomescape.time.db.TimeEntity;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ReservationEntity {

private Long id;

private String name;

private String date;
private TimeEntity timeEntity;

private String time;
}
77 changes: 70 additions & 7 deletions src/main/java/roomescape/reservation/db/ReservationRepository.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,83 @@
package roomescape.reservation.db;

import roomescape.reservation.model.ReservationRequest;

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Primary;
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.time.db.TimeEntity;

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

@Primary
@Repository
@RequiredArgsConstructor
public class ReservationRepository implements ReservationRepositoryImpl {

private final JdbcTemplate jdbcTemplate;

private final RowMapper<ReservationEntity> rowMapper = (rs, rowNum) -> {
TimeEntity timeEntity = new TimeEntity(rs.getLong("time_id"), rs.getString("time_value"));
ReservationEntity reservationEntity = ReservationEntity.builder()
.id(rs.getLong("id"))
.name(rs.getString("name"))
.date(rs.getString("date"))
.timeEntity(timeEntity)
.build();

return reservationEntity;
};


@Override
public List<ReservationEntity> findAll() {
String sql = "SELECT r.id as reservation_id, r.name, r.date, t.id as time_id, t.time as time_value " +
"FROM reservation as r INNER JOIN time as t ON r.time_id = t.id";

return jdbcTemplate.query(sql, rowMapper);
}

@Override
public ReservationEntity save(ReservationEntity reservationEntity) {
String sql = "INSERT INTO reservation (name,date,time_id) VALUES(?,?,?)";

public interface ReservationRepository {
KeyHolder keyHolder = new GeneratedKeyHolder();

jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
ps.setString(1, reservationEntity.getName());
ps.setObject(2, reservationEntity.getDate());
ps.setLong(3, reservationEntity.getTimeEntity().getId());
return ps;

List<ReservationEntity> findAllList();
}, keyHolder);

int countReservation();
Long generatedId = keyHolder.getKey().longValue();
reservationEntity.setId(generatedId);
return reservationEntity;

ReservationEntity findReservationById(Long id);
}

ReservationEntity insertReservation(ReservationRequest reservationRequest);
@Override
public ReservationEntity findById(Long id) {
String sql = "SELECT r.id as reservation_id, r.name, r.date, t.id as time_id, t.time as time_value " +
"FROM reservation as r INNER JOIN time as t ON r.time_id = t.id " +
"WHERE r.id = ?";
try {
return jdbcTemplate.queryForObject(sql, rowMapper, id);
} catch (EmptyResultDataAccessException e) {
return null;
}
}

void deleteReservation(Long id);
@Override
public void deleteById(Long id) {
String sql = "DELETE FROM reservation WHERE id = ?";
jdbcTemplate.update(sql, id);
}
}
Original file line number Diff line number Diff line change
@@ -1,79 +1,14 @@
package roomescape.reservation.db;

import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.stereotype.Repository;
import roomescape.reservation.model.ReservationRequest;

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

@Repository
@RequiredArgsConstructor
public class ReservationRepositoryImpl implements ReservationRepository {

private final JdbcTemplate jdbcTemplate;


public final RowMapper<ReservationEntity> actorRowMapper = (resultSet, rowNum) -> {
ReservationEntity reservationEntity = new ReservationEntity(
resultSet.getLong("id"),
resultSet.getString("name"),
resultSet.getString("date"),
resultSet.getString("time")
);
return reservationEntity;
};

@Override
public List<ReservationEntity> findAllList() {

String sql = "select * from reservation";
return jdbcTemplate.query(sql, actorRowMapper);
}

@Override
public int countReservation() {

String sql = "select count(*) from reservation";
return jdbcTemplate.queryForObject(sql, Integer.class);
}

@Override
public ReservationEntity findReservationById(Long id) {

String sql = "select * from reservation where id=?";
return jdbcTemplate.queryForObject(sql, actorRowMapper, id);
}

@Override
public ReservationEntity insertReservation(ReservationRequest reservationRequest) {

String sql = "insert into reservation (name, date, time) values (?,?,?)";

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

long generatedKey = keyHolder.getKey().longValue();

return findReservationById(generatedKey);

public interface ReservationRepositoryImpl {

}
List<ReservationEntity> findAll();

@Override
public void deleteReservation(Long id) {
ReservationEntity save(ReservationEntity reservationEntity);

String sql = "delete from reservation where id=?";
ReservationEntity findById(Long id);

jdbcTemplate.update(sql, id);
}
void deleteById(Long id);
}
21 changes: 21 additions & 0 deletions src/main/java/roomescape/reservation/dto/ReservationRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package roomescape.reservation.dto;

import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ReservationRequest {

@NotBlank
private String name;

@NotBlank
private String date;

@NotBlank

Choose a reason for hiding this comment

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

여기서 timeId가 아닌 time으로 수정해야 될 것 같습니다

Copy link
Author

Choose a reason for hiding this comment

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

감사합니다 상우님!!
TimeEntity클래스 명을 Time 으로 바꾸니 다른 클래스에서 TimeEntity time~~~ 라고 선언한 변수면들이 다 바뀌어
프로그램이 정상 작동하게 되었습니다.
오류를 찾기위해 많은 시간을 써서 그런지 매핑의 중요성으 뼈저리게 느꼈습니다.

Choose a reason for hiding this comment

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

맞습니다. 저도 스프링 미션을 하면서 여러가지 오류들 때문에 꽤 고생을 했었습니다.
오류들을 해결하는 과정에서 오류를 아예 안내는 것도 중요하지만 오류가 났을때
그 오류의 원인을 빠르게 찾고 수정하는 것도 정말 중요한 것 같습니다. 수고하셨습니다!👍

private Long timeId;
}
25 changes: 25 additions & 0 deletions src/main/java/roomescape/reservation/dto/ReservationResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package roomescape.reservation.dto;

import lombok.Data;
import roomescape.reservation.db.ReservationEntity;
import roomescape.time.db.TimeEntity;

@Data
public class ReservationResponse {

private Long id;
private String name;
private String date;
private TimeEntity timeEntity;

public static ReservationResponse from(ReservationEntity reservationEntity) {

ReservationResponse dto = new ReservationResponse();
dto.setId(reservationEntity.getId());
dto.setName(reservationEntity.getName());
dto.setDate(reservationEntity.getDate());
dto.setTimeEntity(reservationEntity.getTimeEntity());
return dto;
}

}
Loading