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

[4기 - 한승원] SpringBoot Part3 Weekly Mission 제출합니다. #831

Open
wants to merge 9 commits into
base: seungwon/w1
Choose a base branch
from

Conversation

SW-H
Copy link

@SW-H SW-H commented Jul 14, 2023

📌 과제 설명

바우처 관리 애플리케이션

👩‍💻 요구 사항과 구현 내용

(기본) 바우처 서비스 관리페이지 개발하기

  • Spring MVC를 적용해서 thymeleaf 템플릿을 설정해보세요.
  • 커맨드로 지원했던 기능을 thymeleaf를 이용해서 관리페이지를 만들고 다음 기능을 지원가능하게 해보세요
    • 조회페이지
    • 상세페이지
    • 입력페이지
    • 삭제기능

(기본) 바우처 서비스의 API 개발하기

  • Spring MVC를 적용해서 JSON과 XML을 지원하는 REST API를 개발해보세요
    • 전체 조회기능
    • 조건별 조회기능 (바우처 생성기간 및 특정 할인타입별)
    • 바우처 추가기능
    • 바우처 삭제기능
    • 바우처 아이디로 조회 기능

✅ 피드백 반영사항

이전PR에 남겨주신 내용들까지 반영했습니다!

  • 도메인 객체(Voucher 같은 것)에서 입출력 쪽으로의 의존 개선
  • Enum 사용 수정
  • 가독성 측면(Stream API 활용 및 코드 개선)
  • (build.gradle) 인프라 의존성 수정
  • response의 넓은 범용성, 제너럴 타입일 때의 문제점 해결

@SW-H SW-H requested review from lleellee0 and maenguin July 14, 2023 09:39
@SW-H SW-H self-assigned this Jul 14, 2023
@SW-H SW-H changed the base branch from main to seungwon/w1 July 14, 2023 09:39
Comment on lines 180 to 186
List<Voucher> foundVouchers = new ArrayList<>();
for (String[] voucher : vouchers) {
String discountTypeCompared = voucher[VoucherProperty.CUSTOMER_ID.index];
if (discountType.equals(discountTypeCompared)) {
foundVouchers.add(mapToVoucher(voucher));
}
}

Choose a reason for hiding this comment

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

Stream API로 바꿔보세요!

Choose a reason for hiding this comment

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

Restful하게 API가 설계되지 않은 것 같습니다!

다른분들에게 드렸던 피드백 동일하게 드립니다.

API 설계 관련해서는 표준적으로 권장되는 가이드와 여러 서비스들의 API 설계가 어떻게 되어있는지 둘러보시면 좋습니다~
Voucher 관리 서비스는 명확하게 API를 설계할 수 있는 반면 애매한 API를 가지게되는 서비스들도 있어서요.
만약 그런 API를 만들게될 경우 표준적인 설계 방법을 벗어나지 않는 선에서 예성님이 생각하는 기준에 입각하여 API를 설계해보시기 바랍니다.

Comment on lines +10 to +39
@ExceptionHandler(EmptyAssignerException.class)
protected ResponseEntity<ErrorResponse> handleCustomException(EmptyAssignerException emptyAssignerException) {
ErrorCode errorCode = emptyAssignerException.getErrorCode();
return handleExceptionInternal(errorCode);
}

@ExceptionHandler(InvalidDataException.class)
protected ResponseEntity<ErrorResponse> handleCustomException(InvalidDataException invalidDataException) {
ErrorCode errorCode = invalidDataException.getErrorCode();
return handleExceptionInternal(errorCode);
}

@ExceptionHandler(NoSuchDataException.class)
protected ResponseEntity<ErrorResponse> handleCustomException(NoSuchDataException noSuchDataException) {
ErrorCode errorCode = noSuchDataException.getErrorCode();
return handleExceptionInternal(errorCode);
}

@ExceptionHandler(VoucherReassignmentException.class)
protected ResponseEntity<ErrorResponse> handleCustomException(
VoucherReassignmentException voucherReassignmentException) {
ErrorCode errorCode = voucherReassignmentException.getErrorCode();
return handleExceptionInternal(errorCode);
}

private ResponseEntity<ErrorResponse> handleExceptionInternal(ErrorCode errorCode) {
return ResponseEntity
.status(errorCode.getHttpStatus().value())
.body(new ErrorResponse(errorCode));
}

Choose a reason for hiding this comment

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

우리가 예외를 계층적으로 나눠주는 이유는, 예외를 구분해주고 싶은 상황에선 구분해서 처리하고 구분해서 처리하고 싶지 않은 경우 상위 예외로 한번에 처리하려는 겁니다.
지금 4가지 예외는 모두 똑같은 방식으로 처리가 되고 있죠?
이렇게 되면 예외를 굳이 나눠서 처리해줄 필요가 없습니다.

@lleellee0
Copy link

@SW-H

승원님 수고하셨습니다~
리뷰 드린 내용들 잘 반영해서 바꿔보셨네요. ㅎㅎ
이번에 다시 리뷰드린 내용들 확인해보시고 바꿔보세요 :)

Comment on lines +30 to +42
@GetMapping
public ResponseEntity<List<VoucherResponseDTO>> find(
@RequestParam(required = false) String type,
@RequestParam(required = false, defaultValue = "-1") Long id
) {
if (id > 0) {
return findById(id);
}
if (type != null) {
return findByType(type);
}
return findAll();
}

Choose a reason for hiding this comment

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

동적 쿼리를 구현하시려고 노력한 흔적이 보이네요
이미 아실 수도 있지만 QueryDSL을 사용하면 동적쿼리를 쉽게 처리할 수 있습니다.
좀더 검색에 대한 니즈가 강해서 고도화할 필요가 있으면 엘라스틱 서치를 사용하게 될꺼구요

Comment on lines +49 to +52
private ResponseEntity<List<VoucherResponseDTO>> findById(@PathVariable long id) {
VoucherResponseDTO response = voucherService.findById(id);
return ResponseEntity.ok(List.of(response));
}

Choose a reason for hiding this comment

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

ResponseEntity를 사용해서 응답을 제어하는 부분이 딱히 없다면 List 그대로 반환해도 동일한 코드가 될것 같네요

return ResponseEntity.ok(response);
}

@PostMapping

Choose a reason for hiding this comment

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

리소스 경로에 대한 Rest API 컨벤션을 잘지켜주시고 계시네요

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants