diff --git a/.gitignore b/.gitignore index 3cf37560c8..408f4ecce5 100644 --- a/.gitignore +++ b/.gitignore @@ -135,3 +135,5 @@ buildNumber.properties .classpath # End of https://www.toptal.com/developers/gitignore/api/java,intellij+all,maven + +docker/database \ No newline at end of file diff --git a/docker/db-init/schema.sql b/docker/db-init/schema.sql new file mode 100644 index 0000000000..108cf4a39b --- /dev/null +++ b/docker/db-init/schema.sql @@ -0,0 +1,31 @@ +DROP TABLE IF EXISTS customers; +CREATE TABLE customers +( + customer_id BINARY(16) PRIMARY KEY, + name varchar(20) NOT NULL, + email varchar(50) NOT NULL, + create_at datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP (6), + CONSTRAINT unq_user_email UNIQUE (email) +); + +INSERT INTO customers(customer_id, name, email) +VALUES (uuid_to_bin(UUID()), 'tester00', 'test00@gmail.com'), + (uuid_to_bin(UUID()), 'tester01', 'test01@gmail.com'), + (uuid_to_bin(UUID()), 'tester02', 'test02@gmail.com'); + + + +DROP TABLE IF EXISTS vouchers; +CREATE TABLE vouchers +( + voucher_id BINARY(16) PRIMARY KEY, + amount bigint NOT NULL, + discount enum('FIXED', 'PERCENT') NOT NULL, + registration_date datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP (6), + expiration_date datetime(6) NOT NULL +); + +INSERT INTO vouchers (voucher_id, amount, discount, expiration_date) +VALUES (uuid_to_bin(UUID()), 50, 'PERCENT', DATE_ADD(CURRENT_TIMESTAMP(6), INTERVAL 7 DAY)), + (uuid_to_bin(UUID()), 100000, 'FIXED', DATE_ADD(CURRENT_TIMESTAMP(6), INTERVAL 7 DAY)), + (uuid_to_bin(UUID()), 80, 'PERCENT', DATE_ADD(CURRENT_TIMESTAMP(6), INTERVAL 7 DAY)); diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000000..6528d5e609 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,21 @@ +version: "3.7" + +services: + vacation-db: + image: mysql + restart: always + environment: + MYSQL_ROOT_PASSWORD: "qwe123" + MYSQL_DATABASE: "voucher_mgmt" + MYSQL_USER: "test" + MYSQL_PASSWORD: "test" + TZ: Asia/Seoul + command: + - --character-set-server=utf8mb4 + - --collation-server=utf8mb4_unicode_ci + volumes: + - ./db-init:/docker-entrypoint-initdb.d + - ./database/datadir/:/var/lib/mysql + platform: linux/x86_64 + ports: + - 3306:3306 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 72e5a7a170..e432970fdb 100644 --- a/pom.xml +++ b/pom.xml @@ -11,12 +11,12 @@ org.weekly weekly 0.0.1-SNAPSHOT - weekly + weekly21 + war Demo project for Spring Boot 17 - jar org.springframework.boot @@ -35,7 +35,23 @@ - mysql + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.springframework.boot + spring-boot-starter-tomcat + provided + + + + org.springframework.boot + spring-boot-starter-web + + + + ` mysql mysql-connector-java 8.0.28 @@ -58,6 +74,13 @@ 1.18.3 test + + + org.mockito + mockito-core + + + diff --git a/src/main/java/org/weekly/weekly/VoucherManageApplication.java b/src/main/java/org/weekly/weekly/VoucherManageApplication.java index 7fe8ed5f34..a176e6079e 100644 --- a/src/main/java/org/weekly/weekly/VoucherManageApplication.java +++ b/src/main/java/org/weekly/weekly/VoucherManageApplication.java @@ -6,9 +6,9 @@ @SpringBootApplication public class VoucherManageApplication { - public static void main(String[] args) { - ApplicationContext context = SpringApplication.run(VoucherManageApplication.class, args); - context.getBean(VoucherManagementController.class).start(); - } -} \ No newline at end of file + public static void main(String[] args) { + ApplicationContext context = SpringApplication.run(VoucherManageApplication.class, args); + context.getBean(VoucherManagementController.class).start(); + } +} diff --git a/src/main/java/org/weekly/weekly/VoucherManagementController.java b/src/main/java/org/weekly/weekly/VoucherManagementController.java index 8cc14adbd3..38df9e1eb9 100644 --- a/src/main/java/org/weekly/weekly/VoucherManagementController.java +++ b/src/main/java/org/weekly/weekly/VoucherManagementController.java @@ -8,19 +8,19 @@ import org.weekly.weekly.customer.dto.request.CustomerUpdateRequest; import org.weekly.weekly.customer.dto.response.CustomerResponse; import org.weekly.weekly.customer.dto.response.CustomersResponse; +import org.weekly.weekly.global.util.CustomerMenu; +import org.weekly.weekly.global.util.ManageMenu; +import org.weekly.weekly.global.util.PrintMessageType; +import org.weekly.weekly.global.util.VoucherMenu; import org.weekly.weekly.ui.CommandLineApplication; -import org.weekly.weekly.util.CustomerMenu; -import org.weekly.weekly.util.ManageMenu; -import org.weekly.weekly.util.PrintMessageType; -import org.weekly.weekly.util.VoucherMenu; import org.weekly.weekly.voucher.controller.VoucherController; -import org.weekly.weekly.voucher.dto.Response; import org.weekly.weekly.voucher.dto.request.VoucherCreationRequest; - -import java.util.List; +import org.weekly.weekly.voucher.dto.response.VoucherCreationResponse; +import org.weekly.weekly.voucher.dto.response.VouchersResponse; @Component public class VoucherManagementController { + private final Logger logger = LoggerFactory.getLogger(VoucherManagementController.class); private final CommandLineApplication commandLineApplication; private final VoucherController voucherController; @@ -33,12 +33,12 @@ public VoucherManagementController(CommandLineApplication commandLineApplication } public void start() { - boolean isExit = false; + boolean isRunning = true; - while(!isExit) { + while (isRunning) { try { ManageMenu manageMenu = commandLineApplication.readManageMenu(); - isExit = processManageMenuSelection(manageMenu); + isRunning = processManageMenuSelection(manageMenu); } catch (RuntimeException runtimeException) { commandLineApplication.printErrorMsg(runtimeException.getMessage()); } @@ -46,85 +46,50 @@ public void start() { } private boolean processManageMenuSelection(ManageMenu manageMenu) { - if (ManageMenu.EXIT.equals(manageMenu)) { - return true; - } - - if (ManageMenu.VOUCHER.equals(manageMenu)) { - VoucherMenu voucherMenu = commandLineApplication.readVoucherMenu(); - processVoucherMenuSelection(voucherMenu); - return false; - } - - if (ManageMenu.CUSTOMER.equals(manageMenu)){ - CustomerMenu customerMenu = commandLineApplication.readCustomerMenu(); - processCustomerMenuSelection(customerMenu); - return false; - } - - return true; + return switch (manageMenu) { + case VOUCHER -> { + VoucherMenu voucherMenu = commandLineApplication.readVoucherMenu(); + processVoucherMenuSelection(voucherMenu); + yield false; + } + case CUSTOMER -> { + CustomerMenu customerMenu = commandLineApplication.readCustomerMenu(); + processCustomerMenuSelection(customerMenu); + yield false; + } + default -> true; + }; } - private boolean processVoucherMenuSelection(VoucherMenu selectMenu) { - if (VoucherMenu.CREATE.equals(selectMenu)) { - handleVoucherCreation(); - return false; - } - - if (VoucherMenu.LIST.equals(selectMenu)) { - handleVoucherSearch(); - return false; + private void processVoucherMenuSelection(VoucherMenu selectMenu) { + switch (selectMenu) { + case CREATE -> handleVoucherCreation(); + case LIST -> handleVoucherSearch(); } - - - return true; } private void handleVoucherCreation() { VoucherCreationRequest voucherCreationRequest = commandLineApplication.createVoucherFromInput(); - Response response = voucherController.createVoucher(voucherCreationRequest); - logger.info("{}{}", PrintMessageType.CREATE_VOUCHER_SUCCESS.getMessage(),response.getResult()); + VoucherCreationResponse response = voucherController.createVoucher(voucherCreationRequest); + logger.info("{}{}", PrintMessageType.CREATE_VOUCHER_SUCCESS.getMessage(), response.result()); commandLineApplication.printResult(response); } private void handleVoucherSearch() { - Response response = voucherController.getVouchers(); - logger.info("{}{}", PrintMessageType.FIND_ALL_VOUCHER_SUCCESS.getMessage(), response.getResult()); + VouchersResponse response = voucherController.getVouchers(); + logger.info("{}{}", PrintMessageType.FIND_ALL_VOUCHER_SUCCESS.getMessage(), response.result()); commandLineApplication.printResult(response); } - private boolean processCustomerMenuSelection(CustomerMenu selectMenu) { - if (CustomerMenu.CREATE.equals(selectMenu)) { - handleCustomerCreation(); - return false; + private void processCustomerMenuSelection(CustomerMenu selectMenu) { + switch (selectMenu) { + case CREATE -> handleCustomerCreation(); + case DELETE -> handleCustomerDelete(); + case DELETE_ALL -> handleCustomerDeleteAll(); + case FIND_ALL -> handleCustomerFindAll(); + case FIND_DETAIL -> handleFindDetail(); + case UPDATE -> handleUpdateCustomer(); } - - if (CustomerMenu.DELETE.equals(selectMenu)) { - handleCustomerDelete(); - return false; - } - - if (CustomerMenu.DELETE_ALL.equals(selectMenu)) { - handleCustomerDeleteAll(); - return false; - } - - if (CustomerMenu.FIND_ALL.equals(selectMenu)) { - handleCustomerFindAll(); - return false; - } - - if (CustomerMenu.FIND_DETAIL.equals(selectMenu)) { - handleFindDetail(); - return false; - } - - if (CustomerMenu.UPDATE.equals(selectMenu)) { - handleUpdateCustomer(); - return false; - } - - return true; } private void handleCustomerCreation() { @@ -160,5 +125,4 @@ private void handleUpdateCustomer() { CustomerResponse customerResponse = customerController.updateCustomer(customerUpdateRequest); commandLineApplication.printResult(customerResponse); } - } diff --git a/src/main/java/org/weekly/weekly/customer/controller/CustomerController.java b/src/main/java/org/weekly/weekly/customer/controller/CustomerController.java index 83abc90697..d2b6af0fb1 100644 --- a/src/main/java/org/weekly/weekly/customer/controller/CustomerController.java +++ b/src/main/java/org/weekly/weekly/customer/controller/CustomerController.java @@ -7,8 +7,6 @@ import org.weekly.weekly.customer.dto.response.CustomersResponse; import org.weekly.weekly.customer.service.CustomerService; -import java.util.List; - @Controller public class CustomerController { diff --git a/src/main/java/org/weekly/weekly/customer/controller/api/CustomerAPIController.java b/src/main/java/org/weekly/weekly/customer/controller/api/CustomerAPIController.java new file mode 100644 index 0000000000..f22a81a65f --- /dev/null +++ b/src/main/java/org/weekly/weekly/customer/controller/api/CustomerAPIController.java @@ -0,0 +1,59 @@ +package org.weekly.weekly.customer.controller.api; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.weekly.weekly.customer.dto.request.CustomerCreationRequest; +import org.weekly.weekly.customer.dto.request.CustomerUpdateRequest; +import org.weekly.weekly.customer.dto.response.CustomerResponse; +import org.weekly.weekly.customer.dto.response.CustomersResponse; +import org.weekly.weekly.customer.service.CustomerService; + +import java.util.List; + +@RestController +@RequestMapping("/api/v1/customers") +public class CustomerAPIController { + + private final CustomerService customerService; + + public CustomerAPIController(CustomerService customerService) { + this.customerService = customerService; + } + + @PostMapping + public ResponseEntity create(@RequestBody CustomerCreationRequest creationRequest) { + CustomerResponse customerResponse = customerService.createCustomer(creationRequest); + return new ResponseEntity<>(customerResponse, HttpStatus.CREATED); + } + + @GetMapping + public ResponseEntity> customers() { + CustomersResponse customersResponse = customerService.findAllCustomer(); + return new ResponseEntity<>(customersResponse.getCustomerResponses(), HttpStatus.OK); + } + + @GetMapping("/{customerEmail}") + public ResponseEntity findCustomer(@PathVariable String customerEmail) { + CustomerResponse customerResponse = customerService.findDetailCustomer(customerEmail); + return new ResponseEntity<>(customerResponse, HttpStatus.OK); + } + + @PatchMapping + public ResponseEntity updateCustomer(@RequestBody CustomerUpdateRequest customerUpdateRequest) { + CustomerResponse customerResponse = customerService.updateCustomer(customerUpdateRequest); + return new ResponseEntity<>(customerResponse, HttpStatus.OK); + } + + @DeleteMapping("/{customerEmail}") + public ResponseEntity deleteCustomer(@PathVariable String customerEmail) { + customerService.deleteCustomer(customerEmail); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @DeleteMapping("/delete-all") + public ResponseEntity deleteAll() { + customerService.deleteAllCustomers(); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } +} diff --git a/src/main/java/org/weekly/weekly/customer/controller/web/CustomerWebController.java b/src/main/java/org/weekly/weekly/customer/controller/web/CustomerWebController.java new file mode 100644 index 0000000000..236a873a2f --- /dev/null +++ b/src/main/java/org/weekly/weekly/customer/controller/web/CustomerWebController.java @@ -0,0 +1,122 @@ +package org.weekly.weekly.customer.controller.web; + +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.weekly.weekly.customer.dto.request.CustomerCreationRequest; +import org.weekly.weekly.customer.dto.request.CustomerUpdateRequest; +import org.weekly.weekly.customer.dto.response.CustomerResponse; +import org.weekly.weekly.customer.dto.response.CustomersResponse; +import org.weekly.weekly.customer.exception.CustomerException; +import org.weekly.weekly.customer.service.CustomerService; +import org.weekly.weekly.global.handler.WebExceptionDto; + +@Controller +@RequestMapping("/customer") +public class CustomerWebController { + + private final CustomerService customerService; + + public CustomerWebController(CustomerService customerService) { + this.customerService = customerService; + } + + @GetMapping("/menu") + public String menu() { + return "customer/menu"; + } + + @GetMapping("/findAll") + public String findCustomers(Model model) { + CustomersResponse customersResponse = customerService.findAllCustomer(); + model.addAttribute("customers", customersResponse); + return "customer/findCustomers"; + } + + @GetMapping("/create") + public String createCustomer() { + return "customer/createCustomer"; + } + + @PostMapping("/create") + public String createCustomer(CustomerCreationRequest creationRequest, Model model) { + try { + CustomerResponse customerResponse = customerService.createCustomer(creationRequest); + model.addAttribute("customer", customerResponse); + } catch (CustomerException exception) { + model.addAttribute("exception", new WebExceptionDto(exception)); + return "exception/exception"; + } + return "customer/customerInfo"; + } + + + @GetMapping("/find") + public String findCustomer() { + return "customer/findCustomer"; + } + + @PostMapping("/find") + public String findCustomer(CustomerUpdateRequest updateRequest, Model model) { + try { + CustomerResponse customerResponse = customerService.findDetailCustomer(updateRequest); + model.addAttribute("customer", customerResponse); + } catch (CustomerException | EmptyResultDataAccessException exception) { + model.addAttribute("exception", new WebExceptionDto(exception)); + return "exception/exception"; + } + return "customer/customerInfo"; + } + + @GetMapping("/delete") + public String deleteCustomer() { + return "customer/deleteCustomer"; + } + + @PostMapping("/delete") + public String deleteCustomer(CustomerUpdateRequest updateRequest, Model model) { + try { + customerService.deleteCustomer(updateRequest); + } catch (CustomerException | EmptyResultDataAccessException exception) { + model.addAttribute("exception", new WebExceptionDto(exception)); + return "exception/exception"; + } + return "redirect:/"; + } + + @GetMapping("/deleteAll") + public String deleteAllCustomer() { + return "customer/deleteAll"; + } + + @PostMapping("/deleteAll") + public String deleteAllCustomers(Model model) { + try { + customerService.deleteAllCustomers(); + } catch (CustomerException | EmptyResultDataAccessException exception) { + model.addAttribute("exception", new WebExceptionDto(exception)); + return "exception/exception"; + } + return "redirect:/"; + } + + @GetMapping("/update") + public String updateCustomer() { + return "customer/updateCustomer"; + } + + @PostMapping("/update") + public String updateCustomer(CustomerUpdateRequest updateRequest, Model model) { + try { + CustomerResponse customerResponse = customerService.updateCustomer(updateRequest); + model.addAttribute("customer", customerResponse); + } catch (CustomerException | EmptyResultDataAccessException exception) { + model.addAttribute("exception", new WebExceptionDto(exception)); + return "exception/exception"; + } + return "customer/customerInfo"; + } +} diff --git a/src/main/java/org/weekly/weekly/customer/domain/Customer.java b/src/main/java/org/weekly/weekly/customer/domain/Customer.java index b6cdb8d6fb..b912ea3463 100644 --- a/src/main/java/org/weekly/weekly/customer/domain/Customer.java +++ b/src/main/java/org/weekly/weekly/customer/domain/Customer.java @@ -6,6 +6,7 @@ import java.util.UUID; public class Customer { + UUID customerId; String name; String email; diff --git a/src/main/java/org/weekly/weekly/customer/dto/request/CustomerCreationRequest.java b/src/main/java/org/weekly/weekly/customer/dto/request/CustomerCreationRequest.java index f21ac3cb5b..8651b3db9d 100644 --- a/src/main/java/org/weekly/weekly/customer/dto/request/CustomerCreationRequest.java +++ b/src/main/java/org/weekly/weekly/customer/dto/request/CustomerCreationRequest.java @@ -6,6 +6,7 @@ import java.util.UUID; public class CustomerCreationRequest { + private String email; private String name; @@ -27,4 +28,16 @@ public Customer toCustomer() { public String getEmail() { return email; } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public void setEmail(String email) { + this.email = email; + } } diff --git a/src/main/java/org/weekly/weekly/customer/dto/request/CustomerUpdateRequest.java b/src/main/java/org/weekly/weekly/customer/dto/request/CustomerUpdateRequest.java index 5567f226b4..a87c7dd51d 100644 --- a/src/main/java/org/weekly/weekly/customer/dto/request/CustomerUpdateRequest.java +++ b/src/main/java/org/weekly/weekly/customer/dto/request/CustomerUpdateRequest.java @@ -3,31 +3,38 @@ import org.weekly.weekly.ui.exception.InputValidator; public class CustomerUpdateRequest { + private String email; private String newEmail; - private CustomerUpdateRequest(String email, String afterEmail) { - this.email = email; - this.newEmail = afterEmail; - } - private CustomerUpdateRequest(String email) { - this.email = email; + private CustomerUpdateRequest() { } - public static CustomerUpdateRequest of(String email) { + public CustomerUpdateRequest(String email, String afterEmail) { InputValidator.isEmpty(email); - return new CustomerUpdateRequest(email); + InputValidator.isEmpty(afterEmail); + this.email = email; + this.newEmail = afterEmail; } - public static CustomerUpdateRequest of(String email, String afterEmail) { + public CustomerUpdateRequest(String email) { InputValidator.isEmpty(email); - InputValidator.isEmpty(afterEmail); - return new CustomerUpdateRequest(email, afterEmail); + this.email = email; } public String email() { return email; } - public String newEmail() {return newEmail;} + public String newEmail() { + return newEmail; + } + + public void setEmail(String email) { + this.email = email; + } + + public void setNewEmail(String newEmail) { + this.newEmail = newEmail; + } } diff --git a/src/main/java/org/weekly/weekly/customer/dto/response/CustomerResponse.java b/src/main/java/org/weekly/weekly/customer/dto/response/CustomerResponse.java index 343af5edb7..773dc92829 100644 --- a/src/main/java/org/weekly/weekly/customer/dto/response/CustomerResponse.java +++ b/src/main/java/org/weekly/weekly/customer/dto/response/CustomerResponse.java @@ -1,12 +1,12 @@ package org.weekly.weekly.customer.dto.response; import org.weekly.weekly.customer.domain.Customer; -import org.weekly.weekly.voucher.dto.Response; import java.text.MessageFormat; import java.time.LocalDateTime; -public class CustomerResponse implements Response { +public class CustomerResponse { + String name; String email; LocalDateTime createAt; @@ -21,8 +21,19 @@ public static CustomerResponse of(Customer customer) { return new CustomerResponse(customer.getName(), customer.getEmail(), customer.getCreateAt()); } - @Override - public String getResult() { + public String getEmail() { + return email; + } + + public LocalDateTime getCreateAt() { + return createAt; + } + + public String getName() { + return name; + } + + public String result() { return MessageFormat.format("[이름: {0}, 이메일: {1}, 생성 시기: {2}]", name, email, createAt); } } diff --git a/src/main/java/org/weekly/weekly/customer/dto/response/CustomersResponse.java b/src/main/java/org/weekly/weekly/customer/dto/response/CustomersResponse.java index eb601c9e82..908b16b29c 100644 --- a/src/main/java/org/weekly/weekly/customer/dto/response/CustomersResponse.java +++ b/src/main/java/org/weekly/weekly/customer/dto/response/CustomersResponse.java @@ -1,31 +1,31 @@ package org.weekly.weekly.customer.dto.response; import org.weekly.weekly.customer.domain.Customer; -import org.weekly.weekly.util.PrintMessageType; -import org.weekly.weekly.voucher.domain.Voucher; -import org.weekly.weekly.voucher.dto.Response; -import org.weekly.weekly.voucher.dto.response.VoucherCreationResponse; +import org.weekly.weekly.global.util.PrintMessageType; import java.util.List; -import java.util.stream.Collectors; -public class CustomersResponse implements Response { +public class CustomersResponse { + List result; public CustomersResponse(List customers) { result = customers.stream() .map(CustomerResponse::of) - .collect(Collectors.toUnmodifiableList()); + .toList(); } - @Override - public String getResult() { + public String result() { if (result.isEmpty()) { return PrintMessageType.NO_VOUCHER_DATAS.getMessage(); } StringBuilder resultBuilder = new StringBuilder(); - result.forEach(customerResponse-> resultBuilder.append(customerResponse.getResult()).append('\n')); + result.forEach(customerResponse -> resultBuilder.append(customerResponse.result()).append('\n')); return resultBuilder.toString(); } + + public List getCustomerResponses() { + return result; + } } diff --git a/src/main/java/org/weekly/weekly/customer/exception/CustomerException.java b/src/main/java/org/weekly/weekly/customer/exception/CustomerException.java index cfda9e7fa5..5c3f5fe62f 100644 --- a/src/main/java/org/weekly/weekly/customer/exception/CustomerException.java +++ b/src/main/java/org/weekly/weekly/customer/exception/CustomerException.java @@ -1,9 +1,17 @@ package org.weekly.weekly.customer.exception; -import org.weekly.weekly.util.ExceptionMsg; +import org.weekly.weekly.global.handler.ExceptionCode; -public class CustomerException extends RuntimeException{ - public CustomerException(ExceptionMsg exceptionMsg) { - super(exceptionMsg.getMsg()); +public class CustomerException extends RuntimeException { + + private final ExceptionCode exceptionCode; + + public CustomerException(ExceptionCode exceptionMsg) { + super(exceptionMsg.getMessage()); + this.exceptionCode = exceptionMsg; + } + + public ExceptionCode getExceptionCode() { + return exceptionCode; } } diff --git a/src/main/java/org/weekly/weekly/customer/exception/CustomerValidator.java b/src/main/java/org/weekly/weekly/customer/exception/CustomerValidator.java index d30f721d32..3ba3f132da 100644 --- a/src/main/java/org/weekly/weekly/customer/exception/CustomerValidator.java +++ b/src/main/java/org/weekly/weekly/customer/exception/CustomerValidator.java @@ -1,18 +1,20 @@ package org.weekly.weekly.customer.exception; -import org.weekly.weekly.util.ExceptionMsg; +import org.weekly.weekly.global.handler.ExceptionCode; import java.util.regex.Pattern; public class CustomerValidator { - public CustomerValidator() { - throw new CustomerException(ExceptionMsg.UTIL_CLASS); - } private static final String EMAIL_FORMAT = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,3}$"; + + private CustomerValidator() { + throw new CustomerException(ExceptionCode.UTIL_CLASS); + } + public static void validateEmailFormat(String email) { if (!Pattern.matches(EMAIL_FORMAT, email)) { - throw new CustomerException(ExceptionMsg.NOT_EMAIL_FORMAT); + throw new CustomerException(ExceptionCode.NOT_EMAIL_FORMAT); } } } diff --git a/src/main/java/org/weekly/weekly/customer/repository/CustomerRepository.java b/src/main/java/org/weekly/weekly/customer/repository/CustomerRepository.java index a8a7352288..fe994e1fc8 100644 --- a/src/main/java/org/weekly/weekly/customer/repository/CustomerRepository.java +++ b/src/main/java/org/weekly/weekly/customer/repository/CustomerRepository.java @@ -7,9 +7,13 @@ public interface CustomerRepository { Customer insert(Customer customer); + void deleteByEmail(String email); + void deleteAll(); + Optional findByEmail(String email); + List findAll(); Customer update(Customer customer, String newEmail); diff --git a/src/main/java/org/weekly/weekly/customer/repository/JdbcCustomerRepository.java b/src/main/java/org/weekly/weekly/customer/repository/JdbcCustomerRepository.java index b332fa85f4..59e3790134 100644 --- a/src/main/java/org/weekly/weekly/customer/repository/JdbcCustomerRepository.java +++ b/src/main/java/org/weekly/weekly/customer/repository/JdbcCustomerRepository.java @@ -1,23 +1,18 @@ package org.weekly.weekly.customer.repository; import org.springframework.context.annotation.Profile; -import org.springframework.dao.DataAccessException; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import org.weekly.weekly.customer.domain.Customer; import org.weekly.weekly.customer.exception.CustomerException; -import org.weekly.weekly.util.ExceptionMsg; -import org.weekly.weekly.voucher.domain.DiscountType; -import org.weekly.weekly.voucher.domain.Voucher; -import org.weekly.weekly.voucher.exception.VoucherException; +import org.weekly.weekly.global.handler.ExceptionCode; import javax.sql.DataSource; import java.nio.ByteBuffer; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; -import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @@ -25,13 +20,18 @@ @Profile("!dev") @Repository -public class JdbcCustomerRepository implements CustomerRepository{ +public class JdbcCustomerRepository implements CustomerRepository { + private final JdbcTemplate jdbcTemplate; public JdbcCustomerRepository(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); } + private static UUID toUUID(byte[] bytes) { + var buffer = ByteBuffer.wrap(bytes); + return new UUID(buffer.getLong(), buffer.getLong()); + } @Override public Customer insert(Customer customer) { @@ -43,7 +43,7 @@ public Customer insert(Customer customer) { Timestamp.valueOf(customer.getCreateAt())); if (insert != 1) { - throw new CustomerException(ExceptionMsg.SQL_INSERT_ERROR); + throw new CustomerException(ExceptionCode.SQL_INSERT_ERROR); } return customer; } @@ -89,27 +89,20 @@ public Customer update(Customer customer, String newEmail) { beforeEmail); if (update != 1) { - throw new CustomerException(ExceptionMsg.SQL_ERROR); + throw new CustomerException(ExceptionCode.SQL_ERROR); } return customer; } - - private static UUID toUUID(byte[] bytes) { - var buffer = ByteBuffer.wrap(bytes); - return new UUID(buffer.getLong(), buffer.getLong()); - } - private Customer mapToCustomer(ResultSet resultSet) throws SQLException { UUID customerId = toUUID(resultSet.getBytes("customer_id")); String name = resultSet.getString("name"); String email = resultSet.getString("email"); - LocalDateTime createAt = resultSet.getTimestamp("create_at") == null? null : resultSet.getTimestamp("create_at").toLocalDateTime(); + LocalDateTime createAt = resultSet.getTimestamp("create_at") == null ? null : resultSet.getTimestamp("create_at").toLocalDateTime(); return new Customer(customerId, name, email, createAt); } - private byte[] uuidToBytes(UUID voucherId) { return voucherId.toString().getBytes(); } diff --git a/src/main/java/org/weekly/weekly/customer/service/CustomerService.java b/src/main/java/org/weekly/weekly/customer/service/CustomerService.java index dcfa849365..d193afd878 100644 --- a/src/main/java/org/weekly/weekly/customer/service/CustomerService.java +++ b/src/main/java/org/weekly/weekly/customer/service/CustomerService.java @@ -9,13 +9,14 @@ import org.weekly.weekly.customer.dto.response.CustomersResponse; import org.weekly.weekly.customer.exception.CustomerException; import org.weekly.weekly.customer.repository.CustomerRepository; -import org.weekly.weekly.util.ExceptionMsg; +import org.weekly.weekly.global.handler.ExceptionCode; import java.util.List; import java.util.Optional; @Service public class CustomerService { + private final CustomerRepository customerRepository; public CustomerService(CustomerRepository customerRepository) { @@ -27,27 +28,34 @@ public CustomerResponse createCustomer(CustomerCreationRequest creationRequest) validateCustomerNotExist(creationRequest.getEmail()); Customer customer = creationRequest.toCustomer(); - customerRepository.insert(customer); - return CustomerResponse.of(customer); + Customer savedCustomer = customerRepository.insert(customer); + return CustomerResponse.of(savedCustomer); } @Transactional public void deleteCustomer(CustomerUpdateRequest updateRequest) { - String email = updateRequest.email(); - customerRepository.deleteByEmail(email); + deleteCustomer(updateRequest.email()); + } + + public void deleteCustomer(String customerEmail) { + customerRepository.deleteByEmail(customerEmail); } public void deleteAllCustomers() { customerRepository.deleteAll(); } - + @Transactional(readOnly = true) public CustomerResponse findDetailCustomer(CustomerUpdateRequest updateRequest) { - String email = updateRequest.email(); - Customer customer = validateCustomerExistAndGet(email); + return findDetailCustomer(updateRequest.email()); + } + + public CustomerResponse findDetailCustomer(String customerEmail) { + Customer customer = validateCustomerExistAndGet(customerEmail); return CustomerResponse.of(customer); } + public CustomersResponse findAllCustomer() { List customers = customerRepository.findAll(); return new CustomersResponse(customers); @@ -66,14 +74,14 @@ public CustomerResponse updateCustomer(CustomerUpdateRequest updateRequest) { private void validateCustomerNotExist(String email) { Optional findCustomer = customerRepository.findByEmail(email); if (findCustomer.isPresent()) { - throw new CustomerException(ExceptionMsg.SQL_EXIST); + throw new CustomerException(ExceptionCode.SQL_EXIST); } } private Customer validateCustomerExistAndGet(String email) { Optional customer = customerRepository.findByEmail(email); if (customer.isEmpty()) { - throw new CustomerException(ExceptionMsg.SQL_ERROR); + throw new CustomerException(ExceptionCode.SQL_ERROR); } return customer.get(); } diff --git a/src/main/java/org/weekly/weekly/global/handler/APIExceptionHandler.java b/src/main/java/org/weekly/weekly/global/handler/APIExceptionHandler.java new file mode 100644 index 0000000000..666bb9297e --- /dev/null +++ b/src/main/java/org/weekly/weekly/global/handler/APIExceptionHandler.java @@ -0,0 +1,41 @@ +package org.weekly.weekly.global.handler; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; +import org.weekly.weekly.customer.exception.CustomerException; +import org.weekly.weekly.voucher.exception.VoucherException; + +@RestControllerAdvice(basePackages = {"org.weekly.weekly.api"}) +public class APIExceptionHandler extends ResponseEntityExceptionHandler { + + @ExceptionHandler({VoucherException.class}) + public ResponseEntity handleVoucherException(VoucherException exception) { + return handleExceptionInternal(exception.getExceptionCode()); + } + + @ExceptionHandler({CustomerException.class}) + public ResponseEntity handleCustomerException(CustomerException customerException) { + return handleExceptionInternal(customerException.getExceptionCode()); + } + + @ExceptionHandler({RuntimeException.class}) + public ResponseEntity handleGlobalException(RuntimeException runtimeException) { + return handleExceptionInternal(ExceptionCode.NOT_ACCESS, runtimeException.getMessage()); + } + + private ResponseEntity handleExceptionInternal(ExceptionCode exceptionCode) { + return ResponseEntity.status(exceptionCode.getHttpStatus()) + .body(errorResponse(exceptionCode.name(), exceptionCode.getMessage())); + } + + private ResponseEntity handleExceptionInternal(ExceptionCode exceptionCode, String message) { + return ResponseEntity.status(exceptionCode.getHttpStatus()) + .body(errorResponse(exceptionCode.name(), message)); + } + + private ErrorResponse errorResponse(String code, String message) { + return new ErrorResponse(code, message); + } +} diff --git a/src/main/java/org/weekly/weekly/global/handler/ErrorResponse.java b/src/main/java/org/weekly/weekly/global/handler/ErrorResponse.java new file mode 100644 index 0000000000..4e5a133f2f --- /dev/null +++ b/src/main/java/org/weekly/weekly/global/handler/ErrorResponse.java @@ -0,0 +1,20 @@ +package org.weekly.weekly.global.handler; + +public class ErrorResponse { + + private final String code; + private final String message; + + public ErrorResponse(String code, String message) { + this.code = code; + this.message = message; + } + + public String getMessage() { + return message; + } + + public String getCode() { + return code; + } +} diff --git a/src/main/java/org/weekly/weekly/global/handler/ExceptionCode.java b/src/main/java/org/weekly/weekly/global/handler/ExceptionCode.java new file mode 100644 index 0000000000..244802616e --- /dev/null +++ b/src/main/java/org/weekly/weekly/global/handler/ExceptionCode.java @@ -0,0 +1,40 @@ +package org.weekly.weekly.global.handler; + +import org.springframework.http.HttpStatus; + +public enum ExceptionCode { + ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "[ERROR]: "), + NOT_ACCESS(HttpStatus.FORBIDDEN, "잘못된 접근"), + UTIL_CLASS(HttpStatus.BAD_REQUEST, "유틸 클래스입니다."), + EMPTY(HttpStatus.BAD_REQUEST, "사용자가 아무 값도 입력하지 않았습니다."), + NOT_INPUT_FORMAT(HttpStatus.BAD_REQUEST, "입력 형식에 맞지 않습니다."), + NOT_MENU(HttpStatus.NOT_FOUND, "해당 메뉴는 존재하지 않습니다."), + NOT_NUMBER_FORMAT(HttpStatus.BAD_REQUEST, "허용되지 않는 값입니다."), + NOT_NATURAL_NUMBER(HttpStatus.BAD_REQUEST, "자연수가 아닙니다."), + NOT_DISCOUNT(HttpStatus.BAD_REQUEST, "할인 종류가 아닙니다."), + EXPIRATION_ERROR(HttpStatus.BAD_REQUEST, "유효기간이 등록기간보다 빠릅니다."), + VOUCHER_EXIST(HttpStatus.CONFLICT, "이미 존재하는 바우처입니다."), + NOT_FOUND(HttpStatus.BAD_REQUEST, "해당 종류의 할인정보를 찾을 수 없습니다."), + NOT_SAME_PARAM_SIZE(HttpStatus.BAD_REQUEST, "입력 파라미터 개수가 맞지 않습니다."), + NOT_EMAIL_FORMAT(HttpStatus.BAD_REQUEST, "이메일형식이 아닙니다."), + SQL_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "값을 가져오기 실패"), + SQL_INSERT_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "값 추가 실패"), + SQL_EXIST(HttpStatus.CONFLICT, "이미 존재합니다."), + SQL_DELETE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "삭제 실패"); + + private final String message; + private final HttpStatus httpStatus; + + ExceptionCode(HttpStatus httpStatus, String message) { + this.httpStatus = httpStatus; + this.message = message; + } + + public String getMessage() { + return ERROR.message + message; + } + + public HttpStatus getHttpStatus() { + return httpStatus; + } +} diff --git a/src/main/java/org/weekly/weekly/global/handler/WebExceptionDto.java b/src/main/java/org/weekly/weekly/global/handler/WebExceptionDto.java new file mode 100644 index 0000000000..4550e2649d --- /dev/null +++ b/src/main/java/org/weekly/weekly/global/handler/WebExceptionDto.java @@ -0,0 +1,14 @@ +package org.weekly.weekly.global.handler; + +public class WebExceptionDto { + + private final String message; + + public WebExceptionDto(RuntimeException error) { + this.message = error.getMessage(); + } + + public String getMessage() { + return message; + } +} diff --git a/src/main/java/org/weekly/weekly/util/CustomerMenu.java b/src/main/java/org/weekly/weekly/global/util/CustomerMenu.java similarity index 84% rename from src/main/java/org/weekly/weekly/util/CustomerMenu.java rename to src/main/java/org/weekly/weekly/global/util/CustomerMenu.java index 14bcd473fe..41d52a0997 100644 --- a/src/main/java/org/weekly/weekly/util/CustomerMenu.java +++ b/src/main/java/org/weekly/weekly/global/util/CustomerMenu.java @@ -1,4 +1,7 @@ -package org.weekly.weekly.util; +package org.weekly.weekly.global.util; + +import org.weekly.weekly.customer.exception.CustomerException; +import org.weekly.weekly.global.handler.ExceptionCode; import java.util.Arrays; import java.util.Map; @@ -15,6 +18,7 @@ public enum CustomerMenu implements Menu { private final String printMessage; private static final Map CUSTOMER_MENU_MAP; + static { CUSTOMER_MENU_MAP = new ConcurrentHashMap<>(); Arrays.stream(CustomerMenu.values()) @@ -29,7 +33,7 @@ public static CustomerMenu getMenu(String userInput) { if (CUSTOMER_MENU_MAP.containsKey(userInput)) { return CUSTOMER_MENU_MAP.get(userInput); } - throw new RuntimeException(ExceptionMsg.NOT_MENU.getMsg()); + throw new CustomerException(ExceptionCode.NOT_MENU); } @Override diff --git a/src/main/java/org/weekly/weekly/util/ManageMenu.java b/src/main/java/org/weekly/weekly/global/util/ManageMenu.java similarity index 85% rename from src/main/java/org/weekly/weekly/util/ManageMenu.java rename to src/main/java/org/weekly/weekly/global/util/ManageMenu.java index fcd829a672..1ce8e2c54b 100644 --- a/src/main/java/org/weekly/weekly/util/ManageMenu.java +++ b/src/main/java/org/weekly/weekly/global/util/ManageMenu.java @@ -1,4 +1,6 @@ -package org.weekly.weekly.util; +package org.weekly.weekly.global.util; + +import org.weekly.weekly.global.handler.ExceptionCode; import java.util.Arrays; import java.util.Map; @@ -26,7 +28,7 @@ public static ManageMenu getMenu(String userInput) { if (MANAGE_MENU_MAP.containsKey(userInput)) { return MANAGE_MENU_MAP.get(userInput); } - throw new RuntimeException(ExceptionMsg.NOT_MENU.getMsg()); + throw new RuntimeException(ExceptionCode.NOT_MENU.getMessage()); } @Override diff --git a/src/main/java/org/weekly/weekly/util/Menu.java b/src/main/java/org/weekly/weekly/global/util/Menu.java similarity index 58% rename from src/main/java/org/weekly/weekly/util/Menu.java rename to src/main/java/org/weekly/weekly/global/util/Menu.java index 40981c0f93..9c286bd89a 100644 --- a/src/main/java/org/weekly/weekly/util/Menu.java +++ b/src/main/java/org/weekly/weekly/global/util/Menu.java @@ -1,4 +1,4 @@ -package org.weekly.weekly.util; +package org.weekly.weekly.global.util; public interface Menu { String printMessage(); diff --git a/src/main/java/org/weekly/weekly/util/PrintMessageType.java b/src/main/java/org/weekly/weekly/global/util/PrintMessageType.java similarity index 96% rename from src/main/java/org/weekly/weekly/util/PrintMessageType.java rename to src/main/java/org/weekly/weekly/global/util/PrintMessageType.java index c42e69ef39..4bd9f3e925 100644 --- a/src/main/java/org/weekly/weekly/util/PrintMessageType.java +++ b/src/main/java/org/weekly/weekly/global/util/PrintMessageType.java @@ -1,4 +1,4 @@ -package org.weekly.weekly.util; +package org.weekly.weekly.global.util; public enum PrintMessageType { MANAGE_PROGRAM("=== Manage Program ==="), diff --git a/src/main/java/org/weekly/weekly/util/VoucherMenu.java b/src/main/java/org/weekly/weekly/global/util/VoucherMenu.java similarity index 75% rename from src/main/java/org/weekly/weekly/util/VoucherMenu.java rename to src/main/java/org/weekly/weekly/global/util/VoucherMenu.java index a9b4e621ce..a6c5532e15 100644 --- a/src/main/java/org/weekly/weekly/util/VoucherMenu.java +++ b/src/main/java/org/weekly/weekly/global/util/VoucherMenu.java @@ -1,4 +1,7 @@ -package org.weekly.weekly.util; +package org.weekly.weekly.global.util; + +import org.weekly.weekly.global.handler.ExceptionCode; +import org.weekly.weekly.voucher.exception.VoucherException; import java.util.Arrays; import java.util.Map; @@ -8,9 +11,11 @@ public enum VoucherMenu implements Menu { EXIT("Type exit to exit the program."), CREATE("Type create to create a new voucher."), LIST("Type list to list all vouchers."); + private final String printMessage; - private final static Map VOUCHER_MENU_MAP; + private static final Map VOUCHER_MENU_MAP; + static { VOUCHER_MENU_MAP = new ConcurrentHashMap<>(); Arrays.stream(VoucherMenu.values()) @@ -25,7 +30,7 @@ public static VoucherMenu getMenu(String userInput) { if (VOUCHER_MENU_MAP.containsKey(userInput)) { return VOUCHER_MENU_MAP.get(userInput); } - throw new RuntimeException(ExceptionMsg.NOT_MENU.getMsg()); + throw new VoucherException(ExceptionCode.NOT_MENU); } @Override diff --git a/src/main/java/org/weekly/weekly/ui/CommandLineApplication.java b/src/main/java/org/weekly/weekly/ui/CommandLineApplication.java index 5798232ca1..80e84e9730 100644 --- a/src/main/java/org/weekly/weekly/ui/CommandLineApplication.java +++ b/src/main/java/org/weekly/weekly/ui/CommandLineApplication.java @@ -4,23 +4,26 @@ import org.springframework.stereotype.Component; import org.weekly.weekly.customer.dto.request.CustomerCreationRequest; import org.weekly.weekly.customer.dto.request.CustomerUpdateRequest; +import org.weekly.weekly.customer.dto.response.CustomerResponse; +import org.weekly.weekly.customer.dto.response.CustomersResponse; +import org.weekly.weekly.global.util.CustomerMenu; +import org.weekly.weekly.global.util.ManageMenu; +import org.weekly.weekly.global.util.Menu; +import org.weekly.weekly.global.util.VoucherMenu; import org.weekly.weekly.ui.exception.InputValidator; import org.weekly.weekly.ui.reader.CommandReader; import org.weekly.weekly.ui.writer.SystemWriter; -import org.weekly.weekly.util.CustomerMenu; -import org.weekly.weekly.util.ManageMenu; -import org.weekly.weekly.util.Menu; import org.weekly.weekly.voucher.domain.DiscountType; -import org.weekly.weekly.util.VoucherMenu; -import org.weekly.weekly.voucher.dto.Response; -import org.weekly.weekly.voucher.dto.request.VoucherInfoRequest; import org.weekly.weekly.voucher.dto.request.VoucherCreationRequest; +import org.weekly.weekly.voucher.dto.request.VoucherInfoRequest; +import org.weekly.weekly.voucher.dto.response.VoucherCreationResponse; +import org.weekly.weekly.voucher.dto.response.VouchersResponse; -import java.util.List; import java.util.function.Supplier; @Component public class CommandLineApplication { + private final CommandReader commandReader; private final SystemWriter commandWriter; @@ -31,28 +34,28 @@ public CommandLineApplication(CommandReader commandReader, SystemWriter commandW } public ManageMenu readManageMenu() { - return readMenu(()-> { + return readMenu(() -> { commandWriter.printMangeProgram(); return ManageMenu.getMenu(readMenuInput()); }); } public VoucherMenu readVoucherMenu() { - return readMenu(()-> { + return readMenu(() -> { commandWriter.printVoucherProgram(); return VoucherMenu.getMenu(readMenuInput()); }); } public CustomerMenu readCustomerMenu() { - return readMenu(()-> { + return readMenu(() -> { commandWriter.printCustomerProgram(); return CustomerMenu.getMenu(readMenuInput()); }); } public VoucherCreationRequest createVoucherFromInput() { - while(true) { + while (true) { try { DiscountType discountType = readDiscountType(); VoucherInfoRequest voucherInfoRequest = readVoucherInfo(discountType); @@ -64,7 +67,7 @@ public VoucherCreationRequest createVoucherFromInput() { } public CustomerCreationRequest createCustomerFromInput() { - while(true) { + while (true) { try { String email = processEmail(); String name = processName(); @@ -76,22 +79,22 @@ public CustomerCreationRequest createCustomerFromInput() { } public CustomerUpdateRequest customerDetailFromInput() { - while(true) { + while (true) { try { String email = processEmail(); - return CustomerUpdateRequest.of(email); + return new CustomerUpdateRequest(email); } catch (Exception exception) { printErrorMsg(exception.getMessage()); } } } - public CustomerUpdateRequest customerUpdateRequest(){ - while(true) { + public CustomerUpdateRequest customerUpdateRequest() { + while (true) { try { String email = processEmail(); String newEmail = processNewEmail(); - return CustomerUpdateRequest.of(email, newEmail); + return new CustomerUpdateRequest(email, newEmail); } catch (Exception exception) { printErrorMsg(exception.getMessage()); } @@ -102,15 +105,26 @@ public void printErrorMsg(String errorMsg) { commandWriter.printErrorMessage(errorMsg); } - public void printResult(Response response) { - commandWriter.printReuslt(response.getResult()); + public void printResult(VoucherCreationResponse voucherCreationResponse) { + commandWriter.printResult(voucherCreationResponse.result()); + } + + public void printResult(VouchersResponse vouchersResponse) { + commandWriter.printResult(vouchersResponse.result()); + } + + public void printResult(CustomerResponse customerResponse) { + commandWriter.printResult(customerResponse.result()); + } + + public void printResult(CustomersResponse customerResponse) { + commandWriter.printResult(customerResponse.result()); } public void printDeleteMessage() { commandWriter.printDeleteMessage(); } - private String readMenuInput() { String userInput = commandReader.readLine(); InputValidator.isEmpty(userInput); @@ -124,7 +138,7 @@ private String readUserInput() { } private T readMenu(Supplier menuSupplier) { - while(true) { + while (true) { try { return menuSupplier.get(); } catch (Exception exception) { @@ -139,7 +153,7 @@ private DiscountType readDiscountType() { return DiscountType.getDiscountTypeByNumber(no); } - private VoucherInfoRequest readVoucherInfo(DiscountType discountType){ + private VoucherInfoRequest readVoucherInfo(DiscountType discountType) { commandWriter.printCreateVoucher(discountType); String voucherInfo = readUserInput(); return VoucherInfoRequest.of(voucherInfo); diff --git a/src/main/java/org/weekly/weekly/ui/exception/InputException.java b/src/main/java/org/weekly/weekly/ui/exception/InputException.java index 6eb0516cfb..6c56107daf 100644 --- a/src/main/java/org/weekly/weekly/ui/exception/InputException.java +++ b/src/main/java/org/weekly/weekly/ui/exception/InputException.java @@ -1,10 +1,10 @@ package org.weekly.weekly.ui.exception; -import org.weekly.weekly.util.ExceptionMsg; +import org.weekly.weekly.global.handler.ExceptionCode; -public class InputException extends RuntimeException{ +public class InputException extends RuntimeException { - public InputException(ExceptionMsg exception) { - super(exception.getMsg()); + public InputException(ExceptionCode exception) { + super(exception.getMessage()); } } diff --git a/src/main/java/org/weekly/weekly/ui/exception/InputValidator.java b/src/main/java/org/weekly/weekly/ui/exception/InputValidator.java index 0c4c3ef6c0..ff42dfa461 100644 --- a/src/main/java/org/weekly/weekly/ui/exception/InputValidator.java +++ b/src/main/java/org/weekly/weekly/ui/exception/InputValidator.java @@ -1,34 +1,35 @@ package org.weekly.weekly.ui.exception; -import org.weekly.weekly.util.ExceptionMsg; -import org.weekly.weekly.voucher.exception.VoucherException; +import org.weekly.weekly.global.handler.ExceptionCode; import java.util.Arrays; public class InputValidator { - public InputValidator() { - throw new InputException(ExceptionMsg.UTIL_CLASS); + + private InputValidator() { + throw new InputException(ExceptionCode.UTIL_CLASS); } private static final int VOUCHER_INPUT_SIZE = 2; + public static void isEmpty(String userInput) { if (userInput == null || userInput.isBlank()) { - throw new RuntimeException(ExceptionMsg.EMPTY.getMsg()); + throw new InputException(ExceptionCode.EMPTY); } } public static void notVoucherInputSize(String[] userInputs) { if (userInputs.length != VOUCHER_INPUT_SIZE) { - throw new InputException(ExceptionMsg.NOT_SAME_PARAM_SIZE); + throw new InputException(ExceptionCode.NOT_SAME_PARAM_SIZE); } } - + public static void notNumber(String[] userInputs) { try { Arrays.stream(userInputs) - .peek(Long::parseLong); + .forEach(userInput->Long.parseLong(userInput.trim())); } catch (NumberFormatException exception) { - throw new InputException(ExceptionMsg.NOT_INPUT_FORMAT); + throw new InputException(ExceptionCode.NOT_INPUT_FORMAT); } } } diff --git a/src/main/java/org/weekly/weekly/ui/reader/BufferedReaderWrap.java b/src/main/java/org/weekly/weekly/ui/reader/BufferedReaderWrap.java index 6542b3dc7c..08483777b5 100644 --- a/src/main/java/org/weekly/weekly/ui/reader/BufferedReaderWrap.java +++ b/src/main/java/org/weekly/weekly/ui/reader/BufferedReaderWrap.java @@ -2,28 +2,29 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; +import org.weekly.weekly.global.handler.ExceptionCode; import org.weekly.weekly.ui.exception.InputException; -import org.weekly.weekly.util.ExceptionMsg; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @Component -@ConditionalOnProperty(value="command.read", havingValue = "buffer") +@ConditionalOnProperty(value = "command.read", havingValue = "buffer") public class BufferedReaderWrap implements CommandReader { + private final BufferedReader bufferedReader; public BufferedReaderWrap() { - bufferedReader = new BufferedReader(new InputStreamReader(System.in)); + bufferedReader = new BufferedReader(new InputStreamReader(System.in)); } @Override - public String readLine(){ + public String readLine() { try { return bufferedReader.readLine(); } catch (IOException exception) { - throw new InputException(ExceptionMsg.NOT_INPUT_FORMAT); + throw new InputException(ExceptionCode.NOT_INPUT_FORMAT); } } } diff --git a/src/main/java/org/weekly/weekly/ui/reader/CommandReader.java b/src/main/java/org/weekly/weekly/ui/reader/CommandReader.java index 9ba5cf6055..2543b0e52a 100644 --- a/src/main/java/org/weekly/weekly/ui/reader/CommandReader.java +++ b/src/main/java/org/weekly/weekly/ui/reader/CommandReader.java @@ -1,7 +1,5 @@ package org.weekly.weekly.ui.reader; -import java.io.IOException; - public interface CommandReader { String readLine(); } diff --git a/src/main/java/org/weekly/weekly/ui/reader/ConsoleWrap.java b/src/main/java/org/weekly/weekly/ui/reader/ConsoleWrap.java index b4e02e6bb8..c77ca7ada1 100644 --- a/src/main/java/org/weekly/weekly/ui/reader/ConsoleWrap.java +++ b/src/main/java/org/weekly/weekly/ui/reader/ConsoleWrap.java @@ -6,16 +6,17 @@ import java.io.Console; @Component -@ConditionalOnProperty(value="command.read", havingValue = "console") -public class ConsoleWrap implements CommandReader{ - private final Console consoleWrap; +@ConditionalOnProperty(value = "command.read", havingValue = "console") +public class ConsoleWrap implements CommandReader { + + private final Console console; public ConsoleWrap() { - consoleWrap = System.console(); + console = System.console(); } @Override - public String readLine() { - return consoleWrap.readLine(); + public String readLine() { + return console.readLine(); } } diff --git a/src/main/java/org/weekly/weekly/ui/reader/ScannerWrap.java b/src/main/java/org/weekly/weekly/ui/reader/ScannerWrap.java index 35fb98e407..54346046fe 100644 --- a/src/main/java/org/weekly/weekly/ui/reader/ScannerWrap.java +++ b/src/main/java/org/weekly/weekly/ui/reader/ScannerWrap.java @@ -7,8 +7,9 @@ import java.util.Scanner; @Component -@ConditionalOnProperty(value="command.read", havingValue = "scanner") -public class ScannerWrap implements CommandReader{ +@ConditionalOnProperty(value = "command.read", havingValue = "scanner") +public class ScannerWrap implements CommandReader { + private final Scanner scanner; public ScannerWrap() { diff --git a/src/main/java/org/weekly/weekly/ui/writer/CommandWriter.java b/src/main/java/org/weekly/weekly/ui/writer/CommandWriter.java index f26b91797c..69770ff1a3 100644 --- a/src/main/java/org/weekly/weekly/ui/writer/CommandWriter.java +++ b/src/main/java/org/weekly/weekly/ui/writer/CommandWriter.java @@ -4,8 +4,10 @@ public interface CommandWriter { void printVoucherProgram(); - void printErrorMsg(String message); + + void printErrorMessage(String message); + void printCreateVoucher(DiscountType discountType); + void printSelectDiscount(); - void printReuslt(String result); } diff --git a/src/main/java/org/weekly/weekly/ui/writer/SystemWriter.java b/src/main/java/org/weekly/weekly/ui/writer/SystemWriter.java index 241130f9f4..848425ec92 100644 --- a/src/main/java/org/weekly/weekly/ui/writer/SystemWriter.java +++ b/src/main/java/org/weekly/weekly/ui/writer/SystemWriter.java @@ -4,19 +4,23 @@ import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; -import org.weekly.weekly.util.*; +import org.weekly.weekly.global.util.*; import org.weekly.weekly.voucher.domain.DiscountType; import java.util.Arrays; @Component -@ConditionalOnProperty(value="command.write", havingValue = "system") -public class SystemWriter { +@ConditionalOnProperty(value = "command.write", havingValue = "system") +public class SystemWriter implements CommandWriter { private final Logger logger = LoggerFactory.getLogger(SystemWriter.class); + private void println(String msg) { System.out.println(msg); } - private void print(String msg) {System.out.print(msg);} + + private void print(String msg) { + System.out.print(msg); + } public void printMangeProgram() { printMenu(ManageMenu.values(), PrintMessageType.MANAGE_PROGRAM); @@ -61,7 +65,7 @@ public void printNameInputMessage() { println(PrintMessageType.NAME_INPUT.getMessage()); } - public void printReuslt(String result) { + public void printResult(String result) { println(PrintMessageType.EMPTY.getMessage()); println(result); } @@ -70,7 +74,6 @@ public void printDeleteMessage() { println(PrintMessageType.DELETE.getMessage()); } - private void printMenu(Menu[] menus, PrintMessageType programMessage) { println(PrintMessageType.EMPTY.getMessage()); println(programMessage.getMessage()); diff --git a/src/main/java/org/weekly/weekly/util/ExceptionMsg.java b/src/main/java/org/weekly/weekly/util/ExceptionMsg.java deleted file mode 100644 index c77ec9ab02..0000000000 --- a/src/main/java/org/weekly/weekly/util/ExceptionMsg.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.weekly.weekly.util; - -public enum ExceptionMsg { - ERROR("[ERROR]: "), - UTIL_CLASS("유틸 클래스입니다."), - EMPTY("사용자가 아무 값도 입력하지 않았습니다."), - NOT_INPUT_FORMAT("입력 형식에 맞지 않습니다."), - NOT_MENU("해당 메뉴는 존재하지 않습니다."), - NOT_NUMBER_FORMAT("허용되지 않는 값입니다."), - NOT_NATURAL_NUMBER("자연수가 아닙니다."), - NOT_DISCOUNT("할인 종류가 아닙니다."), - EXPIRATION_ERROR("유효기간이 등록기간보다 빠릅니다."), - VOUCHER_EXIST("이미 존재하는 바우처입니다."), - NOT_FOUND("해당 종류의 할인정보를 찾을 수 없습니다."), - NOT_SAME_PARAM_SIZE("입력 파라미터 개수가 맞지 않습니다."), - NOT_EMAIL_FORMAT("이메일형식이 아닙니다."), - SQL_ERROR("값을 가져오기 실패"), - SQL_INSERT_ERROR("값 추가 실패"), - SQL_EXIST("이미 존재합니다."), - SQL_DELETE_ERROR("삭제 실패"); - - private final String msg; - - ExceptionMsg(String msg) { - this.msg = msg; - } - - public String getMsg() { - return ERROR.msg+msg; - } -} diff --git a/src/main/java/org/weekly/weekly/voucher/controller/VoucherController.java b/src/main/java/org/weekly/weekly/voucher/controller/VoucherController.java index 5e9c1e2804..c23a9a59b6 100644 --- a/src/main/java/org/weekly/weekly/voucher/controller/VoucherController.java +++ b/src/main/java/org/weekly/weekly/voucher/controller/VoucherController.java @@ -1,28 +1,25 @@ package org.weekly.weekly.voucher.controller; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; -import org.weekly.weekly.voucher.dto.Response; import org.weekly.weekly.voucher.dto.request.VoucherCreationRequest; +import org.weekly.weekly.voucher.dto.response.VoucherCreationResponse; +import org.weekly.weekly.voucher.dto.response.VouchersResponse; import org.weekly.weekly.voucher.service.VoucherService; @Controller public class VoucherController { - private final Logger logger = LoggerFactory.getLogger(VoucherController.class); - private final VoucherService voucherService; + private final VoucherService voucherService; public VoucherController(VoucherService voucherService) { this.voucherService = voucherService; } - - public Response createVoucher(VoucherCreationRequest voucherCreationRequest) { + public VoucherCreationResponse createVoucher(VoucherCreationRequest voucherCreationRequest) { return voucherService.insertVoucher(voucherCreationRequest); } - public Response getVouchers() { + public VouchersResponse getVouchers() { return voucherService.getVouchers(); } } diff --git a/src/main/java/org/weekly/weekly/voucher/controller/api/VoucherAPIController.java b/src/main/java/org/weekly/weekly/voucher/controller/api/VoucherAPIController.java new file mode 100644 index 0000000000..b050fab915 --- /dev/null +++ b/src/main/java/org/weekly/weekly/voucher/controller/api/VoucherAPIController.java @@ -0,0 +1,35 @@ +package org.weekly.weekly.voucher.controller.api; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.weekly.weekly.voucher.dto.request.VoucherCreationRequest; +import org.weekly.weekly.voucher.dto.response.VoucherCreationResponse; +import org.weekly.weekly.voucher.dto.response.VouchersResponse; +import org.weekly.weekly.voucher.service.VoucherService; + +import java.util.List; + +@RestController +@RequestMapping("/api/v1/vouchers") +public class VoucherAPIController { + + private final VoucherService voucherService; + + public VoucherAPIController(VoucherService voucherService) { + this.voucherService = voucherService; + } + + @PostMapping + public ResponseEntity createVoucher(@RequestBody VoucherCreationRequest voucherCreationRequest) { + VoucherCreationResponse voucherCreationResponse = voucherService.insertVoucher(voucherCreationRequest); + return new ResponseEntity<>(voucherCreationResponse, HttpStatus.OK); + } + + + @GetMapping + public ResponseEntity> getVouchers() { + VouchersResponse vouchersResponse = voucherService.getVouchers(); + return new ResponseEntity<>(vouchersResponse.getResult(), HttpStatus.OK); + } +} diff --git a/src/main/java/org/weekly/weekly/voucher/controller/web/VoucherWebController.java b/src/main/java/org/weekly/weekly/voucher/controller/web/VoucherWebController.java new file mode 100644 index 0000000000..1cdadbbfd9 --- /dev/null +++ b/src/main/java/org/weekly/weekly/voucher/controller/web/VoucherWebController.java @@ -0,0 +1,60 @@ +package org.weekly.weekly.voucher.controller.web; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.weekly.weekly.voucher.dto.request.VoucherCreationRequest; +import org.weekly.weekly.voucher.dto.response.VoucherCreationResponse; +import org.weekly.weekly.voucher.dto.response.VouchersResponse; +import org.weekly.weekly.voucher.exception.VoucherException; +import org.weekly.weekly.voucher.service.VoucherService; +import org.weekly.weekly.global.handler.WebExceptionDto; + +@Controller +@RequestMapping("/voucher") +public class VoucherWebController { + + private final VoucherService voucherService; + + public VoucherWebController(VoucherService voucherService) { + this.voucherService = voucherService; + } + + @GetMapping("/menu") + public String menu() { + return "voucher/menu"; + } + + @PostMapping("/create") + public String createVoucher(@ModelAttribute VoucherCreationRequest voucherCreationRequest, Model model) { + try { + VoucherCreationResponse voucherCreationResponse = voucherService.insertVoucher(voucherCreationRequest); + model.addAttribute("voucher", voucherCreationResponse); + } catch (VoucherException voucherException) { + model.addAttribute("exception", new WebExceptionDto(voucherException)); + return "exception/exception"; + } + return "redirect:/"; + } + + @GetMapping("/create") + public String createVoucher(Model model) { + model.addAttribute("voucherCreationRequest", new VoucherCreationRequest(null, null)); + return "voucher/create"; + } + + @GetMapping("/vouchers") + public String getVouchers(Model model) { + try { + VouchersResponse vouchersResponse = voucherService.getVouchers(); + model.addAttribute("vouchers", vouchersResponse); + } catch (VoucherException voucherException) { + model.addAttribute("exception", new WebExceptionDto(voucherException)); + return "exception/exception"; + } + return "voucher/vouchers"; + } +} diff --git a/src/main/java/org/weekly/weekly/voucher/domain/Discount.java b/src/main/java/org/weekly/weekly/voucher/domain/Discount.java index c7dc3708a2..48c68a54fe 100644 --- a/src/main/java/org/weekly/weekly/voucher/domain/Discount.java +++ b/src/main/java/org/weekly/weekly/voucher/domain/Discount.java @@ -2,5 +2,6 @@ public interface Discount { long applyDiscount(long beforeAmount, long discountAmount); + DiscountType discountType(); } diff --git a/src/main/java/org/weekly/weekly/voucher/domain/DiscountType.java b/src/main/java/org/weekly/weekly/voucher/domain/DiscountType.java index d27a2b602f..f871f313cc 100644 --- a/src/main/java/org/weekly/weekly/voucher/domain/DiscountType.java +++ b/src/main/java/org/weekly/weekly/voucher/domain/DiscountType.java @@ -1,6 +1,6 @@ package org.weekly.weekly.voucher.domain; -import org.weekly.weekly.util.ExceptionMsg; +import org.weekly.weekly.global.handler.ExceptionCode; import org.weekly.weekly.voucher.exception.VoucherException; import java.lang.reflect.InvocationTargetException; @@ -38,7 +38,7 @@ public static DiscountType getDiscountTypeByNumber(String no) { if (discuontTypeMap.containsKey(no)) { return discuontTypeMap.get(no); } - throw new VoucherException(ExceptionMsg.NOT_DISCOUNT); + throw new VoucherException(ExceptionCode.NOT_DISCOUNT); } public static DiscountType getDiscountTypeByName(String name) { @@ -47,19 +47,18 @@ public static DiscountType getDiscountTypeByName(String name) { return discount; } } - throw new VoucherException(ExceptionMsg.NOT_DISCOUNT); + throw new VoucherException(ExceptionCode.NOT_DISCOUNT); } public Discount getNewInstance() { try { return this.cls.getDeclaredConstructor().newInstance(); - } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) { - throw new VoucherException(ExceptionMsg.NOT_FOUND); + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | + InvocationTargetException exception) { + throw new VoucherException(ExceptionCode.NOT_FOUND); } - } - public String getSelectMessage() { return selectMessage; } diff --git a/src/main/java/org/weekly/weekly/voucher/domain/FixedDiscount.java b/src/main/java/org/weekly/weekly/voucher/domain/FixedDiscount.java index b8621eb46f..d0d8b4ed6a 100644 --- a/src/main/java/org/weekly/weekly/voucher/domain/FixedDiscount.java +++ b/src/main/java/org/weekly/weekly/voucher/domain/FixedDiscount.java @@ -1,6 +1,7 @@ package org.weekly.weekly.voucher.domain; -public class FixedDiscount implements Discount{ +public class FixedDiscount implements Discount { + @Override public long applyDiscount(long beforeAmount, long discountAmount) { return beforeAmount - discountAmount; diff --git a/src/main/java/org/weekly/weekly/voucher/domain/PercentDiscount.java b/src/main/java/org/weekly/weekly/voucher/domain/PercentDiscount.java index 8670ab08ca..c2b9485f63 100644 --- a/src/main/java/org/weekly/weekly/voucher/domain/PercentDiscount.java +++ b/src/main/java/org/weekly/weekly/voucher/domain/PercentDiscount.java @@ -1,7 +1,9 @@ package org.weekly.weekly.voucher.domain; -public class PercentDiscount implements Discount{ - private final int PERCENT = 100; +public class PercentDiscount implements Discount { + + private static final int PERCENT = 100; + @Override public long applyDiscount(long beforeAmount, long discountAmount) { return beforeAmount - beforeAmount * discountAmount / PERCENT; diff --git a/src/main/java/org/weekly/weekly/voucher/domain/Voucher.java b/src/main/java/org/weekly/weekly/voucher/domain/Voucher.java index f5242f721f..4b57c4e9c2 100644 --- a/src/main/java/org/weekly/weekly/voucher/domain/Voucher.java +++ b/src/main/java/org/weekly/weekly/voucher/domain/Voucher.java @@ -1,10 +1,7 @@ package org.weekly.weekly.voucher.domain; -import org.weekly.weekly.util.ExceptionMsg; -import org.weekly.weekly.voucher.exception.VoucherException; import org.weekly.weekly.voucher.exception.VoucherValidator; -import java.text.MessageFormat; import java.time.LocalDate; import java.util.UUID; @@ -17,7 +14,7 @@ public class Voucher { private long amount; - private Discount discount; + private final Discount discount; public Voucher(UUID voucherId, long amount, LocalDate registrationDate, LocalDate expirationDate, Discount discount) { diff --git a/src/main/java/org/weekly/weekly/voucher/dto/Response.java b/src/main/java/org/weekly/weekly/voucher/dto/Response.java deleted file mode 100644 index 86c2795d86..0000000000 --- a/src/main/java/org/weekly/weekly/voucher/dto/Response.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.weekly.weekly.voucher.dto; - -/** - * 모든 반환 값에 대해 동일한 동작을 적용시키고 싶어서 이렇게 했습니다. - */ -public interface Response { - String getResult(); -} diff --git a/src/main/java/org/weekly/weekly/voucher/dto/request/VoucherCreationRequest.java b/src/main/java/org/weekly/weekly/voucher/dto/request/VoucherCreationRequest.java index 76c137ed6e..e6527ae758 100644 --- a/src/main/java/org/weekly/weekly/voucher/dto/request/VoucherCreationRequest.java +++ b/src/main/java/org/weekly/weekly/voucher/dto/request/VoucherCreationRequest.java @@ -2,13 +2,13 @@ import org.weekly.weekly.voucher.domain.DiscountType; import org.weekly.weekly.voucher.domain.Voucher; -import org.weekly.weekly.voucher.exception.VoucherException; import java.time.LocalDate; import java.util.UUID; public class VoucherCreationRequest { - private final VoucherInfoRequest voucherInfoRequest; + + private VoucherInfoRequest voucherInfoRequest; private final DiscountType discountType; public VoucherCreationRequest(VoucherInfoRequest voucherInfoRequest, DiscountType discountType) { @@ -16,7 +16,19 @@ public VoucherCreationRequest(VoucherInfoRequest voucherInfoRequest, DiscountTyp this.discountType = discountType; } - public Voucher toVoucher() { + public VoucherInfoRequest getVoucherInfoRequest() { + return voucherInfoRequest; + } + + public void setVoucherInfoRequest(VoucherInfoRequest voucherInfoRequest) { + this.voucherInfoRequest = voucherInfoRequest; + } + + public DiscountType getDiscountType() { + return discountType; + } + + public Voucher toVoucher() { UUID id = UUID.randomUUID(); long amount = voucherInfoRequest.getAmount(); LocalDate now = LocalDate.now(); diff --git a/src/main/java/org/weekly/weekly/voucher/dto/request/VoucherInfoRequest.java b/src/main/java/org/weekly/weekly/voucher/dto/request/VoucherInfoRequest.java index 3aecb596c7..04f7658ac5 100644 --- a/src/main/java/org/weekly/weekly/voucher/dto/request/VoucherInfoRequest.java +++ b/src/main/java/org/weekly/weekly/voucher/dto/request/VoucherInfoRequest.java @@ -3,15 +3,18 @@ import org.weekly.weekly.ui.exception.InputValidator; public class VoucherInfoRequest { + private static final String SPLIT_FORMAT = ","; private static final int AMOUNT_NO = 0; private static final int EXPIRATION = 1; - private final long amount; - private final long expiration; + private long amount; + private long expiration; + public VoucherInfoRequest() { + } - private VoucherInfoRequest(long amount, long expiration) { + public VoucherInfoRequest(long amount, long expiration) { this.amount = amount; this.expiration = expiration; } @@ -25,6 +28,11 @@ public static VoucherInfoRequest of(String userInput) { Long.parseLong(inputs[EXPIRATION].trim())); } + private static void checkReadVoucherException(String[] inputs) { + InputValidator.notVoucherInputSize(inputs); + InputValidator.notNumber(inputs); + } + public long getAmount() { return amount; } @@ -33,8 +41,11 @@ public long getExpiration() { return expiration; } - private static void checkReadVoucherException(String[] inputs) { - InputValidator.notVoucherInputSize(inputs); - InputValidator.notNumber(inputs); + public void setAmount(long amount) { + this.amount = amount; + } + + public void setExpiration(long expiration) { + this.expiration = expiration; } } diff --git a/src/main/java/org/weekly/weekly/voucher/dto/response/VoucherCreationResponse.java b/src/main/java/org/weekly/weekly/voucher/dto/response/VoucherCreationResponse.java index f02d0703a6..1071e374c9 100644 --- a/src/main/java/org/weekly/weekly/voucher/dto/response/VoucherCreationResponse.java +++ b/src/main/java/org/weekly/weekly/voucher/dto/response/VoucherCreationResponse.java @@ -1,27 +1,48 @@ package org.weekly.weekly.voucher.dto.response; import org.weekly.weekly.voucher.domain.Voucher; -import org.weekly.weekly.voucher.dto.Response; import java.text.MessageFormat; import java.time.LocalDate; import java.util.UUID; -public class VoucherCreationResponse implements Response { +public class VoucherCreationResponse { + private final UUID id; private final LocalDate registrationDate; private final LocalDate expirationDate; private final long amount; + private final String voucherType; public VoucherCreationResponse(Voucher voucher) { this.id = voucher.getVoucherId(); this.registrationDate = voucher.getRegistrationDate(); this.expirationDate = voucher.getExpirationDate(); this.amount = voucher.getAmount(); + this.voucherType = voucher.getDiscountType().name(); + } + + public UUID getId() { + return id; + } + + public long getAmount() { + return amount; + } + + public LocalDate getExpirationDate() { + return expirationDate; + } + + public LocalDate getRegistrationDate() { + return registrationDate; + } + + public String getVoucherType() { + return voucherType; } - @Override - public String getResult() { + public String result() { return MessageFormat.format("[ID: {0}, 금액: {1}, 등록일자: {2}, 유효기간: {3}]", id, amount, registrationDate, expirationDate); } } diff --git a/src/main/java/org/weekly/weekly/voucher/dto/response/VouchersResponse.java b/src/main/java/org/weekly/weekly/voucher/dto/response/VouchersResponse.java index 64b16be1ce..263afc1f8d 100644 --- a/src/main/java/org/weekly/weekly/voucher/dto/response/VouchersResponse.java +++ b/src/main/java/org/weekly/weekly/voucher/dto/response/VouchersResponse.java @@ -1,29 +1,31 @@ package org.weekly.weekly.voucher.dto.response; -import org.weekly.weekly.util.PrintMessageType; +import org.weekly.weekly.global.util.PrintMessageType; import org.weekly.weekly.voucher.domain.Voucher; -import org.weekly.weekly.voucher.dto.Response; import java.util.List; -import java.util.stream.Collectors; -public class VouchersResponse implements Response { +public class VouchersResponse { + private final List result; public VouchersResponse(List vouchers) { this.result = vouchers.stream() .map(VoucherCreationResponse::new) - .collect(Collectors.toUnmodifiableList()); + .toList(); + } + + public List getResult() { + return result; } - public String getResult() { + public String result() { if (result.isEmpty()) { return PrintMessageType.NO_VOUCHER_DATAS.getMessage(); } - StringBuilder resultBuilder = new StringBuilder(); - result.forEach(voucherResponse-> resultBuilder.append(voucherResponse.getResult()).append('\n')); + result.forEach(voucherResponse -> resultBuilder.append(voucherResponse.result()).append('\n')); return resultBuilder.toString(); } } diff --git a/src/main/java/org/weekly/weekly/voucher/exception/VoucherException.java b/src/main/java/org/weekly/weekly/voucher/exception/VoucherException.java index a9743019c0..d7af54212e 100644 --- a/src/main/java/org/weekly/weekly/voucher/exception/VoucherException.java +++ b/src/main/java/org/weekly/weekly/voucher/exception/VoucherException.java @@ -1,9 +1,17 @@ package org.weekly.weekly.voucher.exception; -import org.weekly.weekly.util.ExceptionMsg; +import org.weekly.weekly.global.handler.ExceptionCode; -public class VoucherException extends RuntimeException{ - public VoucherException(ExceptionMsg exceptionMsg) { - super(exceptionMsg.getMsg()); +public class VoucherException extends RuntimeException { + + private final ExceptionCode exceptionCode; + + public VoucherException(ExceptionCode exceptionMsg) { + super(exceptionMsg.getMessage()); + this.exceptionCode = exceptionMsg; + } + + public ExceptionCode getExceptionCode() { + return exceptionCode; } } diff --git a/src/main/java/org/weekly/weekly/voucher/exception/VoucherValidator.java b/src/main/java/org/weekly/weekly/voucher/exception/VoucherValidator.java index 872558d980..b4efecdb54 100644 --- a/src/main/java/org/weekly/weekly/voucher/exception/VoucherValidator.java +++ b/src/main/java/org/weekly/weekly/voucher/exception/VoucherValidator.java @@ -1,38 +1,40 @@ package org.weekly.weekly.voucher.exception; -import org.weekly.weekly.util.ExceptionMsg; +import org.weekly.weekly.global.handler.ExceptionCode; import org.weekly.weekly.voucher.domain.DiscountType; import java.time.LocalDate; import java.util.function.LongPredicate; public class VoucherValidator { + private static final int RANGE_START = 0; private static final int RANGE_END = 100; private VoucherValidator() { - throw new VoucherException(ExceptionMsg.UTIL_CLASS); + throw new VoucherException(ExceptionCode.UTIL_CLASS); } public static void validateExpiration(LocalDate registrationDate, long expirationMonth) { LocalDate expirationDate = registrationDate.plusMonths(expirationMonth); if (registrationDate.isEqual(expirationDate) || registrationDate.isAfter(expirationDate)) { - throw new VoucherException(ExceptionMsg.EXPIRATION_ERROR); + throw new VoucherException(ExceptionCode.EXPIRATION_ERROR); } } + public static void validateAmount(DiscountType discountType, long amount) { if (DiscountType.FIXED.equals(discountType)) { notRange(amount, input -> input < RANGE_START); return; } - notRange(amount, input -> input < RANGE_START || input > RANGE_END); + notRange(amount, input -> input <= RANGE_START || input > RANGE_END); } private static void notRange(long userInput, LongPredicate ifCase) { if (ifCase.test(userInput)) { - throw new VoucherException(ExceptionMsg.NOT_NUMBER_FORMAT); + throw new VoucherException(ExceptionCode.NOT_NUMBER_FORMAT); } } } diff --git a/src/main/java/org/weekly/weekly/voucher/repository/JdbcVoucherRepository.java b/src/main/java/org/weekly/weekly/voucher/repository/JdbcVoucherRepository.java index 8892e68ef2..e69e54016c 100644 --- a/src/main/java/org/weekly/weekly/voucher/repository/JdbcVoucherRepository.java +++ b/src/main/java/org/weekly/weekly/voucher/repository/JdbcVoucherRepository.java @@ -5,7 +5,7 @@ import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; -import org.weekly.weekly.util.ExceptionMsg; +import org.weekly.weekly.global.handler.ExceptionCode; import org.weekly.weekly.voucher.domain.DiscountType; import org.weekly.weekly.voucher.domain.Voucher; import org.weekly.weekly.voucher.exception.VoucherException; @@ -22,13 +22,23 @@ @Profile("!dev") @Repository -public class JdbcVoucherRepository implements VoucherRepository{ +public class JdbcVoucherRepository implements VoucherRepository { + private final JdbcTemplate jdbcTemplate; public JdbcVoucherRepository(DataSource dataSource) { jdbcTemplate = new JdbcTemplate(dataSource); } + public static UUID toUUID(byte[] bytes) { + var buffer = ByteBuffer.wrap(bytes); + return new UUID(buffer.getLong(), buffer.getLong()); + } + + private byte[] uuidToBytes(UUID voucherId) { + return voucherId.toString().getBytes(); + } + @Override public Optional findById(UUID voucherId) { String sql = "SELECT * FROM vouchers WHERE voucher_id = UUID_TO_BIN(?)"; @@ -62,12 +72,12 @@ public Voucher insert(Voucher voucher) { voucher.getDiscountType().name(), Timestamp.valueOf(voucher.getRegistrationDate().atStartOfDay()), Timestamp.valueOf(voucher.getExpirationDate().atStartOfDay())); - } catch(DataAccessException dataAccessException) { - throw new VoucherException(ExceptionMsg.SQL_INSERT_ERROR); + } catch (DataAccessException dataAccessException) { + throw new VoucherException(ExceptionCode.SQL_INSERT_ERROR); } if (update != 1) { - throw new VoucherException(ExceptionMsg.SQL_ERROR); + throw new VoucherException(ExceptionCode.SQL_ERROR); } return voucher; } @@ -82,7 +92,7 @@ public Voucher update(Voucher voucher) { Timestamp.valueOf(voucher.getExpirationDate().atStartOfDay()), uuidToBytes(voucher.getVoucherId())); if (update != 1) { - throw new VoucherException(ExceptionMsg.SQL_ERROR); + throw new VoucherException(ExceptionCode.SQL_ERROR); } return voucher; } @@ -99,15 +109,6 @@ public void deleteAll() { jdbcTemplate.update(sql); } - public static UUID toUUID(byte[] bytes) { - var buffer = ByteBuffer.wrap(bytes); - return new UUID(buffer.getLong(), buffer.getLong()); - } - - private byte[] uuidToBytes(UUID voucherId) { - return voucherId.toString().getBytes(); - } - private Voucher mapToVoucher(ResultSet resultSet) throws SQLException { UUID voucherId = toUUID(resultSet.getBytes("voucher_id")); long amount = resultSet.getLong("amount"); @@ -115,9 +116,6 @@ private Voucher mapToVoucher(ResultSet resultSet) throws SQLException { LocalDate registrationDate = resultSet.getTimestamp("registration_date") == null ? null : resultSet.getTimestamp("registration_date").toLocalDateTime().toLocalDate(); LocalDate expirationDate = resultSet.getTimestamp("expiration_date") == null ? null : resultSet.getTimestamp("expiration_date").toLocalDateTime().toLocalDate(); - return new Voucher(voucherId,amount, registrationDate, expirationDate, discountType.getNewInstance()); + return new Voucher(voucherId, amount, registrationDate, expirationDate, discountType.getNewInstance()); } - - - } diff --git a/src/main/java/org/weekly/weekly/voucher/repository/MemoryVoucherRepository.java b/src/main/java/org/weekly/weekly/voucher/repository/MemoryVoucherRepository.java index e1b8d1bc70..78328ec1ac 100644 --- a/src/main/java/org/weekly/weekly/voucher/repository/MemoryVoucherRepository.java +++ b/src/main/java/org/weekly/weekly/voucher/repository/MemoryVoucherRepository.java @@ -2,7 +2,7 @@ import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Repository; -import org.weekly.weekly.util.ExceptionMsg; +import org.weekly.weekly.global.handler.ExceptionCode; import org.weekly.weekly.voucher.domain.DiscountType; import org.weekly.weekly.voucher.domain.Voucher; import org.weekly.weekly.voucher.exception.VoucherException; @@ -15,7 +15,8 @@ @Profile("dev") @Repository -public class MemoryVoucherRepository implements VoucherRepository{ +public class MemoryVoucherRepository implements VoucherRepository { + private final Map storages = new ConcurrentHashMap<>(); public Voucher insert(Voucher voucher) { @@ -56,7 +57,7 @@ public void deleteAll() { private void validateUUID(UUID uuid) { Optional voucherOptional = findById(uuid); if (voucherOptional.isPresent()) { - throw new VoucherException(ExceptionMsg.VOUCHER_EXIST); + throw new VoucherException(ExceptionCode.VOUCHER_EXIST); } } } diff --git a/src/main/java/org/weekly/weekly/voucher/repository/VoucherRepository.java b/src/main/java/org/weekly/weekly/voucher/repository/VoucherRepository.java index 0e794a4f2f..0bc962c767 100644 --- a/src/main/java/org/weekly/weekly/voucher/repository/VoucherRepository.java +++ b/src/main/java/org/weekly/weekly/voucher/repository/VoucherRepository.java @@ -9,7 +9,9 @@ public interface VoucherRepository { Voucher insert(Voucher voucher); + Optional findById(UUID voucherId); + List findAll(); List findByDiscountType(DiscountType discountType); diff --git a/src/main/java/org/weekly/weekly/voucher/service/VoucherService.java b/src/main/java/org/weekly/weekly/voucher/service/VoucherService.java index a79e89cd54..e48535e4fb 100644 --- a/src/main/java/org/weekly/weekly/voucher/service/VoucherService.java +++ b/src/main/java/org/weekly/weekly/voucher/service/VoucherService.java @@ -11,6 +11,7 @@ @Service public class VoucherService { + private final VoucherRepository voucherRepository; public VoucherService(VoucherRepository voucherRepository) { @@ -19,14 +20,12 @@ public VoucherService(VoucherRepository voucherRepository) { public VoucherCreationResponse insertVoucher(VoucherCreationRequest voucherCreationRequest) { Voucher voucher = voucherCreationRequest.toVoucher(); - voucherRepository.insert(voucher); - return new VoucherCreationResponse(voucher); + Voucher savedVoucher = voucherRepository.insert(voucher); + return new VoucherCreationResponse(savedVoucher); } public VouchersResponse getVouchers() { List vouchers = voucherRepository.findAll(); return new VouchersResponse(vouchers); } - - } diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 90244d6551..e0316ef90e 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -13,6 +13,10 @@ spring: sql: init: mode: always + schema-locations: + - classpath:db-init/schema.sql + data-locations: + - classpath:db-init/data.sql --- @@ -39,8 +43,12 @@ spring: datasource: url: jdbc:tc:mysql:8://test + sql: init: mode: always - + schema-locations: + - classpath:db-init/schema.sql + data-locations: + - classpath:db-init/data.sql diff --git a/src/main/resources/db-init/data.sql b/src/main/resources/db-init/data.sql new file mode 100644 index 0000000000..119716bc80 --- /dev/null +++ b/src/main/resources/db-init/data.sql @@ -0,0 +1,9 @@ +INSERT INTO customers(customer_id, name, email) +VALUES (uuid_to_bin(UUID()), 'tester00', 'test00@gmail.com'), + (uuid_to_bin(UUID()), 'tester01', 'test01@gmail.com'), + (uuid_to_bin(UUID()), 'tester02', 'test02@gmail.com'); + +INSERT INTO vouchers (voucher_id, amount, discount, expiration_date) +VALUES (uuid_to_bin(UUID()), 50, 'PERCENT', DATE_ADD(CURRENT_TIMESTAMP(6), INTERVAL 7 DAY)), + (uuid_to_bin(UUID()), 100000, 'FIXED', DATE_ADD(CURRENT_TIMESTAMP(6), INTERVAL 7 DAY)), + (uuid_to_bin(UUID()), 80, 'PERCENT', DATE_ADD(CURRENT_TIMESTAMP(6), INTERVAL 7 DAY)); \ No newline at end of file diff --git a/src/main/resources/db-init/schema.sql b/src/main/resources/db-init/schema.sql new file mode 100644 index 0000000000..12d8d04cb8 --- /dev/null +++ b/src/main/resources/db-init/schema.sql @@ -0,0 +1,21 @@ +DROP TABLE IF EXISTS customers; +CREATE TABLE customers +( + customer_id BINARY(16) PRIMARY KEY, + name varchar(20) NOT NULL, + email varchar(50) NOT NULL, + create_at datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP (6), + CONSTRAINT unq_user_email UNIQUE (email) +); + + + +DROP TABLE IF EXISTS vouchers; +CREATE TABLE vouchers +( + voucher_id BINARY(16) PRIMARY KEY, + amount bigint NOT NULL, + discount enum('FIXED', 'PERCENT') NOT NULL, + registration_date datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP (6), + expiration_date datetime(6) NOT NULL +); diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 41b5312d80..b59a5e22ad 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -12,10 +12,10 @@ - + - + diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql deleted file mode 100644 index 0b88d26b44..0000000000 --- a/src/main/resources/schema.sql +++ /dev/null @@ -1,29 +0,0 @@ -DROP TABLE IF EXISTS customers; -CREATE TABLE customers ( - customer_id BINARY(16) PRIMARY KEY, - name varchar(20) NOT NULL, - email varchar(50) NOT NULL, - create_at datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), - CONSTRAINT unq_user_email UNIQUE (email) -); - -INSERT INTO customers(customer_id, name, email) -VALUES (uuid_to_bin(UUID()), 'tester00', 'test00@gmail.com'), - (uuid_to_bin(UUID()), 'tester01', 'test01@gmail.com'), - (uuid_to_bin(UUID()), 'tester02', 'test02@gmail.com'); - - - -DROP TABLE IF EXISTS vouchers; -CREATE TABLE vouchers ( - voucher_id BINARY(16) PRIMARY KEY, - amount bigint NOT NULL, - discount enum('FIXED', 'PERCENT') NOT NULL, - registration_date datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), - expiration_date datetime(6) NOT NULL -); - -INSERT INTO vouchers (voucher_id, amount, discount, expiration_date) -VALUES (uuid_to_bin(UUID()), 50, 'PERCENT', DATE_ADD(CURRENT_TIMESTAMP(6), INTERVAL 7 DAY)), - (uuid_to_bin(UUID()), 100000, 'FIXED', DATE_ADD(CURRENT_TIMESTAMP(6), INTERVAL 7 DAY)), - (uuid_to_bin(UUID()), 80, 'PERCENT', DATE_ADD(CURRENT_TIMESTAMP(6), INTERVAL 7 DAY)); \ No newline at end of file diff --git a/src/main/resources/static/form.css b/src/main/resources/static/form.css new file mode 100644 index 0000000000..21a1259fd4 --- /dev/null +++ b/src/main/resources/static/form.css @@ -0,0 +1,171 @@ +* { + margin: 0; + padding: 0; + outline: none; + box-sizing: border-box; + font-family: 'Poppins', sans-serif; +} + +body { + display: flex; + align-items: center; + justify-content: center; + min-height: 100vh; + padding: 10px; + font-family: 'Poppins', sans-serif; +} + +.container { + max-width: 800px; + background: #fff; + width: 800px; + padding: 25px 40px 10px 40px; + box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1); +} + +.text { + color: #3498db; +} + +.container .text { + text-align: center; + font-size: 41px; + font-weight: 600; + font-family: 'Poppins', sans-serif; +} + +.container form { + padding: 30px 0 0 0; +} + +.container form .form-row { + display: flex; + margin: 32px 0; +} + +form .form-row .input-data { + width: 100%; + height: 40px; + margin: 0 20px; + position: relative; +} + +form .form-row .textarea { + height: 70px; +} + +.input-data input, +.textarea textarea { + display: block; + width: 100%; + height: 100%; + border: none; + font-size: 17px; + border-bottom: 2px solid rgba(0, 0, 0, 0.12); +} + +.input-data input:focus ~ label, .textarea textarea:focus ~ label, +.input-data input:valid ~ label, .textarea textarea:valid ~ label { + transform: translateY(-20px); + font-size: 14px; + color: #3498db; +} + +.textarea textarea { + resize: none; + padding-top: 10px; +} + +.input-data label { + position: absolute; + pointer-events: none; + bottom: 10px; + font-size: 16px; + transition: all 0.3s ease; +} + +.textarea label { + width: 100%; + bottom: 40px; + background: #fff; +} + +.input-data .underline { + position: absolute; + bottom: 0; + height: 2px; + width: 100%; + background: #3498db; +} + +.input-data .underline:before { + position: absolute; + content: ""; + height: 2px; + width: 100%; + background: #3498db; + transform: scaleX(0); + transform-origin: center; + transition: transform 0.3s ease; +} + +.input-data input:focus ~ .underline:before, +.input-data input:valid ~ .underline:before, +.textarea textarea:focus ~ .underline:before, +.textarea textarea:valid ~ .underline:before { + transform: scale(1); +} + +.submit-btn .input-data { + overflow: hidden; + height: 45px !important; + width: 25% !important; +} + +.submit-btn .input-data .inner { + height: 100%; + width: 300%; + position: absolute; + left: -100%; + transition: all 0.4s; + background-color: #56d8e4; +} + +.submit-btn .input-data:hover .inner { + left: 0; +} + +.submit-btn .input-data input { + background: none; + border: none; + color: #fff; + font-size: 17px; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 1px; + cursor: pointer; + position: relative; + z-index: 2; +} + +@media (max-width: 700px) { + .container .text { + font-size: 30px; + } + + .container form { + padding: 10px 0 0 0; + } + + .container form .form-row { + display: block; + } + + form .form-row .input-data { + margin: 35px 0 !important; + } + + .submit-btn .input-data { + width: 40% !important; + } +} \ No newline at end of file diff --git a/src/main/resources/static/main.css b/src/main/resources/static/main.css new file mode 100644 index 0000000000..106ec7a98d --- /dev/null +++ b/src/main/resources/static/main.css @@ -0,0 +1,9 @@ +.title-line { + text-align: center; +} + +.menu-list { + list-style: none; + padding: 0; + text-align: center; +} \ No newline at end of file diff --git a/src/main/resources/templates/customer/createCustomer.html b/src/main/resources/templates/customer/createCustomer.html new file mode 100644 index 0000000000..2417195ea8 --- /dev/null +++ b/src/main/resources/templates/customer/createCustomer.html @@ -0,0 +1,17 @@ + + + + Document + + +
+
+

