diff --git a/README.md b/README.md index 0a6a095f92..0899e71fb5 100644 --- a/README.md +++ b/README.md @@ -63,3 +63,23 @@ Type list to list all vouchers. - [x] 고객이 어떤 바우처를 보유하고 있는지 조회할 수 있어야 합니다. - [x] 고객이 보유한 바우처를 제거할 수 있어야 합니다. - [x] 특정 바우처를 보유한 고객을 조회할 수 있어야 합니다. + +### 3주차 미션 + +**3-1** + +- [x] Spring MVC를 적용해서 thymeleaf 템플릿을 설정해보세요. +- [x] 커맨드로 지원했던 기능을 thymeleaf를 이용해서 관리페이지를 만들고 다음 기능을 지원가능하게 해보세요 + - [x] 조회페이지 + - [x] 상세페이지 + - [x] 입력페이지 + - [x] 삭제기능 + +**3-2** + +- [ ] Spring MVC를 적용해서 JSON과 XML을 지원하는 REST API를 개발해보세요 + - [ ] 전체 조회기능 + - [ ] 조건별 조회기능 (바우처 생성기간 및 특정 할인타입별) + - [ ] 바우처 추가기능 + - [ ] 바우처 삭제기능 + - [ ] 바우처 아이디로 조회 기능 diff --git a/build.gradle b/build.gradle index e8d564472a..92ce216994 100644 --- a/build.gradle +++ b/build.gradle @@ -19,6 +19,9 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter' testImplementation 'org.springframework.boot:spring-boot-starter-test' implementation 'org.springframework.boot:spring-boot-starter-jdbc' + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-validation' runtimeOnly 'com.h2database:h2' diff --git a/src/main/java/com/programmers/springweekly/controller/CustomErrorController.java b/src/main/java/com/programmers/springweekly/controller/CustomErrorController.java new file mode 100644 index 0000000000..e4ccce5c62 --- /dev/null +++ b/src/main/java/com/programmers/springweekly/controller/CustomErrorController.java @@ -0,0 +1,31 @@ +package com.programmers.springweekly.controller; + +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.boot.web.servlet.error.ErrorController; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class CustomErrorController implements ErrorController { + + // ControllerAdvice로 처리되지 않는 서블릿 수준의 예외와 404 에러 처리 + @GetMapping("/error") + public String errorThrow(HttpServletRequest httpServletRequest, Model model) { + Integer errorStatusCode = (Integer) httpServletRequest.getAttribute(RequestDispatcher.ERROR_STATUS_CODE); + String errorMessage = (String) httpServletRequest.getAttribute(RequestDispatcher.ERROR_MESSAGE); + + model.addAttribute("errorCode", errorStatusCode); + + if (errorStatusCode == 404) { + model.addAttribute("errorMsg", "요청하신 페이지를 찾을 수 없습니다."); + return "errorPage"; + } + + model.addAttribute("errorMsg", errorMessage); + + return "errorPage"; + } + +} diff --git a/src/main/java/com/programmers/springweekly/controller/CustomerViewController.java b/src/main/java/com/programmers/springweekly/controller/CustomerViewController.java new file mode 100644 index 0000000000..55bdda8e78 --- /dev/null +++ b/src/main/java/com/programmers/springweekly/controller/CustomerViewController.java @@ -0,0 +1,65 @@ +package com.programmers.springweekly.controller; + +import com.programmers.springweekly.dto.customer.request.CustomerCreateRequest; +import com.programmers.springweekly.dto.customer.response.CustomerListResponse; +import com.programmers.springweekly.dto.customer.response.CustomerResponse; +import com.programmers.springweekly.service.CustomerService; +import jakarta.validation.Valid; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequiredArgsConstructor +@RequestMapping("/view/customer") +public class CustomerViewController { + + private final CustomerService customerService; + + @GetMapping + public String getMenuPage() { + return "customer/menu"; + } + + @GetMapping("/save") + public String getCreatePage() { + return "customer/create"; + } + + @PostMapping("/save") + public String save(@Valid CustomerCreateRequest customerCreateRequest) { + customerService.save(customerCreateRequest); + + return "customer/menu"; + } + + @GetMapping("/findAll") + public String getFindAllPage(Model model) { + CustomerListResponse customerListResponse = customerService.findAll(); + model.addAttribute("customerList", customerListResponse.getCustomerList()); + + return "customer/findAll"; + } + + @GetMapping("/find/{id}") + public String findById(@PathVariable("id") UUID customerId, Model model) { + CustomerResponse customerResponse = customerService.findById(customerId); + model.addAttribute("customer", customerResponse); + + return "customer/find"; + } + + @DeleteMapping("/delete/{id}") + public String deleteById(@PathVariable("id") UUID customerId) { + customerService.deleteById(customerId); + + return "redirect:/view/customer/find"; + } + +} diff --git a/src/main/java/com/programmers/springweekly/controller/HomeController.java b/src/main/java/com/programmers/springweekly/controller/HomeController.java new file mode 100644 index 0000000000..d722ad6caa --- /dev/null +++ b/src/main/java/com/programmers/springweekly/controller/HomeController.java @@ -0,0 +1,13 @@ +package com.programmers.springweekly.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class HomeController { + + @GetMapping("/") + public String home() { + return "home"; + } +} diff --git a/src/main/java/com/programmers/springweekly/controller/VoucherController.java b/src/main/java/com/programmers/springweekly/controller/VoucherController.java index 5320093a4b..df75c6b264 100644 --- a/src/main/java/com/programmers/springweekly/controller/VoucherController.java +++ b/src/main/java/com/programmers/springweekly/controller/VoucherController.java @@ -19,7 +19,7 @@ public class VoucherController { public void save(VoucherCreateRequest voucherCreateRequest) { VoucherValidator.validateVoucher( voucherCreateRequest.getVoucherType(), - String.valueOf(voucherCreateRequest.getDiscountAmount()) + voucherCreateRequest.getDiscountAmount() ); voucherService.save(voucherCreateRequest); @@ -28,7 +28,7 @@ public void save(VoucherCreateRequest voucherCreateRequest) { public void update(VoucherUpdateRequest voucherUpdateRequest) { VoucherValidator.validateVoucher( voucherUpdateRequest.getVoucherType(), - String.valueOf(voucherUpdateRequest.getDiscountAmount()) + voucherUpdateRequest.getDiscountAmount() ); voucherService.update(voucherUpdateRequest); diff --git a/src/main/java/com/programmers/springweekly/controller/VoucherViewController.java b/src/main/java/com/programmers/springweekly/controller/VoucherViewController.java new file mode 100644 index 0000000000..cf49f6458c --- /dev/null +++ b/src/main/java/com/programmers/springweekly/controller/VoucherViewController.java @@ -0,0 +1,71 @@ +package com.programmers.springweekly.controller; + +import com.programmers.springweekly.dto.voucher.request.VoucherCreateRequest; +import com.programmers.springweekly.dto.voucher.response.VoucherListResponse; +import com.programmers.springweekly.dto.voucher.response.VoucherResponse; +import com.programmers.springweekly.service.VoucherService; +import com.programmers.springweekly.util.validator.VoucherValidator; +import jakarta.validation.Valid; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequiredArgsConstructor +@RequestMapping("/view/voucher") +public class VoucherViewController { + + private final VoucherService voucherService; + + @GetMapping + public String getMenuPage() { + return "voucher/menu"; + } + + @GetMapping("/save") + public String getCreatePage() { + return "voucher/create"; + } + + @PostMapping("/save") + public String save(@Valid VoucherCreateRequest voucherCreateRequest) { + VoucherValidator.validateVoucher( + voucherCreateRequest.getVoucherType(), + voucherCreateRequest.getDiscountAmount() + ); + + voucherService.save(voucherCreateRequest); + + return "voucher/menu"; + } + + @GetMapping("/findAll") + public String getFindAllPage(Model model) { + VoucherListResponse voucherListResponse = voucherService.findAll(); + model.addAttribute("voucherList", voucherListResponse.getVoucherList()); + + return "voucher/findAll"; + } + + @GetMapping("/find/{id}") + public String findById(@PathVariable("id") UUID voucherId, Model model) { + VoucherResponse voucherResponse = voucherService.findById(voucherId); + model.addAttribute("voucher", voucherResponse); + + return "voucher/find"; + } + + @DeleteMapping("/delete/{id}") + public String deleteById(@PathVariable("id") UUID voucherId) { + voucherService.deleteById(voucherId); + + return "redirect:/view/voucher/find"; + } + +} diff --git a/src/main/java/com/programmers/springweekly/docs/specification.md b/src/main/java/com/programmers/springweekly/docs/specification.md index 1642eedc01..f8d8d0da8b 100644 --- a/src/main/java/com/programmers/springweekly/docs/specification.md +++ b/src/main/java/com/programmers/springweekly/docs/specification.md @@ -206,4 +206,46 @@ blacklist - 바우처 지갑에 있는 모든 리스트 조회(findAll) - 테스트 코드 구현 +
+ +### 3-1 Thymeleaf를 이용하여 바우처 관리페이지 구현 + +### 요약 + +- 고객, 바우처 CREATE, UPDATE, DELETE Web Controller 구현 +- CreateRequestDto에 Validation 적용. +- Thymeleaf를 이용한 페이지 생성 +- ControllerAdvice를 통한 Global 예외 처리 + +### Voucher(web) + +- 바우처 입력 기능 +- 바우처 삭제 기능 +- 바우처 전체 조회, 상세 조회 기능 + +### Customer(web) + +- 고객 입력 기능 +- 고객 삭제 기능 +- 고객 전체 조회, 상세 조회 기능 + +### Validation + +- Spring에서 제공하는 Validation을 사용하여 DTO단에서 RequestBody 값을 검증 + +### ControllerAdvice + +- Controller, Serivce, Repository 등 Controller 하위 단에서 발생한 예외를 전역으로 잡는 ExceptionHandler 클래스 생성 +- 프로그램 내에서 발생할 것 같은 예외들을 모두 구분하여 로깅하고, 메세지를 페이지로 발송하여 Error페이지에 출력 +- 예외 별 상태 코드 적용 +- 발생할 것 같은 예외들을 모두 잡고 예상치 못한 예외가 발생했을 때 프로그램이 꺼지지 않도록 제일 하위에 최상위 Exception으로 예외 처리 + +### 웹 동작 화면(정상) +![ezgif com-video-to-gif](https://github.com/prgrms-be-devcourse/springboot-basic/assets/92444744/c85de587-903e-493d-8fde-5e2d0ba3116b) + +### 웹 동작 화면(에러) +![ezgif com-video-to-gif (1)](https://github.com/prgrms-be-devcourse/springboot-basic/assets/92444744/36e41e81-6d1f-4298-8527-43ee10d43e11) + + + diff --git a/src/main/java/com/programmers/springweekly/domain/voucher/FixedAmountVoucher.java b/src/main/java/com/programmers/springweekly/domain/voucher/FixedAmountVoucher.java index 9f0a89edc9..6e25864146 100644 --- a/src/main/java/com/programmers/springweekly/domain/voucher/FixedAmountVoucher.java +++ b/src/main/java/com/programmers/springweekly/domain/voucher/FixedAmountVoucher.java @@ -11,7 +11,7 @@ public class FixedAmountVoucher implements Voucher { public FixedAmountVoucher(UUID voucherId, long discountAmount) { VoucherValidator.validateVoucher( VoucherType.FIXED, - String.valueOf(discountAmount) + discountAmount ); this.voucherId = voucherId; diff --git a/src/main/java/com/programmers/springweekly/domain/voucher/PercentDiscountVoucher.java b/src/main/java/com/programmers/springweekly/domain/voucher/PercentDiscountVoucher.java index 8fefead89e..49b52bda4b 100644 --- a/src/main/java/com/programmers/springweekly/domain/voucher/PercentDiscountVoucher.java +++ b/src/main/java/com/programmers/springweekly/domain/voucher/PercentDiscountVoucher.java @@ -11,7 +11,7 @@ public class PercentDiscountVoucher implements Voucher { public PercentDiscountVoucher(UUID voucherId, long discountAmount) { VoucherValidator.validateVoucher( VoucherType.PERCENT, - String.valueOf(discountAmount) + discountAmount ); this.voucherId = voucherId; diff --git a/src/main/java/com/programmers/springweekly/dto/customer/request/CustomerCreateRequest.java b/src/main/java/com/programmers/springweekly/dto/customer/request/CustomerCreateRequest.java index 29d48716b0..6261d7c7f5 100644 --- a/src/main/java/com/programmers/springweekly/dto/customer/request/CustomerCreateRequest.java +++ b/src/main/java/com/programmers/springweekly/dto/customer/request/CustomerCreateRequest.java @@ -1,14 +1,25 @@ package com.programmers.springweekly.dto.customer.request; import com.programmers.springweekly.domain.customer.CustomerType; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; import lombok.Builder; import lombok.Getter; @Getter public class CustomerCreateRequest { + @NotBlank(message = "이름은 필수 입력 값입니다.") + @Pattern(regexp = "^[a-zA-Z]*$", message = "이름은 영어로만 입력되어야 합니다.") private String customerName; + + @Email(message = "이메일 양식에 맞춰서 입력해주세요.") + @NotBlank(message = "이메일은 필수 입력 값입니다.") private String customerEmail; + + @NotNull(message = "타입은 필수 입력 값입니다.") private CustomerType customerType; @Builder @@ -17,5 +28,5 @@ public CustomerCreateRequest(String customerName, String customerEmail, Customer this.customerEmail = customerEmail; this.customerType = customerType; } - + } diff --git a/src/main/java/com/programmers/springweekly/dto/voucher/request/VoucherCreateRequest.java b/src/main/java/com/programmers/springweekly/dto/voucher/request/VoucherCreateRequest.java index 63b160cd2f..858f8a7f34 100644 --- a/src/main/java/com/programmers/springweekly/dto/voucher/request/VoucherCreateRequest.java +++ b/src/main/java/com/programmers/springweekly/dto/voucher/request/VoucherCreateRequest.java @@ -1,13 +1,18 @@ package com.programmers.springweekly.dto.voucher.request; import com.programmers.springweekly.domain.voucher.VoucherType; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; import lombok.Builder; import lombok.Getter; @Getter public class VoucherCreateRequest { + @Positive private long discountAmount; + + @NotNull private VoucherType voucherType; @Builder @@ -15,5 +20,5 @@ public VoucherCreateRequest(long discountAmount, VoucherType voucherType) { this.discountAmount = discountAmount; this.voucherType = voucherType; } - + } diff --git a/src/main/java/com/programmers/springweekly/exception/GlobalExceptionHandler.java b/src/main/java/com/programmers/springweekly/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000000..c6e5767ff5 --- /dev/null +++ b/src/main/java/com/programmers/springweekly/exception/GlobalExceptionHandler.java @@ -0,0 +1,99 @@ +package com.programmers.springweekly.exception; + +import java.util.NoSuchElementException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.http.HttpStatus; +import org.springframework.ui.Model; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; + +@Slf4j +@ControllerAdvice +public class GlobalExceptionHandler { + + private static final String ERROR_MSG = "errorMsg"; + private static final String ERROR_CODE = "errorCode"; + private static final String ERROR_PAGE = "errorPage"; + + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public String handleMethodArgumentNotValidException(MethodArgumentNotValidException e, Model model) { + log.warn("GlobalExceptionHandler - MethodArgumentNotValidException 발생, 데이터 검증 실패 {}", e.getMessage(), e); + addAttributeInModel(e.getBindingResult().getAllErrors().get(0).getDefaultMessage(), 400, model); + + return ERROR_PAGE; + } + + @ExceptionHandler(NoSuchElementException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public String handleNoSuchElementException(NoSuchElementException e, Model model) { + log.warn("GlobalExceptionHandler - NoSuchElementException 발생, 찾는 데이터가 없음 {}", e.getMessage(), e); + addAttributeInModel(e.getMessage(), 404, model); + + return ERROR_PAGE; + } + + @ExceptionHandler(NullPointerException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public String handleNullPointerException(NullPointerException e, Model model) { + log.error("GlobalExceptionHandler - NullPointerException 발생 {}", e.getMessage(), e); + addAttributeInModel(e.getMessage(), 500, model); + + return ERROR_PAGE; + } + + @ExceptionHandler(IllegalArgumentException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public String handleIllegalArgumentException(IllegalArgumentException e, Model model) { + log.error("GlobalExceptionHandler - IllegalArgumentException 발생, 클라이언트의 잘못된 입력 값 예상 {}", e.getMessage(), e); + addAttributeInModel(e.getMessage(), 400, model); + + return ERROR_PAGE; + } + + @ExceptionHandler(IndexOutOfBoundsException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public String handleIndexOutOfBoundsException(IndexOutOfBoundsException e, Model model) { + log.error("GlobalExceptionHandler - IndexOutOfBoundsException 발생, 배열의 범위를 초과한 작업 예상 {}", e.getMessage(), e); + addAttributeInModel(e.getMessage(), 400, model); + + return ERROR_PAGE; + } + + @ExceptionHandler(DuplicateKeyException.class) + @ResponseStatus(HttpStatus.CONFLICT) + public String handleDuplicateKeyException(DuplicateKeyException e, Model model) { + log.error("GlobalExceptionHandler - DuplicateKeyException 발생, 유니크/중복 키 충돌 예상 {}", e.getMessage(), e); + addAttributeInModel(e.getMessage(), 409, model); + + return ERROR_PAGE; + } + + @ExceptionHandler(DataAccessException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public String handleDataAccessException(DataAccessException e, Model model) { + log.error("GlobalExceptionHandler - DataAccessException 발생, 데이터 접근 관련 예외 {}", e.getMessage(), e); + addAttributeInModel(e.getMessage(), 500, model); + + return ERROR_PAGE; + } + + @ExceptionHandler(Exception.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public String handleException(Exception e, Model model) { + log.error("GlobalExceptionHandler - Exception 발생, 개발자가 잡지 못한 예외 {}", e.getMessage(), e); + addAttributeInModel(e.getMessage(), 500, model); + + return ERROR_PAGE; + } + + private void addAttributeInModel(String errorMessage, int errorCode, Model model) { + model.addAttribute(ERROR_MSG, errorMessage); + model.addAttribute(ERROR_CODE, errorCode); + } + +} diff --git a/src/main/java/com/programmers/springweekly/service/VoucherService.java b/src/main/java/com/programmers/springweekly/service/VoucherService.java index beb8257301..fe762d43b9 100644 --- a/src/main/java/com/programmers/springweekly/service/VoucherService.java +++ b/src/main/java/com/programmers/springweekly/service/VoucherService.java @@ -12,7 +12,6 @@ import java.util.UUID; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; @Service @RequiredArgsConstructor @@ -36,7 +35,7 @@ public void update(VoucherUpdateRequest voucherUpdateRequest) { voucherUpdateRequest.getVoucherType(), voucherUpdateRequest.getDiscountAmount() ); - + voucherRepository.update(voucher); } @@ -50,10 +49,6 @@ public VoucherResponse findById(UUID voucherId) { public VoucherListResponse findAll() { List voucherList = voucherRepository.findAll(); - if (CollectionUtils.isEmpty(voucherList)) { - throw new NoSuchElementException("바우처가 저장되어 있지 않습니다."); - } - return new VoucherListResponse(voucherList.stream().map(VoucherResponse::new).toList()); } diff --git a/src/main/java/com/programmers/springweekly/util/validator/VoucherValidator.java b/src/main/java/com/programmers/springweekly/util/validator/VoucherValidator.java index e8a53ddb2b..fa6806c807 100644 --- a/src/main/java/com/programmers/springweekly/util/validator/VoucherValidator.java +++ b/src/main/java/com/programmers/springweekly/util/validator/VoucherValidator.java @@ -1,8 +1,6 @@ package com.programmers.springweekly.util.validator; import com.programmers.springweekly.domain.voucher.VoucherType; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -11,19 +9,16 @@ @Slf4j public final class VoucherValidator { - private static final Pattern numberPattern = Pattern.compile("\\d+"); private static final int PERCENT_MAX = 100; private static final int PERCENT_AND_FIXED_MIN = 0; - public static void validateVoucher(VoucherType voucherType, String discountAmount) { + public static void validateVoucher(VoucherType voucherType, long discountAmount) { switch (voucherType) { case FIXED -> { - validateNumber(discountAmount); validateFixedRange(discountAmount); } case PERCENT -> { - validateNumber(discountAmount); validatePercentRange(discountAmount); } default -> { @@ -33,28 +28,18 @@ public static void validateVoucher(VoucherType voucherType, String discountAmoun } } - private static void validateNumber(String input) { - Matcher match = numberPattern.matcher(input); - if (!match.matches()) { - log.warn("고객이 입력한 문자열 {} 이 숫자 형태가 아니어서 예외 발생", input); - throw new IllegalArgumentException("Input : " + input + ", 입력하신 것은 숫자가 아닙니다."); - } - } - - private static void validateFixedRange(String inputFixed) { - int fixed = Integer.parseInt(inputFixed); + private static void validateFixedRange(long inputFixed) { - if (fixed < PERCENT_AND_FIXED_MIN) { + if (inputFixed < PERCENT_AND_FIXED_MIN) { log.warn("고객이 입력한 고정 할인 금액 {} 이 음수여서 예외 발생", inputFixed); throw new IllegalArgumentException("Input : " + inputFixed + ", 입력하신 숫자는 음수입니다. 양수를 입력해주세요."); } } - private static void validatePercentRange(String inputPercent) { - int percent = Integer.parseInt(inputPercent); + private static void validatePercentRange(long inputPercent) { - if (percent > PERCENT_MAX || percent < PERCENT_AND_FIXED_MIN) { + if (inputPercent > PERCENT_MAX || inputPercent < PERCENT_AND_FIXED_MIN) { log.warn("고객이 입력한 퍼센트 할인 {}% 가 퍼센트 범위를 벗어나서 예외 발생", inputPercent); throw new IllegalArgumentException("Input : " + inputPercent + ", 입력하신 숫자는 퍼센트 범위를 벗어납니다."); } diff --git a/src/main/java/com/programmers/springweekly/view/Console.java b/src/main/java/com/programmers/springweekly/view/Console.java index af4639bd4f..84c41a6423 100644 --- a/src/main/java/com/programmers/springweekly/view/Console.java +++ b/src/main/java/com/programmers/springweekly/view/Console.java @@ -38,7 +38,7 @@ public VoucherCreateRequest inputVoucherCreate(VoucherType voucherType) { String inputDiscountAmount = SCANNER.nextLine(); log.info("사용자가 입력한 할인 양 : {}", inputDiscountAmount); - VoucherValidator.validateVoucher(voucherType, inputDiscountAmount); + VoucherValidator.validateVoucher(voucherType, Long.parseLong(inputDiscountAmount)); return VoucherCreateRequest.builder() .discountAmount(Long.parseLong(inputDiscountAmount)) @@ -54,7 +54,7 @@ public VoucherUpdateRequest inputVoucherUpdate(UUID voucherId) { ParseValidator.validateVoucherUpdateLength(voucherInfo); VoucherType voucherType = VoucherType.from(voucherInfo[1]); - VoucherValidator.validateVoucher(voucherType, voucherInfo[0]); + VoucherValidator.validateVoucher(voucherType, Long.parseLong(voucherInfo[0])); return VoucherUpdateRequest.builder() .voucherId(voucherId) diff --git a/src/main/resources/static/common.css b/src/main/resources/static/common.css new file mode 100644 index 0000000000..2b183c70bd --- /dev/null +++ b/src/main/resources/static/common.css @@ -0,0 +1,38 @@ +body { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + width: 100%; + height: 100vh; + font-family: 'Noto Sans KR', sans-serif; +} + +.header1, .header2, .header3 { + margin: 3px 0px; + font-weight: bold; +} + +.header1 { + font-size: 24px; +} + +.header2 { + font-size: 19px; +} + +.header3 { + font-size: 22px; +} + +form { + width: 400px; +} + +.inputHeader { + font-weight: bold; + font-size: 14px; + width: 100%; + margin: 5px 0px; +} + diff --git a/src/main/resources/static/error.png b/src/main/resources/static/error.png new file mode 100644 index 0000000000..e10d2ce829 Binary files /dev/null and b/src/main/resources/static/error.png differ diff --git a/src/main/resources/templates/customer/create.html b/src/main/resources/templates/customer/create.html new file mode 100644 index 0000000000..c2fbe92857 --- /dev/null +++ b/src/main/resources/templates/customer/create.html @@ -0,0 +1,55 @@ + + + + + + + Document + + + + + + + + + +
고객 입력
+
+
+
고객 이름
+
+
+ +
+
+
고객 이메일
+
+
+ +
+
+
고객 타입
+
+ +
+ +
+ +
+ + diff --git a/src/main/resources/templates/customer/find.html b/src/main/resources/templates/customer/find.html new file mode 100644 index 0000000000..738cbf2e7c --- /dev/null +++ b/src/main/resources/templates/customer/find.html @@ -0,0 +1,53 @@ + + + + + + + + + + + Title + + + +
+
고객 조회
+
고객 ID
+
고객 ID
+
고객 이름
+
고객 이름
+
고객 이메일
+
고객 이메일
+
고객 타입
+
고객 타입
+ +
+ + diff --git a/src/main/resources/templates/customer/findAll.html b/src/main/resources/templates/customer/findAll.html new file mode 100644 index 0000000000..b171f3f829 --- /dev/null +++ b/src/main/resources/templates/customer/findAll.html @@ -0,0 +1,75 @@ + + + + + + + + + + + + + Document + + + +
고객 조회
+ + + + + + + + + + + + + + + + + + + + + +
고객 ID고객 이름고객 이메일고객 타입고객 정보고객 삭제
고객 ID고객 이름고객 이메일고객 타입 + + + +
+ + + + diff --git a/src/main/resources/templates/customer/menu.html b/src/main/resources/templates/customer/menu.html new file mode 100644 index 0000000000..d8b3cdd455 --- /dev/null +++ b/src/main/resources/templates/customer/menu.html @@ -0,0 +1,41 @@ + + + + + + + Document + + + + + + + + + +
바우처 프로그램
+
고객 관련 기능
+
+
+ + +
+ +
+ + diff --git a/src/main/resources/templates/errorPage.html b/src/main/resources/templates/errorPage.html new file mode 100644 index 0000000000..c047104ba1 --- /dev/null +++ b/src/main/resources/templates/errorPage.html @@ -0,0 +1,38 @@ + + + + + + + + + + + Title + + + +
에러 페이지
+
+ 에러 사진 +
에러 코드
+
+
에러 메시지
+
+
+ + diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html new file mode 100644 index 0000000000..ef4187a52c --- /dev/null +++ b/src/main/resources/templates/home.html @@ -0,0 +1,31 @@ + + + + + + + Document + + + + + + + + + +
바우처 프로그램
+
+ + +
+ + diff --git a/src/main/resources/templates/voucher/create.html b/src/main/resources/templates/voucher/create.html new file mode 100644 index 0000000000..507ad52c4d --- /dev/null +++ b/src/main/resources/templates/voucher/create.html @@ -0,0 +1,49 @@ + + + + + + + Document + + + + + + + + + +
바우처 입력
+
+
+
바우처 타입
+
+ +
+
바우처 할인 양
+
+
+ +
+
+ +
+ +
+ + diff --git a/src/main/resources/templates/voucher/find.html b/src/main/resources/templates/voucher/find.html new file mode 100644 index 0000000000..d5fa2daa71 --- /dev/null +++ b/src/main/resources/templates/voucher/find.html @@ -0,0 +1,51 @@ + + + + + + + + + + + Title + + + +
+
바우처 조회
+
바우처 ID
+
바우처 ID
+
바우처 타입
+
바우처 타입
+
바우처 할인 양
+
바우처 할인 양
+ +
+ + diff --git a/src/main/resources/templates/voucher/findAll.html b/src/main/resources/templates/voucher/findAll.html new file mode 100644 index 0000000000..6234bc3015 --- /dev/null +++ b/src/main/resources/templates/voucher/findAll.html @@ -0,0 +1,73 @@ + + + + + + + + + + + + + Document + + + +
바우처 조회
+ + + + + + + + + + + + + + + + + + + +
바우처 ID바우처 타입바우처 할인 양바우처 정보바우처 삭제
바우처 ID바우처 타입바우처 할인 양 + + + +
+ + + + diff --git a/src/main/resources/templates/voucher/menu.html b/src/main/resources/templates/voucher/menu.html new file mode 100644 index 0000000000..b23535849e --- /dev/null +++ b/src/main/resources/templates/voucher/menu.html @@ -0,0 +1,41 @@ + + + + + + + Document + + + + + + + + + +
바우처 프로그램
+
바우처 관련 기능
+
+
+ + +
+ +
+ + diff --git a/src/test/java/com/programmers/springweekly/service/voucher/VoucherServiceTest.java b/src/test/java/com/programmers/springweekly/service/voucher/VoucherServiceTest.java index 21706e0121..042be57ef5 100644 --- a/src/test/java/com/programmers/springweekly/service/voucher/VoucherServiceTest.java +++ b/src/test/java/com/programmers/springweekly/service/voucher/VoucherServiceTest.java @@ -117,8 +117,6 @@ void deleteAll() { voucherService.deleteAll(); // then - assertThatThrownBy(() -> voucherService.findAll()) - .isInstanceOf(NoSuchElementException.class) - .hasMessage("바우처가 저장되어 있지 않습니다."); + assertThat(voucherService.findAll().getVoucherList().size()).isEqualTo(0); } }