Skip to content
Open
Show file tree
Hide file tree
Changes from 78 commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
d404a92
chore: add spring-boot-web dependency
IjjS Nov 1, 2023
c943839
feat: implement profile conditions
IjjS Nov 1, 2023
52604fe
refactor: apply profile conditions usage
IjjS Nov 1, 2023
7712ce8
feat: add voucher rest controller
IjjS Nov 1, 2023
9eeab54
refactor: decide to add percentage mark in formatter
IjjS Nov 2, 2023
4bba969
refactor: make VoucherResponse a record
IjjS Nov 2, 2023
29353f9
enhance: add createdAt to Voucher
IjjS Nov 2, 2023
1b9c323
chore: reset file
IjjS Nov 2, 2023
b39904f
feat: tell if the input is the same type of the voucher
IjjS Nov 2, 2023
a46bb32
feat: add findByType in repositories
IjjS Nov 2, 2023
85a4cfa
feat: implement findByType service
IjjS Nov 2, 2023
7a3e0e8
feat: map to find vouchers by type
IjjS Nov 2, 2023
5b9f5aa
feat: implemented to find vouchers by createdAt
IjjS Nov 2, 2023
cb5e395
feat: tell the info regarding createdAt from Voucher
IjjS Nov 2, 2023
f141525
feat: add api endpoint to find vouchers by createdAt
IjjS Nov 2, 2023
0d7498b
refactor: improve readability
IjjS Nov 2, 2023
48bb995
refactor: edit request variables to be close to primitive for validation
IjjS Nov 2, 2023
2fd2330
chore: add spring boot validation dependency
IjjS Nov 2, 2023
de91ea5
enhance: validate the create request from the controller
IjjS Nov 2, 2023
d0cee1d
enhance: add not null validation to SearchCreatedAtRequest
IjjS Nov 2, 2023
d0d6c67
chore: add jackson xml dataformat
IjjS Nov 3, 2023
c741401
enhance: produce responses in both json and xml
IjjS Nov 3, 2023
e45343f
feat: add controller advice to handle exceptions
IjjS Nov 4, 2023
8ab774c
enhance: elaborate the validation messages
IjjS Nov 4, 2023
a1f83b4
enhance: attach response status
IjjS Nov 4, 2023
29e4fae
fix: convert LocalDateTime to String
IjjS Nov 4, 2023
fbf474c
fix: apply the addition of createdAt
IjjS Nov 4, 2023
8b6dce1
fix: apply the change of parameters of CreateRequest
IjjS Nov 4, 2023
f8e9c7d
chore: add thymeleaf dependency
IjjS Nov 4, 2023
ef8f2d5
feat: implement read all vouchers controller for web
IjjS Nov 4, 2023
5e84284
feat: implement vouchers view
IjjS Nov 4, 2023
f6132aa
feat: implement find voucher by id controller for web
IjjS Nov 4, 2023
1b70792
feat: implement home page
IjjS Nov 4, 2023
c06ba66
refactor: retrieve primitive types for parameters of dto
IjjS Nov 4, 2023
5ff79eb
refactor: find voucher type regardless of the string form
IjjS Nov 4, 2023
4687ebe
enhance: add validation to UpdateVoucherRequest
IjjS Nov 4, 2023
f82fb08
refactor: simplify finding voucher type process to avoid exception
IjjS Nov 4, 2023
70074b4
feat: implement update controller
IjjS Nov 4, 2023
042bc35
feat: implement voucher view to be enabled for update
IjjS Nov 4, 2023
347ffdb
feat: create empty voucher for thymeleaf
IjjS Nov 4, 2023
f3a6e48
feat: implement create voucher controller
IjjS Nov 4, 2023
eb7873a
enhance: enhance voucher view to work for creation
IjjS Nov 4, 2023
528539b
feat: implement delete voucher controller
IjjS Nov 4, 2023
3f88909
enhance: add delete functionality to voucher view
IjjS Nov 4, 2023
3a0fe24
feat: add deleted view
IjjS Nov 4, 2023
4c010ac
feat: add onclick event callback for creation of a voucher
IjjS Nov 4, 2023
851139d
fix: close the form element
IjjS Nov 4, 2023
8c9b70f
feat: implement customer admin controllers
IjjS Nov 4, 2023
76ab655
style: specify title for deleted view
IjjS Nov 4, 2023
764ed32
enhance: add back to list button
IjjS Nov 4, 2023
5a243d7
feat: add back to home button
IjjS Nov 4, 2023
cd56a54
feat: add button to move to customers view
IjjS Nov 4, 2023
e7be225
refactor: remove unused statements
IjjS Nov 4, 2023
71989c6
enhance: add empty constructor of Customer
IjjS Nov 4, 2023
6120d16
feat: add similar views to that for vouchers
IjjS Nov 4, 2023
3e0e65f
style: update overall style
IjjS Nov 4, 2023
4d6b853
refactor: remove unnecessary empty list creation
IjjS Nov 5, 2023
39ef1a3
refactor: fix header to be selective
IjjS Nov 5, 2023
7729514
refactor: fix to use constants defined
IjjS Nov 5, 2023
b1134f5
refactor: directly load the data in Map structure
IjjS Nov 5, 2023
404d65f
refactor: track unknown exception
IjjS Nov 5, 2023
0d0e732
refactor: confirm the use of blacklist file only in file profile
IjjS Nov 5, 2023
8561a13
refactor: clear exception type
IjjS Nov 5, 2023
7da230f
feat: implement delete all vouchers using db
IjjS Nov 5, 2023
ba7d722
refactor: separate the concern to maintain the depth to 1
IjjS Nov 5, 2023
d2fdeb3
refactor: apply ParametrizedTest for repetitive tests
IjjS Nov 5, 2023
b46faf4
fix: revert exception causing variable
IjjS Nov 5, 2023
fae3d1b
style: fix minor view style
IjjS Nov 5, 2023
775ab6d
enhance: enable controllers for only web condition
IjjS Nov 5, 2023
609c3c7
feat: add general advice for thymeleaf error page
IjjS Nov 5, 2023
c245c62
fix: disable name to be blank
IjjS Nov 5, 2023
40cbeed
chore: create dockerfile and update to proper mysql url
IjjS Nov 5, 2023
d38611f
enhance: advise only RestControllers
IjjS Nov 5, 2023
e9fd577
chore: add init.sql for Dockerfile building
IjjS Nov 5, 2023
c1b6ca7
enhance: add transactional
IjjS Nov 5, 2023
98d87e8
enhance: enable general advice to advise only admin controllers
IjjS Nov 5, 2023
249bd53
refactor: merge find all api end points into one
IjjS Nov 5, 2023
58ba532
refactor: remove unnecessary request param
IjjS Nov 5, 2023
46ff569
refactor: remove unnecessary request param
IjjS Nov 5, 2023
2d85816
feat: handle unexpected error
IjjS Nov 21, 2023
34aecf0
fix: fix the improper http response status
IjjS Nov 21, 2023
a413117
Merge branch 'main' of https://github.com/IjjS/springboot-basic
IjjS Nov 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM mysql:latest