고객 생성

+ Home +
+ +
+
+ + + diff --git a/src/main/resources/templates/customer/customerInfo.html b/src/main/resources/templates/customer/customerInfo.html new file mode 100644 index 0000000000..e32bf436a9 --- /dev/null +++ b/src/main/resources/templates/customer/customerInfo.html @@ -0,0 +1,23 @@ + + + + Customer Info + + +
+
+

고객 정보

+ Home +
+
+ + + + +
+
+
+ + + + diff --git a/src/main/resources/templates/customer/deleteAll.html b/src/main/resources/templates/customer/deleteAll.html new file mode 100644 index 0000000000..187962b4e4 --- /dev/null +++ b/src/main/resources/templates/customer/deleteAll.html @@ -0,0 +1,17 @@ + + + + + Title + + +
+
+

고객 전체 삭제

+ Home +
+ +
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/customer/deleteCustomer.html b/src/main/resources/templates/customer/deleteCustomer.html new file mode 100644 index 0000000000..a8994eed04 --- /dev/null +++ b/src/main/resources/templates/customer/deleteCustomer.html @@ -0,0 +1,16 @@ + + + + Document + + +
+
+

고객 삭제

+ Home +
+ +
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/customer/findCustomer.html b/src/main/resources/templates/customer/findCustomer.html new file mode 100644 index 0000000000..6acdac3019 --- /dev/null +++ b/src/main/resources/templates/customer/findCustomer.html @@ -0,0 +1,17 @@ + + + + + Title + + +
+
+

