Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5기 - 조인수] SpringBoot Part2 Weekly Mission 제출합니다. #944

Open
wants to merge 62 commits into
base: zzambas
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
6d4d4c5
Chore: 동사형 메서드 이름으로 변경한다.
ZZAMBAs Oct 28, 2023
50704c4
Refactor: stream 형식으로 for문을 변경한다.
ZZAMBAs Oct 28, 2023
f96f455
Chore: 잘못된 값에 대한 로그의 레벨을 변경한다.
ZZAMBAs Oct 28, 2023
279b036
Chore: 상수 네이밍을 변수 네이밍으로 변경한다.
ZZAMBAs Oct 28, 2023
38c3600
Refactor: VoucherType 입력 순서를 CommonConstant에서 가지고 있도록 한다.
ZZAMBAs Oct 28, 2023
5e648dc
Chore: 불필요한 주석들을 제거한다.
ZZAMBAs Oct 28, 2023
aa8eb70
Refactor: 동사형 메서드 명으로 변경한다.
ZZAMBAs Oct 28, 2023
662d31d
Fix: VoucherMemoryRepository 내 필드를 private final로 설정한다.
ZZAMBAs Oct 28, 2023
f3542b5
Refactor: VoucherRepository의 findById 메서드가 Optional을 반환하도록 한다.
ZZAMBAs Oct 28, 2023
0fca27c
Test: VoucherMemoryRepository를 테스트하는 코드를 작성한다.
ZZAMBAs Oct 28, 2023
f7d94d0
Chore: CSV 종속적이므로 이름을 그에 맞게 변경한다.
ZZAMBAs Oct 28, 2023
9c32e33
Feat: VoucherRepository에 삭제, 전체 삭제 기능을 추가한다.
ZZAMBAs Oct 28, 2023
f1e6519
Test: 삭제, 전체 삭제 기능 테스트를 추가한다.
ZZAMBAs Oct 28, 2023
3c6f00b
Feat: @Value를 이용해 파일 경로를 프로파일에 맞게 설정한다.
ZZAMBAs Oct 28, 2023
83c8ad2
Test: CSV 파일로 관리하는 VoucherRepository 테스트를 작성한다.
ZZAMBAs Oct 28, 2023
a821665
Feat: customers 테이블 생성을 위한 스키마 파일을 추가한다.
ZZAMBAs Oct 28, 2023
04b2444
Rename: 패키지를 적절히 이동한다.
ZZAMBAs Oct 28, 2023
124ab3c
Feat: CustomerRepository에 CRUD 기능을 전부 추가한다.
ZZAMBAs Oct 28, 2023
5ee64a4
Feat: DB를 이용한 CustomerDatabaseRepository를 추가한다.
ZZAMBAs Oct 29, 2023
64fb4c1
Feat: final이 아닌 필드에 대한 생성자, 정보 변경 그리고 isBlack 필드의 getter 메서드를 추가한다.
ZZAMBAs Oct 29, 2023
d3e34a1
Feat: MySQL 연결을 위한 설정을 추가한다.
ZZAMBAs Oct 29, 2023
83b6469
Feat: 고객 전체 조회 메서드를 추가한다.
ZZAMBAs Oct 29, 2023
81b816e
Feat: DB에 조회하는 데이터가 없을 때 나타나는 예외를 추가한다.
ZZAMBAs Oct 29, 2023
3e7207c
Feat: queryForObject 시, 데이터가 0개인 경우 예외 처리를 하고, toParamMap에 isBlacked …
ZZAMBAs Oct 29, 2023
1b7c39a
Test: 고객 DB Repository 테스트를 작성한다.
ZZAMBAs Oct 29, 2023
43b5892
Feat: 코드 전체에서 사용할만한 메서드를 모아둔 UtilMethod 클래스를 정의한다.
ZZAMBAs Oct 29, 2023
2d1c408
Chore: VoucherRepository의 create를 save라는 네이밍으로 변경한다.
ZZAMBAs Oct 29, 2023
6d527b6
Feat: vouchers 테이블 정의 SQL문을 추가한다.
ZZAMBAs Oct 29, 2023
a03c585
Chore: 메서드 명을 바꾼다.
ZZAMBAs Oct 29, 2023
e74d7bb
Feat: vouchers 테이블에 타입 컬럼을 추가한다.
ZZAMBAs Oct 30, 2023
b959918
Feat: DB로 Voucher를 관리하는 Repository를 추가한다.
ZZAMBAs Oct 30, 2023
957dc40
Refactor: 구성 파일을 수정한다.
ZZAMBAs Oct 30, 2023
facf373
Test: DB 관리 VoucherRepository 테스트를 작성한다.
ZZAMBAs Oct 30, 2023
e2f9d15
Feat: 바우처 지갑 콘솔 입력을 받는 WalletConsole을 추가하고 최초 콘솔 입출력 클래스를 MainConsole…
ZZAMBAs Oct 30, 2023
a059942
Feat: 바우처 지갑 컨트롤러를 추가한다.
ZZAMBAs Oct 30, 2023
abc4063
Refactor: 필요없는 메서드를 삭제한다.
ZZAMBAs Oct 30, 2023
326419f
Feat: String을 UUID로 변경하는 공통 메서드를 추가한다.
ZZAMBAs Oct 30, 2023
c9caf0d
Refactor: Id 입력을 받으면 UUID로 반환하도록 한다.
ZZAMBAs Oct 30, 2023
e34bf01
Refactor: 직관적인 메서드 명으로 변경한다.
ZZAMBAs Oct 30, 2023
350a181
Feat: 지갑 테이블 wallet 생성 SQL문을 작성한다.
ZZAMBAs Oct 30, 2023
5b98ac4
Refactor: Colection 출력을 공통 콘솔 부분으로 분리한다.
ZZAMBAs Oct 30, 2023
f773ecf
Feat: 바우처 지갑 콘솔과 서비스 부분을 완성한다.
ZZAMBAs Oct 30, 2023
aa4e08f
Feat: 데이터베이스 예외 처리를 잡도록 한다.
ZZAMBAs Oct 30, 2023
7a81749
Feat: DataAccessException 발생 시, 로그에 스택 트레이스를 남기도록 한다.
ZZAMBAs Oct 30, 2023
96d6121
Refactor: 이미 존재하는 메서드를 이용한다.
ZZAMBAs Oct 30, 2023
3b1136b
Feat: DB에서 관리하는 바우처 지갑 Repository를 추가한다.
ZZAMBAs Oct 30, 2023
193f73c
Fix: 부트 설정을 변경한다.
ZZAMBAs Oct 30, 2023
ad0baa3
Refactor: 직관적인 이름으로 변경한다.
ZZAMBAs Oct 30, 2023
97b54cf
Refactor: deleteById가 void 반환값을 가지게 하고 save 메서드 명을 직관적으로 바꾼다.
ZZAMBAs Oct 31, 2023
f5fda67
Refactor: 하나의 Console, 하나의 Controller로 통합한다.
ZZAMBAs Oct 31, 2023
eb7da2e
Feat: Voucher를 새로 정의한다.
ZZAMBAs Oct 31, 2023
4b64bf1
Refactor: 정의된 Voucher에 따라 기존 코드를 VoucherPolicy에서 Voucher로 처리하게 한다.
ZZAMBAs Nov 1, 2023
3bb2f99
Feat: Policy에 따라 생성자 조건을 추가하고 VoucherPolicy의 getter를 생성한다.
ZZAMBAs Nov 1, 2023
c6e8871
Refactor: import 문을 최적화한다.
ZZAMBAs Nov 1, 2023
0ddbbfb
Refactor: 클래스명을 직관적으로 수정한다.
ZZAMBAs Nov 1, 2023
80b422a
Chore: DataSource 빈을 생성하지 못하는 문제를 해결하기 위해 테스트용 DB와 연결하도록 한다.
ZZAMBAs Nov 1, 2023
716ee19
Feat: Customer에 대한 create, findAll을 콘솔 기능에 추가한다.
ZZAMBAs Nov 1, 2023
26019b0
Test: CustomerService의 테스트 코드를 작성한다.
ZZAMBAs Nov 1, 2023
96392b0
Feat: findById 기능을 추가한다.
ZZAMBAs Nov 2, 2023
f3e265c
Refactor: 네이밍을 적절히 수정한다.
ZZAMBAs Nov 2, 2023
3b423d7
Test: 바우처 지갑의 역할을 하는 Customer, Voucher 관리 클래스 테스트를 추가한다.
ZZAMBAs Nov 2, 2023
23ed012
Rename: Console 부분 패키지를 따로 뺀다.
ZZAMBAs Nov 2, 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
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ repositories {

dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'com.mysql:mysql-connector-j'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@

public class CommonConstant {
public static final String CSV_PATTERN = ",(?=([^\"]*\"[^\"]*\")*[^\"]*$)";
public static final int INPUT_FIXED_AMOUNT_VOUCHER = 1;
public static final int INPUT_PERCENT_DISCOUNT_VOUCHER = 2;
}
59 changes: 0 additions & 59 deletions src/main/java/org/prgms/springbootbasic/common/Console.java

This file was deleted.

12 changes: 12 additions & 0 deletions src/main/java/org/prgms/springbootbasic/common/UtilMethod.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.prgms.springbootbasic.common;

import java.nio.ByteBuffer;
import java.util.UUID;

public class UtilMethod {
public static UUID bytesToUUID(byte[] bytes) {
ByteBuffer wrappedByte = ByteBuffer.wrap(bytes);

return new UUID(wrappedByte.getLong(), wrappedByte.getLong());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

import java.io.*;
Expand All @@ -11,6 +12,7 @@
import java.util.function.Function;

@Component
@Profile("test")
public class CsvFileTemplate {
private static final Logger log = LoggerFactory.getLogger(CsvFileTemplate.class);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import static org.prgms.springbootbasic.common.CommonConstant.CSV_PATTERN;

@Component
@Profile({"dev", "prod"})
@Profile({"test"})
@Slf4j
public class CustomerCsvFileManager {
private static final String BLACK_PATH = "./src/main/resources/customer_blacklist.csv";
Expand All @@ -31,10 +31,10 @@ public CustomerCsvFileManager(CsvFileTemplate csvFileTemplate) {


public List<Customer> readBlack(){
return csvFileTemplate.read(BLACK_PATH, this::lineToBlack);
return csvFileTemplate.read(BLACK_PATH, this::convertToBlack);
}

private Customer lineToBlack(String line){
private Customer convertToBlack(String line){
log.debug("line = {}", line);

List<String> csvFields =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import lombok.extern.slf4j.Slf4j;
import org.prgms.springbootbasic.domain.VoucherType;
import org.prgms.springbootbasic.domain.voucher.Voucher;
import org.prgms.springbootbasic.domain.voucher.VoucherPolicy;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

Expand All @@ -14,62 +16,62 @@

@Component
@Slf4j
@Profile({"dev", "prod"})
public class VoucherCsvFileManager { // CsvFileManager 하나로 합쳐서. domain은 최대한 순수하게 유지. 외부 의존성이 들어간다? 이게 도메인에 들어가면 변경이 취약. -> 분리
private static final String FILE_PATH = "./src/main/resources/voucher.csv";
@Profile({"test"})
public class VoucherCsvFileManager {
@Value("${basic.file.path}")
private String FILE_PATH;
private static final String CSV_FIRST_LINE = "UUID,Type,DiscountValue";
private static final int UUID_IDX = 0;
private static final int TYPE_IDX = 1;
private static final int DISCOUNT_VALUE_IDX = 2;
private static final int DISCOUNT_DEGREE_IDX = 2;

private final CsvFileTemplate csvFileTemplate;

public VoucherCsvFileManager(CsvFileTemplate csvFileTemplate) {
this.csvFileTemplate = csvFileTemplate;
}

public List<VoucherPolicy> read(){
return csvFileTemplate.read(FILE_PATH, this::lineToVoucher);
public List<Voucher> read(){
return csvFileTemplate.read(FILE_PATH, this::convertToVoucher);
}

public void write(List<VoucherPolicy> voucherPolicies){
csvFileTemplate.write(FILE_PATH, voucherPolicies, this::voucherToString, CSV_FIRST_LINE);
public void write(List<Voucher> voucherPolicies){
csvFileTemplate.write(FILE_PATH, voucherPolicies, this::convertToString, CSV_FIRST_LINE);
}

private VoucherPolicy lineToVoucher(String line){
private Voucher convertToVoucher(String line){
log.debug("line = {}", line);

List<String> splitLine = Arrays.stream(line.split(CSV_PATTERN))
.map(s -> s.replaceAll("\"", ""))
.toList();
VoucherType[] voucherTypes = VoucherType.values();

for (VoucherType type : voucherTypes) {
String voucherType = type.getDisplayName();
String curStringType = splitLine.get(TYPE_IDX);
VoucherType thisVoucherType =
Arrays.stream(voucherTypes)
.filter(type -> type.getDisplayName().equals(splitLine.get(TYPE_IDX)))
.findAny()
.orElseThrow(() -> {
log.error("Invalid voucher type.");
return new IllegalArgumentException("Invalid voucher type");
});

if (curStringType.equals(voucherType)) {
log.info("This voucher type is {}", voucherType);
VoucherPolicy voucherPolicy = thisVoucherType.create();
UUID voucherId = UUID.fromString(splitLine.get(UUID_IDX));
long discountDegree = Long.parseLong(splitLine.get(DISCOUNT_DEGREE_IDX));

return type.create(
UUID.fromString(splitLine.get(UUID_IDX)),
Long.parseLong(splitLine.get(DISCOUNT_VALUE_IDX))
);
}
}

log.error("Invalid voucher type.");
throw new IllegalArgumentException("Invalid voucher type.");
return new Voucher(voucherId, discountDegree, voucherPolicy);
}

private String voucherToString(VoucherPolicy voucherPolicy){
private String convertToString(Voucher voucher){ // 외부에 도메인을 맞추면 안됨. -> DB 의존적 클래스랑 실제 내부 도메인 분리.
// 이거를 위해서 VoucherPolicy가 getter를 들고있는게 말이 안됨. 얘를 도메인에 맞춰야지 얘때문에 도메인이 망가지면 안된다.
StringBuilder sb = new StringBuilder();

sb.append(voucherPolicy.getVoucherId());
sb.append(voucher.getVoucherId());
sb.append(",");
sb.append(voucherPolicy.getClass().getSimpleName());
sb.append(voucher.getVoucherPolicy().getClass().getSimpleName());
sb.append(",");
sb.append(voucherPolicy.getDiscountAmount());
sb.append(voucher.getDiscountDegree());
sb.append(System.lineSeparator());

return sb.toString();
Expand Down
106 changes: 106 additions & 0 deletions src/main/java/org/prgms/springbootbasic/console/Console.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package org.prgms.springbootbasic.console;

import lombok.extern.slf4j.Slf4j;
import org.prgms.springbootbasic.domain.VoucherType;
import org.springframework.stereotype.Component;

import java.text.MessageFormat;
import java.util.Collection;
import java.util.Scanner;
import java.util.UUID;

import static org.prgms.springbootbasic.common.CommonConstant.INPUT_FIXED_AMOUNT_VOUCHER;
import static org.prgms.springbootbasic.common.CommonConstant.INPUT_PERCENT_DISCOUNT_VOUCHER;

@Component
@Slf4j
public class Console { // Console이 common인가? MVC 생각하며 고민하자. View에 해당한다고 보이는데... MVC가 뭔지 대답 못한 것을 두번째 걸렸다. 공부하자...
public static final Scanner consoleInput = new Scanner(System.in);

public static String readCommand() {
System.out.println("=== Voucher Program ===");
System.out.println("Type 'createVoucher' to create a new voucher.");
System.out.println("Type 'createCustomer' to create a new customer.");
System.out.println("Type 'listVoucher' to list all vouchers.");
System.out.println("Type 'listCustomer' to list all customers.");
System.out.println("Type 'black' to list customers blacked.");
System.out.println("Type 'wallet' to enter wallet service.");
System.out.println("Type 'exit' to exit the program.");

return consoleInput.next();
}

public static int selectPolicyType() {
System.out.println();
System.out.println("Which voucher would you like to create? Just type number.");
System.out.println(MessageFormat.format("{0}. with fixed amount discount policy", INPUT_FIXED_AMOUNT_VOUCHER));
System.out.println(MessageFormat.format("{0}. with percent discount policy", INPUT_PERCENT_DISCOUNT_VOUCHER));

return consoleInput.nextInt();
}

public static String putCustomerInfo() {
ignoreLine();

System.out.println();
System.out.println("Please enter the name and email of the customer you want to create, separated by a space on a single line.");

return consoleInput.nextLine();
}

public static int putDiscountDegree(VoucherType type) {
switch (type){
case FIXED_AMOUNT -> System.out.println("Enter the fixed discount amount.");
case PERCENT_DISCOUNT -> System.out.println("Enter the discount percentage.");
}
return consoleInput.nextInt();
}


public static String ignoreLine() {
return consoleInput.nextLine();
}

public static void printArgException() {
System.out.println("Invalid argument. Type command again.");
}

public static void printRuntimeException() {
System.out.println("Invalid input or system error. redirect to beginning.");
}

public static String readWalletCommand() {
System.out.println();
System.out.println("Welcome to our wallet service.");
System.out.println("Type 'allocate' if you want to allocate voucher to a customer." );
System.out.println("Type 'delete' if you want to delete voucher from a customer.");
System.out.println("Type 'showVoucherByCustomer' to view customers with a voucher.");
System.out.println("Type 'showCustomerByVoucher' to view vouchers that a customer has.");
System.out.println("Type 'back' to go back.");

return consoleInput.next();
}

public static UUID typeCustomerId(){
System.out.println("Type customer Id.");

return UUID.fromString(consoleInput.next());
}

public static UUID typeVoucherId(){
System.out.println("Type voucher Id.");

return UUID.fromString(consoleInput.next());
}

public static void success(String command){
System.out.println("'" + command + "' command successfully executed.");
System.out.println();
}

public static <T> void printList(Collection<T> collection) {
System.out.println();
collection.forEach(System.out::println);
System.out.println();
}
}
Loading