ENV MYSQL_ROOT_PASSWORD=1234
ENV MYSQL_DATABASE=voucher_management

COPY ./init.sql /docker-entrypoint-initdb.d/
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ dependencies {
testImplementation 'org.testcontainers:testcontainers:1.19.1'
testImplementation 'org.testcontainers:mysql:1.19.1'
testImplementation 'org.testcontainers:junit-jupiter:1.19.1'
implementation 'org.springframework.boot:spring-boot-starter-web:3.1.4'
implementation 'org.springframework.boot:spring-boot-starter-validation:3.1.4'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.15.2'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.1.4'
}

test {
Expand Down
14 changes: 14 additions & 0 deletions init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
CREATE TABLE customers (
customer_id BINARY(16) PRIMARY KEY,
name VARCHAR(30) NOT NULL,
customer_type VARCHAR(10) NOT NULL default 'NORMAL'
);

CREATE TABLE vouchers (
voucher_id BINARY(16) PRIMARY KEY,
created_at DATETIME NOT NULL,
discount_value DECIMAL NOT NULL,
voucher_type VARCHAR(10) NOT NULL,
customer_id BINARY(16),
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.programmers.vouchermanagement;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
Expand All @@ -12,7 +13,19 @@ public class VoucherManagementApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(VoucherManagementApplication.class);
application.setAdditionalProfiles("file");
setApplicationMode(application);
application.run(args);
}

private static void setApplicationMode(SpringApplication application) {
if (isWebMode(application)) {
return;
}
application.setWebApplicationType(WebApplicationType.NONE);
}

private static boolean isWebMode(SpringApplication application) {
return application.getAdditionalProfiles().contains("web");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.programmers.vouchermanagement.advice;

public class ExceptionMessage {
private final String message;

public ExceptionMessage(String message) {
this.message = message;
}

public String getMessage() {
return message;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.programmers.vouchermanagement.advice;

import java.util.NoSuchElementException;

import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import com.programmers.vouchermanagement.advice.annotation.AdminController;

@ControllerAdvice(annotations = AdminController.class)
public class GeneralAdvice {

Choose a reason for hiding this comment

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

공통된 애가 있으면 좋을거 같아요!


@ExceptionHandler({IllegalArgumentException.class, NoSuchElementException.class, RuntimeException.class})
public String renderErrorPage(RuntimeException exception, Model model) {
model.addAttribute("message", exception.getMessage());
return "error";
}

@ExceptionHandler(MethodArgumentNotValidException.class)
public String handleInvalidMethodArgumentException(BindingResult bindingResult, Model model) {
FieldError error = bindingResult.getFieldErrors()
.get(0);
String message = error.getField() + " exception - " + error.getDefaultMessage();
model.addAttribute("message", message);
return "error";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.programmers.vouchermanagement.advice;

import java.util.NoSuchElementException;

import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice(annotations = RestController.class)
public class RestAdvice {

Choose a reason for hiding this comment

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

RuntimeException으로 예상치 못한 예외를 방어해보면 어떨까요?


@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ExceptionMessage handleInvalidMethodArgumentException(BindingResult bindingResult) {
FieldError error = bindingResult.getFieldErrors()
.get(0);
String message = error.getField() + " exception - " + error.getDefaultMessage();
return new ExceptionMessage(message);
}

@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ExceptionMessage handleIllegalArgumentException(IllegalArgumentException exception) {
return new ExceptionMessage(exception.getMessage());
}

@ExceptionHandler(NoSuchElementException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ExceptionMessage handleNoSuchElementException(NoSuchElementException exception) {
return new ExceptionMessage(exception.getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.programmers.vouchermanagement.advice.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.stereotype.Controller;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
public @interface AdminController {
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@

import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

import com.programmers.vouchermanagement.configuration.profiles.DBEnabledCondition;
import com.programmers.vouchermanagement.configuration.properties.datasource.DataSourceProperties;
import com.zaxxer.hikari.HikariDataSource;

@Configuration
@Profile("jdbc")
@Conditional(DBEnabledCondition.class)
public class DBConfig {
@Bean
public DataSource dataSource(DataSourceProperties dataSourceProperties) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@
import java.util.UUID;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.programmers.vouchermanagement.configuration.profiles.FileEnabledCondition;
import com.programmers.vouchermanagement.customer.domain.Customer;
import com.programmers.vouchermanagement.util.JSONFileManager;
import com.programmers.vouchermanagement.voucher.domain.Voucher;

@Configuration
@Profile({"file", "test"})
@Conditional(FileEnabledCondition.class)
public class FileConfig {
@Bean
public ObjectMapper objectMapper() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.programmers.vouchermanagement.configuration.profiles;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class ConsoleCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().matchesProfiles("dev", "file", "jdbc");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.programmers.vouchermanagement.configuration.profiles;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class DBEnabledCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().matchesProfiles("jdbc", "web");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.programmers.vouchermanagement.configuration.profiles;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class FileEnabledCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().matchesProfiles("file", "test");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.ConstructorBinding;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.Conditional;

@Profile("jdbc")
import com.programmers.vouchermanagement.configuration.profiles.DBEnabledCondition;

@Conditional(DBEnabledCondition.class)
@ConfigurationProperties("datasource")
public class DataSourceProperties {
private final String driverClassName;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.programmers.vouchermanagement.consoleapp.io;

import java.math.BigDecimal;
import java.util.List;
import java.util.UUID;

Expand All @@ -14,7 +13,6 @@
import com.programmers.vouchermanagement.customer.dto.CustomerResponse;
import com.programmers.vouchermanagement.customer.dto.UpdateCustomerRequest;
import com.programmers.vouchermanagement.util.Formatter;
import com.programmers.vouchermanagement.voucher.domain.VoucherType;
import com.programmers.vouchermanagement.voucher.dto.CreateVoucherRequest;
import com.programmers.vouchermanagement.voucher.dto.UpdateVoucherRequest;
import com.programmers.vouchermanagement.voucher.dto.VoucherCustomerRequest;
Expand Down Expand Up @@ -77,6 +75,7 @@ public class ConsoleManager {
private static final String LISTING_OWNED_VOUCHERS_OF = "Listing vouchers that Customer %s has ...";
private static final String GRANT_SUCCESSFUL = "Voucher (%s) is granted to Customer (%s).";
private static final String VOUCHER_OWNER_BELOW = "The owner of Voucher %s is provided below:";
private static final String UNKNOWN_EXCEPTION_THROWN = "Failed to run the command. Unknown Exception is thrown.";

private final TextIO textIO;

Expand All @@ -100,24 +99,20 @@ public CustomerMenu selectCustomerMenu() {
}

public CreateVoucherRequest instructCreateVoucher() {
String voucherTypeCode = read(VOUCHER_TYPE_INPUT);
VoucherType voucherType = VoucherType.findVoucherTypeByCode(voucherTypeCode);

String voucherType = read(VOUCHER_TYPE_INPUT);
String discountValueInput = read(VOUCHER_DISCOUNT_VALUE_INSTRUCTION);
BigDecimal discountValue = new BigDecimal(discountValueInput);
long discountValue = Long.parseLong(discountValueInput);
return new CreateVoucherRequest(discountValue, voucherType);
}

public UpdateVoucherRequest instructUpdateVoucher() {
String voucherIdInput = read(ID_INPUT.formatted(CONTENT_VOUCHER));
UUID voucherId = UUID.fromString(voucherIdInput);

String discountValueInput = read(VOUCHER_DISCOUNT_VALUE_INSTRUCTION);
BigDecimal discountValue = new BigDecimal(discountValueInput);
String discountValue = read(VOUCHER_DISCOUNT_VALUE_INSTRUCTION);

String voucherTypeCode = read(VOUCHER_TYPE_INPUT);
VoucherType voucherType = VoucherType.findVoucherTypeByCode(voucherTypeCode);
return new UpdateVoucherRequest(voucherId, discountValue, voucherType);
return new UpdateVoucherRequest(voucherId, Long.parseLong(discountValue), voucherTypeCode);
}

public String instructCreateCustomer() {
Expand Down Expand Up @@ -152,7 +147,7 @@ public VoucherCustomerRequest instructRequestVoucherCustomer() {
}

public void printSaveVoucherResult(VoucherResponse voucherResponse) {
print(CREATE_SUCCESS_MESSAGE.formatted(CONTENT_VOUCHER, voucherResponse.getVoucherId()));
print(CREATE_SUCCESS_MESSAGE.formatted(CONTENT_VOUCHER, voucherResponse.voucherId()));
}

public void printSaveCustomerResult(CustomerResponse customerResponse) {
Expand Down Expand Up @@ -220,6 +215,9 @@ public void printIncorrectMenu() {
}

public void printException(RuntimeException e) {
if (e.getMessage() == null) {
print(UNKNOWN_EXCEPTION_THROWN);
}
print(e.getMessage());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;

import com.programmers.vouchermanagement.configuration.profiles.ConsoleCondition;
import com.programmers.vouchermanagement.consoleapp.io.ConsoleManager;
import com.programmers.vouchermanagement.consoleapp.menu.Menu;
import com.programmers.vouchermanagement.consoleapp.menu.MenuHandler;

@Component
@Profile({"jdbc, dev, file"})
@Conditional(ConsoleCondition.class)
public class ConsoleApp implements ApplicationRunner {
private static final Logger logger = LoggerFactory.getLogger(ConsoleApp.class);
private static final String INCORRECT_MESSAGE = "Selected menu is not an executable menu.";
Expand Down
Loading