고객 정보 찾기

+ Home +
+ +
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/customer/findCustomers.html b/src/main/resources/templates/customer/findCustomers.html new file mode 100644 index 0000000000..e8ef39e5b4 --- /dev/null +++ b/src/main/resources/templates/customer/findCustomers.html @@ -0,0 +1,25 @@ + + + + + Document + + +
+
+

고객 리스트

+ Home +
+
+ + + + + + + +
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/customer/menu.html b/src/main/resources/templates/customer/menu.html new file mode 100644 index 0000000000..9932fa0830 --- /dev/null +++ b/src/main/resources/templates/customer/menu.html @@ -0,0 +1,37 @@ + + + + Document + + +
+ +

회원 메뉴

+ + + +
+ + \ No newline at end of file diff --git a/src/main/resources/templates/customer/updateCustomer.html b/src/main/resources/templates/customer/updateCustomer.html new file mode 100644 index 0000000000..9a869dc5f9 --- /dev/null +++ b/src/main/resources/templates/customer/updateCustomer.html @@ -0,0 +1,17 @@ + + + + + Title + + +
+
+

고객 정보 업데이트

+ Home +
+ +
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/exception/exception.html b/src/main/resources/templates/exception/exception.html new file mode 100644 index 0000000000..210b00ce64 --- /dev/null +++ b/src/main/resources/templates/exception/exception.html @@ -0,0 +1,14 @@ + + + + + + + Document + + +

Error Page

+

+ + \ No newline at end of file diff --git a/src/main/resources/templates/global/customer.html b/src/main/resources/templates/global/customer.html new file mode 100644 index 0000000000..1fe1b6735d --- /dev/null +++ b/src/main/resources/templates/global/customer.html @@ -0,0 +1,18 @@ +
+ + + 번호 + 이름 + 이에밀 + 생성일 + + +
+ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/global/form.html b/src/main/resources/templates/global/form.html new file mode 100644 index 0000000000..6beb0e0d09 --- /dev/null +++ b/src/main/resources/templates/global/form.html @@ -0,0 +1,104 @@ +
+
+
+ +
+
+
+
+ +
+
+
+
+ + +
+
+
+ +
+ +
+
+ +
+ +
+
+
+ + +
+
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+
+
+ +
+ +
+
+
+ + +
+
+
+
+
+ +
+
+
+
+ + +
+
+
+ +
+
+
+
+ +
+
+
+
+ + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
\ No newline at end of file diff --git a/src/main/resources/templates/global/head.html b/src/main/resources/templates/global/head.html new file mode 100644 index 0000000000..388ec75fa8 --- /dev/null +++ b/src/main/resources/templates/global/head.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/global/voucher.html b/src/main/resources/templates/global/voucher.html new file mode 100644 index 0000000000..0a0b0a1ba5 --- /dev/null +++ b/src/main/resources/templates/global/voucher.html @@ -0,0 +1,23 @@ +
+ + + 번호 + 바우처 아이디 + 할인가 + 바우처 타입 + 등록일 + 만료일 + + +
+ + + + + + + + + + + diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html new file mode 100644 index 0000000000..2f603203a6 --- /dev/null +++ b/src/main/resources/templates/index.html @@ -0,0 +1,28 @@ + + + + Document + + +
+ 1 +
+
+

메인 페이지

+ +
+ +
+ +
+ + \ No newline at end of file diff --git a/src/main/resources/templates/voucher/create.html b/src/main/resources/templates/voucher/create.html new file mode 100644 index 0000000000..0c4544cef7 --- /dev/null +++ b/src/main/resources/templates/voucher/create.html @@ -0,0 +1,17 @@ + + + + Document + + +
+
+

바우처 생성

+ Home +
+ +
+
+ + + diff --git a/src/main/resources/templates/voucher/menu.html b/src/main/resources/templates/voucher/menu.html new file mode 100644 index 0000000000..b0b195cdd8 --- /dev/null +++ b/src/main/resources/templates/voucher/menu.html @@ -0,0 +1,26 @@ + + + + Document + + +
+ +

회원 메뉴

+ + + +
+ + \ No newline at end of file diff --git a/src/main/resources/templates/voucher/vouchers.html b/src/main/resources/templates/voucher/vouchers.html new file mode 100644 index 0000000000..5e6a5a984c --- /dev/null +++ b/src/main/resources/templates/voucher/vouchers.html @@ -0,0 +1,25 @@ + + + + + Document + + +
+
+

바우처 리스트

+ Home +
+
+ + + + + + + +
+
+
+ + \ No newline at end of file diff --git a/src/test/java/org/weekly/weekly/VoucherManageApplicationTests.java b/src/test/java/org/weekly/weekly/VoucherManageApplicationTests.java index 4d2b02e11a..c7dd265580 100644 --- a/src/test/java/org/weekly/weekly/VoucherManageApplicationTests.java +++ b/src/test/java/org/weekly/weekly/VoucherManageApplicationTests.java @@ -1,13 +1,7 @@ package org.weekly.weekly; -import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest class VoucherManageApplicationTests { - - @Test - void contextLoads() { - } - } diff --git a/src/test/java/org/weekly/weekly/customer/CustomerTest.java b/src/test/java/org/weekly/weekly/customer/CustomerTest.java index a809768083..ba244eb902 100644 --- a/src/test/java/org/weekly/weekly/customer/CustomerTest.java +++ b/src/test/java/org/weekly/weekly/customer/CustomerTest.java @@ -8,9 +8,9 @@ import java.util.UUID; -import static org.hamcrest.MatcherAssert.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; public class CustomerTest { @@ -22,6 +22,6 @@ public class CustomerTest { @ParameterizedTest @ValueSource(strings = {"123", "123@", "213@n", "abc@naver.", "abc@naver.c", "abc@naver.comc"}) void 회원생성_실패_테스트(String email) { - assertThatThrownBy(()-> Customer.of(UUID.randomUUID(), "hello", email)).isInstanceOf(CustomerException.class); + assertThatThrownBy(() -> Customer.of(UUID.randomUUID(), "hello", email)).isInstanceOf(CustomerException.class); } } diff --git a/src/test/java/org/weekly/weekly/customer/JdbcCustomerRepositoryTest.java b/src/test/java/org/weekly/weekly/customer/JdbcCustomerRepositoryTest.java index 54b4f22fed..eff3456bf9 100644 --- a/src/test/java/org/weekly/weekly/customer/JdbcCustomerRepositoryTest.java +++ b/src/test/java/org/weekly/weekly/customer/JdbcCustomerRepositoryTest.java @@ -3,23 +3,19 @@ import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.ActiveProfiles; -import org.testcontainers.junit.jupiter.Testcontainers; +import org.springframework.test.jdbc.JdbcTestUtils; import org.weekly.weekly.customer.domain.Customer; -import org.weekly.weekly.customer.exception.CustomerException; import org.weekly.weekly.customer.repository.JdbcCustomerRepository; import java.util.List; import java.util.Optional; import java.util.UUID; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.samePropertyValuesAs; -@Testcontainers @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @ActiveProfiles("test") @SpringBootTest @@ -27,6 +23,9 @@ class JdbcCustomerRepositoryTest { @Autowired private JdbcCustomerRepository jdbcCustomerRepository; + @Autowired + private JdbcTemplate jdbcTemplate; + Customer customer; @BeforeEach @@ -36,7 +35,7 @@ void setUp() { @AfterEach void deleteCustomer() { - assertThatCode(() -> jdbcCustomerRepository.deleteByEmail(customer.getEmail())); + JdbcTestUtils.deleteFromTables(jdbcTemplate, "customers"); } @Test @@ -59,7 +58,9 @@ void deleteCustomer() { // Then assertThat(findCustomer.isEmpty(), is(false)); - assertThat(findCustomer.get(), samePropertyValuesAs(insertCustomer)); + assertThat(findCustomer.get().getCustomerId(), is(insertCustomer.getCustomerId())); + assertThat(findCustomer.get().getName(), is(insertCustomer.getName())); + assertThat(findCustomer.get().getEmail(), is(insertCustomer.getEmail())); } @Test @@ -99,7 +100,6 @@ void deleteCustomer() { void 회원_삭제_실패_테스트() { // when jdbcCustomerRepository.deleteByEmail(customer.getEmail()); - } @Test @@ -118,7 +118,7 @@ void deleteCustomer() { Customer insertCusomter = jdbcCustomerRepository.insert(customer); // When - jdbcCustomerRepository.update(insertCusomter,newName); + jdbcCustomerRepository.update(insertCusomter, newName); // Then Optional updateCustomer = jdbcCustomerRepository.findByEmail(newName); diff --git a/src/test/java/org/weekly/weekly/customer/dto/CustomerDtoTest.java b/src/test/java/org/weekly/weekly/customer/dto/CustomerDtoTest.java new file mode 100644 index 0000000000..d0f711119b --- /dev/null +++ b/src/test/java/org/weekly/weekly/customer/dto/CustomerDtoTest.java @@ -0,0 +1,74 @@ +package org.weekly.weekly.customer.dto; + +import org.junit.jupiter.api.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.weekly.weekly.customer.dto.request.CustomerCreationRequest; +import org.weekly.weekly.customer.dto.request.CustomerUpdateRequest; +import org.weekly.weekly.ui.exception.InputException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +@DisplayName("CustomerDto 테스트") +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +public class CustomerDtoTest { + + @DisplayName("CustomerUpdate: 업데이트, 삭제, 조회") + @Nested + class Update { + + @Test + void 고객정보_업데이트요청_성공_테스트() { + // Given + String email = "psy@naver.com"; + String newEamil = "newPsy@naver.com"; + + // When + CustomerUpdateRequest customerUpdateRequest = new CustomerUpdateRequest(email, newEamil); + + // Then + assertThat(customerUpdateRequest.email()).isEqualTo(email); + assertThat(customerUpdateRequest.newEmail()).isEqualTo(newEamil); + } + + @ParameterizedTest + @CsvSource({" , ", + "test, ", + ", test"}) + void 고객정보_잘못된_입력으로_업데이트_요청_실패_테스트(String email, String newEmail) { + assertThatThrownBy(() -> new CustomerUpdateRequest(email, newEmail)) + .isInstanceOf(InputException.class); + } + } + + @DisplayName("CustomerCreate") + @Nested + class Create { + + @Test + void 고객생성_요청_성공_테스트() { + // Given + String email = "email@naver.com"; + String name = "psy"; + + // When + CustomerCreationRequest customerCreationRequest = new CustomerCreationRequest(email, name); + + // Then + assertThat(customerCreationRequest.getEmail()).isEqualTo(email); + assertThat(customerCreationRequest.getName()).isEqualTo(name); + } + + @ParameterizedTest + @CsvSource({ + "email@naver.com, ", + ", name", + " , " + }) + void 고객정보_잘못된_입력으로_고객생성_요청_실패_테스트(String email, String name) { + assertThatThrownBy(() -> new CustomerUpdateRequest(email, name)) + .isInstanceOf(InputException.class); + } + } +} diff --git a/src/test/java/org/weekly/weekly/customer/service/CustomerServiceTest.java b/src/test/java/org/weekly/weekly/customer/service/CustomerServiceTest.java new file mode 100644 index 0000000000..a5dd066803 --- /dev/null +++ b/src/test/java/org/weekly/weekly/customer/service/CustomerServiceTest.java @@ -0,0 +1,225 @@ +package org.weekly.weekly.customer.service; + +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.transaction.annotation.Transactional; +import org.weekly.weekly.customer.domain.Customer; +import org.weekly.weekly.customer.dto.request.CustomerCreationRequest; +import org.weekly.weekly.customer.dto.request.CustomerUpdateRequest; +import org.weekly.weekly.customer.dto.response.CustomerResponse; +import org.weekly.weekly.customer.dto.response.CustomersResponse; +import org.weekly.weekly.customer.exception.CustomerException; +import org.weekly.weekly.customer.repository.CustomerRepository; +import org.weekly.weekly.customer.service.CustomerService; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.BDDMockito.any; +import static org.mockito.BDDMockito.given; + +@DisplayName("CustomerService 테스트") +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@ExtendWith(MockitoExtension.class) +public class CustomerServiceTest { + + @InjectMocks CustomerService customerService; + + @Mock CustomerRepository customerRepository; + + @Nested + class Create { + + private CustomerCreationRequest customerCreationRequest; + + @BeforeEach + void init_request() { + String email = "psy@naver.com"; + String name = "name"; + + customerCreationRequest = new CustomerCreationRequest(email, name); + } + + @Test + @Transactional + void 고객생성_성공_테스트() { + // Given + Customer customer = new Customer(UUID.randomUUID(), + customerCreationRequest.getName(), + customerCreationRequest.getEmail(), + LocalDateTime.now()); + CustomerResponse customerResponse = CustomerResponse.of(customer); + Customer savedCustomer = new Customer(customer.getCustomerId(), customer.getName(), customer.getEmail(), customer.getCreateAt()); + + given(customerRepository.findByEmail(customerCreationRequest.getEmail())).willReturn(Optional.empty()); + given(customerRepository.insert(any(Customer.class))).willReturn(savedCustomer); + + // When + CustomerResponse expectResponse = customerService.createCustomer(customerCreationRequest); + + // Then + assertThat(expectResponse).isNotNull(); + assertAll( + () -> assertThat(customerResponse.getEmail()).isEqualTo(expectResponse.getEmail()), + () -> assertThat(customerResponse.getName()).isEqualTo(expectResponse.getName()) + ); + } + + @Test + void 중복된_이메일으로_고객생성_실패_테스트() { + // Given + Customer customer = new Customer(UUID.randomUUID(), + customerCreationRequest.getName(), + customerCreationRequest.getEmail(), + LocalDateTime.now()); + given(customerRepository.findByEmail(customerCreationRequest.getEmail())).willReturn(Optional.of(customer)); + + // When + assertThatThrownBy(() -> customerService.createCustomer(customerCreationRequest)) + .isInstanceOf(CustomerException.class); + } + } + + @Nested + class Delete { + + private CustomerUpdateRequest customerUpdateRequest; + + @BeforeEach + void init_request() { + String email = "psy@naver.com"; + + customerUpdateRequest = new CustomerUpdateRequest(email); + } + + @Test + @Transactional + void 고객삭제_성공_테스트() { + // When + assertDoesNotThrow(() -> customerService.deleteCustomer(customerUpdateRequest)); + } + } + + @Nested + class Search { + + private CustomerUpdateRequest searchRequest; + + @BeforeEach + void init_request() { + String email = "psy@naver.com"; + + searchRequest = new CustomerUpdateRequest(email); + } + + @Test + void 고객_상세조회_성공_테스트() { + // Given + String mockName = "psy"; + Customer customer = new Customer(UUID.randomUUID(), + mockName, + searchRequest.email(), + LocalDateTime.now()); + CustomerResponse expectCustomer = CustomerResponse.of(customer); + + given(customerRepository.findByEmail(searchRequest.email())).willReturn(Optional.of(customer)); + + // When + CustomerResponse customerResponse = customerService.findDetailCustomer(searchRequest); + + // Then + assertThat(customerResponse).isNotNull(); + + assertAll( + () -> assertThat(expectCustomer.getName()).isEqualTo(customerResponse.getName()), + () -> assertThat(expectCustomer.getEmail()).isEqualTo(customerResponse.getEmail()), + () -> assertThat(expectCustomer.getCreateAt()).isEqualTo(customerResponse.getCreateAt()) + ); + } + + @Test + void 존재하지_않는_고객조회로_실패_테스트() { + // Given + given(customerRepository.findByEmail(searchRequest.email())).willReturn(Optional.empty()); + + // When + assertThatThrownBy(() -> customerService.findDetailCustomer(searchRequest)) + .isInstanceOf(CustomerException.class); + } + + @Test + void 모든_고객조회_성공_테스트() { + // Given + Customer mockCustomer = new Customer(UUID.randomUUID(), + "mock", + "mock@naver.com", + LocalDateTime.now()); + + given(customerRepository.findAll()).willReturn(List.of(mockCustomer)); + + // When + CustomersResponse customers = customerService.findAllCustomer(); + + // Then + assertThat(customers).isNotNull(); + assertThat(customers.getCustomerResponses()).isNotEmpty(); + } + } + + @Nested + class Update { + + private CustomerUpdateRequest updateRequest; + + @BeforeEach + void init_request() { + String email = "before@naver.com"; + String newEamil = "after@naver.com"; + + updateRequest = new CustomerUpdateRequest(email, newEamil); + } + + @Test + @Transactional + void 고객_이메일_업데이트_성공_테스트() { + // Given + String mockName = "mock"; + Customer customer = new Customer(UUID.randomUUID(), + mockName, + updateRequest.email(), + LocalDateTime.now()); + + Customer updatedCustomer = new Customer(customer.getCustomerId(), + customer.getName(), + updateRequest.newEmail(), + customer.getCreateAt()); + + CustomerResponse expectCustomer = CustomerResponse.of(updatedCustomer); + + given(customerRepository.findByEmail(updateRequest.newEmail())).willReturn(Optional.empty()); + given(customerRepository.findByEmail(updateRequest.email())).willReturn(Optional.of(customer)); + given(customerRepository.update(customer, updateRequest.newEmail())).willReturn(updatedCustomer); + + // When + CustomerResponse customerResponse = customerService.updateCustomer(updateRequest); + + // Then + assertThat(customerResponse).isNotNull(); + + assertAll( + () -> assertThat(expectCustomer.getName()).isEqualTo(customerResponse.getName()), + () -> assertThat(expectCustomer.getEmail()).isEqualTo(customerResponse.getEmail()), + () -> assertThat(expectCustomer.getCreateAt()).isEqualTo(customerResponse.getCreateAt()) + ); + } + } +} diff --git a/src/test/java/org/weekly/weekly/util/DiscountMapTest.java b/src/test/java/org/weekly/weekly/global/util/DiscountMapTest.java similarity index 90% rename from src/test/java/org/weekly/weekly/util/DiscountMapTest.java rename to src/test/java/org/weekly/weekly/global/util/DiscountMapTest.java index 3443ee7c77..61732248a6 100644 --- a/src/test/java/org/weekly/weekly/util/DiscountMapTest.java +++ b/src/test/java/org/weekly/weekly/global/util/DiscountMapTest.java @@ -1,4 +1,4 @@ -package org.weekly.weekly.util; +package org.weekly.weekly.global.util; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -18,7 +18,7 @@ public class DiscountMapTest { }) void 사용자_입력이_할인_맵에_없으면_예외발생(String userInput) { // when + then - assertThatThrownBy(()-> DiscountType.getDiscountTypeByNumber(userInput)) + assertThatThrownBy(() -> DiscountType.getDiscountTypeByNumber(userInput)) .isInstanceOf(RuntimeException.class); } diff --git a/src/test/java/org/weekly/weekly/util/VoucherMenuTest.java b/src/test/java/org/weekly/weekly/global/util/VoucherMenuTest.java similarity index 65% rename from src/test/java/org/weekly/weekly/util/VoucherMenuTest.java rename to src/test/java/org/weekly/weekly/global/util/VoucherMenuTest.java index 1eeaaa95d1..7f1f2f6556 100644 --- a/src/test/java/org/weekly/weekly/util/VoucherMenuTest.java +++ b/src/test/java/org/weekly/weekly/global/util/VoucherMenuTest.java @@ -1,23 +1,15 @@ -package org.weekly.weekly.util; +package org.weekly.weekly.global.util; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; public class VoucherMenuTest { @ParameterizedTest @ValueSource(strings = {"exti", "he lo", "123fdp", "test"}) void 사용자_입력이_Voucher_메뉴에_없을때_예외반환(String testValue) { - // given - - // when - - // then - - assertThatThrownBy(()->VoucherMenu.getMenu(testValue)) + assertThatThrownBy(() -> VoucherMenu.getMenu(testValue)) .isInstanceOf(RuntimeException.class); } } diff --git a/src/test/java/org/weekly/weekly/ui/ReadExceptionTest.java b/src/test/java/org/weekly/weekly/ui/ReadExceptionTest.java index ec1ee12655..f83fc0555e 100644 --- a/src/test/java/org/weekly/weekly/ui/ReadExceptionTest.java +++ b/src/test/java/org/weekly/weekly/ui/ReadExceptionTest.java @@ -10,7 +10,7 @@ public class ReadExceptionTest { @ParameterizedTest @ValueSource(strings = {"", " "}) void 사용자가_빈값이나_입력오류났을때_예외발생(String userInput) { - assertThatThrownBy(()-> InputValidator.isEmpty(userInput)) + assertThatThrownBy(() -> InputValidator.isEmpty(userInput)) .isInstanceOf(RuntimeException.class); } } diff --git a/src/test/java/org/weekly/weekly/voucher/JdbcVoucherRepositoryTest.java b/src/test/java/org/weekly/weekly/voucher/JdbcVoucherRepositoryTest.java index 6a47bcc496..105cbbf52b 100644 --- a/src/test/java/org/weekly/weekly/voucher/JdbcVoucherRepositoryTest.java +++ b/src/test/java/org/weekly/weekly/voucher/JdbcVoucherRepositoryTest.java @@ -1,11 +1,15 @@ package org.weekly.weekly.voucher; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.jdbc.JdbcTestUtils; import org.testcontainers.junit.jupiter.Testcontainers; import org.weekly.weekly.voucher.domain.DiscountType; import org.weekly.weekly.voucher.domain.Voucher; @@ -20,14 +24,17 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.samePropertyValuesAs; -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) + @ActiveProfiles("test") @Testcontainers @SpringBootTest -class JdbcVoucherRepositoryTest{ +class JdbcVoucherRepositoryTest { @Autowired private JdbcVoucherRepository jdbcVoucherRepository; + @Autowired + private JdbcTemplate jdbcTemplate; + Voucher fixedVoucher; Voucher percentVoucher; @@ -37,64 +44,97 @@ void setUp() { percentVoucher = Voucher.of(UUID.randomUUID(), 50, LocalDate.now(), 7, DiscountType.PERCENT); } + @AfterEach + void initDB() { + JdbcTestUtils.deleteFromTables(jdbcTemplate, "vouchers"); + } + @Test - @Order(1) void 전체_바우처_검색_테스트() { + // Given + jdbcVoucherRepository.insert(fixedVoucher); + jdbcVoucherRepository.insert(percentVoucher); + + // When List vouchers = jdbcVoucherRepository.findAll(); + + // Then assertThat(vouchers.isEmpty(), is(false)); } @Test - @Order(1) void 아이디를_통한_검색_실패_테스트() { + // When Optional voucher = jdbcVoucherRepository.findById(fixedVoucher.getVoucherId()); + + // Then assertThat(voucher.isEmpty(), is(true)); } @Test - @Order(1) void 아이디를_통한_검색_성공_테스트() { + // Given + jdbcVoucherRepository.insert(fixedVoucher); + + // When Optional voucher = jdbcVoucherRepository.findById(fixedVoucher.getVoucherId()); - assertThat(voucher.isPresent(), is(false)); + + // Then + assertThat(voucher.isPresent(), is(true)); } @Test - @Order(1) - void 할인정책을_통한_검색_테스트() { - List vouchers = jdbcVoucherRepository.findByDiscountType(percentVoucher.getDiscountType()); + void 고정_할인정책을_검색_테스트() { + // Given + jdbcVoucherRepository.insert(fixedVoucher); + + // When + List vouchers = jdbcVoucherRepository.findByDiscountType(DiscountType.FIXED); + // Then assertThat(vouchers.isEmpty(), is(false)); + } - vouchers.stream() - .forEach(voucher -> assertThat(voucher.getDiscountType(), is(DiscountType.PERCENT))); + @Test + void 퍼센트_할인정책을_검색_테스트() { + // Given + jdbcVoucherRepository.insert(percentVoucher); + + // When + List vouchers = jdbcVoucherRepository.findByDiscountType(DiscountType.PERCENT); + + // Then + assertThat(vouchers.isEmpty(), is(false)); } @Test - @Order(2) void 할인바우처_등록성공_테스트() { + // Given Voucher voucher = jdbcVoucherRepository.insert(percentVoucher); + // When Optional findVoucher = jdbcVoucherRepository.findById(percentVoucher.getVoucherId()); + // Then assertThat(findVoucher.isEmpty(), is(false)); assertThat(findVoucher.get(), samePropertyValuesAs(voucher)); } @Test - @Order(2) void 고정바우처_등록성공_테스트() { + // Given Voucher voucher = jdbcVoucherRepository.insert(fixedVoucher); + // When Optional findVoucher = jdbcVoucherRepository.findById(fixedVoucher.getVoucherId()); + // Then assertThat(findVoucher.isEmpty(), is(false)); assertThat(findVoucher.get(), samePropertyValuesAs(voucher)); } - @ParameterizedTest @CsvSource({"5000, 0", "15000, 5000"}) - @Order(3) void 고정바우처_정보_업데이트_테스트(int amount, long reaminExpected) { // Given jdbcVoucherRepository.insert(fixedVoucher); @@ -112,7 +152,6 @@ void setUp() { @ParameterizedTest @CsvSource({"3000, 1500", "1000, 500"}) - @Order(3) void 퍼센트바우처_정보_업데이트_테스트(int amount, long reaminExpected) { // Given jdbcVoucherRepository.insert(percentVoucher); @@ -129,7 +168,6 @@ void setUp() { } @Test - @Order(4) void 바우처_삭제_테스트() { // Given Voucher voucher = jdbcVoucherRepository.insert(percentVoucher); @@ -145,13 +183,16 @@ void setUp() { } @Test - @Order(5) void 전체_바우처_삭제_테스트() { // Given - jdbcVoucherRepository.deleteAll(); + jdbcVoucherRepository.insert(percentVoucher); + jdbcVoucherRepository.insert(fixedVoucher); - // when + // When + jdbcVoucherRepository.deleteAll(); List vouchers = jdbcVoucherRepository.findAll(); + + // Then assertThat(vouchers.isEmpty(), is(true)); } } diff --git a/src/test/java/org/weekly/weekly/voucher/VoucherTest.java b/src/test/java/org/weekly/weekly/voucher/VoucherTest.java index d786525500..799acc7d4e 100644 --- a/src/test/java/org/weekly/weekly/voucher/VoucherTest.java +++ b/src/test/java/org/weekly/weekly/voucher/VoucherTest.java @@ -14,7 +14,8 @@ import java.time.LocalDate; import java.util.UUID; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; public class VoucherTest { private MemoryVoucherRepository voucherRepository; @@ -29,7 +30,7 @@ void setVoucherRepository() { "100000,12: 1", "10,1: 1" }, delimiter = ':') - void 바우처가_이미_존재하면_예외발생(String userInput, String no) { + void 중복된_바우처_저장시_예외발생(String userInput, String no) { // Given UUID voucherId = UUID.randomUUID(); VoucherInfoRequest voucherInfo = VoucherInfoRequest.of(userInput); @@ -52,15 +53,13 @@ void setVoucherRepository() { }) void 바우처_발행시간이_유효시간보다_느리면_예외발생(String userInput) { // Given -// UUID voucherId = UUID.randomUUID(); -// LocalDate localDate = LocalDate.now(); DiscountType discount = DiscountType.FIXED; VoucherInfoRequest voucherInfo = VoucherInfoRequest.of(userInput); VoucherCreationRequest request = new VoucherCreationRequest(voucherInfo, discount); // when + then - assertThatThrownBy(()->request.toVoucher()) + assertThatThrownBy(() -> request.toVoucher()) .isInstanceOf(RuntimeException.class); } @@ -75,13 +74,13 @@ class 고정바우처_테스트 { // Given DiscountType discountType = DiscountType.FIXED; - VoucherInfoRequest voucherInfoRequest = VoucherInfoRequest.of(userInput); + VoucherInfoRequest voucherInfoRequest = VoucherInfoRequest.of(userInput); // when VoucherCreationRequest request = new VoucherCreationRequest(voucherInfoRequest, discountType); // then - assertThatThrownBy(()-> request.toVoucher()) + assertThatThrownBy(() -> request.toVoucher()) .isInstanceOf(RuntimeException.class); } @@ -118,7 +117,7 @@ class 퍼센트바우처_테스트 { // when + then - assertThatThrownBy(()->Voucher.of(voucherId, voucherInfo.getAmount(), now, 1, DiscountType.PERCENT)) + assertThatThrownBy(() -> Voucher.of(voucherId, voucherInfo.getAmount(), now, 1, DiscountType.PERCENT)) .isInstanceOf(RuntimeException.class); } diff --git a/src/test/java/org/weekly/weekly/voucher/dto/VoucherDtoTest.java b/src/test/java/org/weekly/weekly/voucher/dto/VoucherDtoTest.java new file mode 100644 index 0000000000..e4281f912a --- /dev/null +++ b/src/test/java/org/weekly/weekly/voucher/dto/VoucherDtoTest.java @@ -0,0 +1,90 @@ +package org.weekly.weekly.voucher.dto; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.weekly.weekly.ui.exception.InputException; +import org.weekly.weekly.voucher.domain.DiscountType; +import org.weekly.weekly.voucher.domain.Voucher; +import org.weekly.weekly.voucher.dto.request.VoucherCreationRequest; +import org.weekly.weekly.voucher.dto.request.VoucherInfoRequest; +import org.weekly.weekly.voucher.dto.response.VoucherCreationResponse; + +import java.text.MessageFormat; +import java.time.LocalDate; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +@DisplayName("CustomerDto 테스트") +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +public class VoucherDtoTest { + + @ParameterizedTest + @ValueSource(strings = { + "10, 10", + "50, 12", + "70, 123" + }) + void 고정바우처_생성_성공_테스트(String userInput) { + // Given + VoucherInfoRequest voucherInfoRequest = VoucherInfoRequest.of(userInput); + + // When + VoucherCreationRequest voucherCreationRequest = new VoucherCreationRequest(voucherInfoRequest, DiscountType.FIXED); + + // Then + assertThat(voucherCreationRequest).isNotNull(); + assertThat(voucherCreationRequest.getDiscountType()).isEqualTo(DiscountType.FIXED); + } + + @ParameterizedTest + @ValueSource(strings = { + "10, 10", + "50, 12", + "70, 123" + }) + void 퍼센트바우처_생성_성공_테스트(String userInput) { + // Given + VoucherInfoRequest voucherInfoRequest = VoucherInfoRequest.of(userInput); + + // When + VoucherCreationRequest voucherCreationRequest = new VoucherCreationRequest(voucherInfoRequest, DiscountType.PERCENT); + + // Then + assertThat(voucherCreationRequest).isNotNull(); + assertThat(voucherCreationRequest.getDiscountType()).isEqualTo(DiscountType.PERCENT); + } + + @ParameterizedTest + @ValueSource(strings = {" , ", + "가나다, ", + ", 나다라" + }) + void 바우처_잘못된_입력으로_실패_테스트(String userInput) { + // When + Then + assertThatThrownBy(() -> VoucherInfoRequest.of(userInput)) + .isInstanceOf(InputException.class); + + } + + @Test + void 바우처_생성요청에_대한_반환_메세지_테스트() { + // Given + Voucher voucher = Voucher.of(UUID.randomUUID(), + 1000L, + LocalDate.now(), + 12, + DiscountType.FIXED); + + VoucherCreationResponse creationResponse = new VoucherCreationResponse(voucher); + + assertThat(creationResponse.result()) + .isEqualTo(MessageFormat.format("[ID: {0}, 금액: {1}, 등록일자: {2}, 유효기간: {3}]", + voucher.getVoucherId(), voucher.getAmount(), voucher.getRegistrationDate(), voucher.getExpirationDate())); + } +} diff --git a/src/test/java/org/weekly/weekly/voucher/service/VoucherServiceTest.java b/src/test/java/org/weekly/weekly/voucher/service/VoucherServiceTest.java new file mode 100644 index 0000000000..a02480aebc --- /dev/null +++ b/src/test/java/org/weekly/weekly/voucher/service/VoucherServiceTest.java @@ -0,0 +1,88 @@ +package org.weekly.weekly.voucher.service; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.weekly.weekly.voucher.domain.DiscountType; +import org.weekly.weekly.voucher.domain.Voucher; +import org.weekly.weekly.voucher.dto.request.VoucherCreationRequest; +import org.weekly.weekly.voucher.dto.request.VoucherInfoRequest; +import org.weekly.weekly.voucher.dto.response.VoucherCreationResponse; +import org.weekly.weekly.voucher.repository.VoucherRepository; +import org.weekly.weekly.voucher.service.VoucherService; + +import java.time.LocalDate; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.any; +import static org.mockito.BDDMockito.given; + +@DisplayName("VoucherService 테스트") +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@ExtendWith(MockitoExtension.class) +public class VoucherServiceTest { + + @InjectMocks + VoucherService voucherService; + + @Mock + VoucherRepository voucherRepository; + + @Test + void 고정_바우처_생성_성공_테스트() { + // Given + Long amount = 1000000L; + Long expire = 1L; + LocalDate registrationDate = LocalDate.now(); + LocalDate expirationDate = LocalDate.now().plusDays(expire); + DiscountType discount = DiscountType.FIXED; + + VoucherInfoRequest voucherFixedInfo = new VoucherInfoRequest(amount, expire); + VoucherCreationRequest fixedRequest = new VoucherCreationRequest(voucherFixedInfo, discount); + Voucher mockVoucehr = new Voucher(UUID.randomUUID(), + amount, + registrationDate, + expirationDate, + discount.getNewInstance()); + + given(voucherRepository.insert(any(Voucher.class))).willReturn(mockVoucehr); + + // When + VoucherCreationResponse voucherCreationResponse = voucherService.insertVoucher(fixedRequest); + + // Then; + assertThat(voucherCreationResponse).isNotNull(); + } + + @Test + void 할인_바우처_생성_성공_테스트() { + // Given + Long percnet = 10L; + Long expire = 1L; + LocalDate registrationDate = LocalDate.now(); + LocalDate expirationDate = LocalDate.now().plusDays(expire); + DiscountType discount = DiscountType.PERCENT; + + VoucherInfoRequest voucherPercentInfo = new VoucherInfoRequest(percnet, expire); + VoucherCreationRequest percentRequest = new VoucherCreationRequest(voucherPercentInfo, discount); + Voucher mockVoucehr = new Voucher(UUID.randomUUID(), + percnet, + registrationDate, + expirationDate, + discount.getNewInstance()); + + given(voucherRepository.insert(any(Voucher.class))).willReturn(mockVoucehr); + + // When + VoucherCreationResponse voucherCreationResponse = voucherService.insertVoucher(percentRequest); + + // Then; + assertThat(voucherCreationResponse).isNotNull(); + } +}