Skip to content

Commit

Permalink
[로또 - 웹, DB] 베디 미션 제출합니다. (#43)
Browse files Browse the repository at this point in the history
* feat: DBUtils, PropertiesUil.class 구현

connection을 얻고 닫아주는 유틸리티 구현

* docs: schema.sql

* feat: RoundDao.class 라운드 관리

* fix: RoundDao.class 커넥션 close 추가

* feat: LottoDao.class 로또 추가, 조회

* refactor: Lotto.class 팩터리 메서드 접근제어자 변경

* refactor: Lotto, LottoNo 접근제어자 변경

* refactor: LottoNo.class 캐싱 시스템 롤백

* feat: ConverterToLottoNos.class 구현

* feat: WinningLottoDao.class 구현

* refactor: LottoDao convert 클래스로 추출

* refactor: WinPrize.class 총구매금액을 외부에서 받는게 아닌 직접 구하게 변경

WinPrize의 ranks로 충분히 총 구매 금액을 구할 수 있으므로 외부에서 파라미터로 받는 방식이 아닌
직접 구하는 방식으로 변경.

* feat: WinPrizeDao.class ㄱ

* refactor: 결과 포맷팅 추출

* refactor: schema.sql 변경

* fix: Lotto.class 중복된 번호 입력 가능 버그 수정

* refactor: LottoNoCollectionTest 매직넘버 상수로 변경

* style: 포맷팅

* feat: web ui 구현

* refactor: index.html 파일명 path 수정

* refactor: DBUtils.class DriverClassName jdbc.properties에 입력하게 수정

* refactor: DBUtils.class 주석 제거, 접근제어자 축소

* refactor: LottosGenerator.class 수동, 오토 새로 생성해서 리턴하게 변경

void 리턴 메서드에서 값을 변경하는 로직이 있는 경우 사이드이펙트가 발생 할 가능성이 생기며 해당 메서드를 테스트하기 어려울 수 있습니다.

* refactor: Rank.class 전략열거타입으로 구현

* fix: Rank.class 결과 잘 못 구하는 문제점 수정

* feat: web ui 회차별 조회 추가

* style: 포맷팅, import 제거

* test: LottoNo 캐싱 테스트 추가

* refactor: Rank.class 전략열거타입 익명클래스에서 람다로 변경

* refactor: Exception 처리 spark api 이용하게 변경

* refactor: ResultFormat.class 결과 메시지 출력 방식 변경

* refactor: WebUILottoApplication의 구현 코드들 Service로 추출

* refactor: Service 추출

* style: 포맷팅 (메소드 순서 정렬)

* refactor: start.html 안쓰는 script 제거

* fix: 잘못된 메소드명 수정

* style: convertToList camelCase 이름수정

* fix: rename 누락 반영

* refactor: Money.getCountAuto() 추가

* feat: 수동 로또 번호 입력 하지 않을 경우. 메시지 출력 추가

* fix: test 메소드명에 test누락한 부분들 추가

* refactor: Controller와 Service 분리

* refactor: RoundController non-static으로 변경

* refactor: LottoHelper.generateLottos() 삭제

* refactor: LottoHelper.generateWinPrize() -> WinningLotto.generateWinPrize() 가 생성하게 변경

* refactor: LottoHelper.generateWinningLotto() 삭제 -> WinningLotto.class 에 위임

* refactor: Encoder.class 삭제

* refactor: LottoDao.findByRound() -> findAllByRound()로 이름 변경

* feat: test용 DB runtime용 DB 분리 (리팩토링 많이 필요)

* refactor: PropertiesUtil -> DataSource로 이름 변경

* refactor: LottoDao.class  Batch Insert, try-with-resources 구현

* test: DBConnectorTest

* refactor: TableCreator 경로 변경 및 non-static 으로 변경

* refactor: RoundDao try-with-resources 구현

* feat: TestTableCreator.class 구현

* refactor: WinPrizeDao, WinningLottoDao try-with-resources 구현

* fix: RoundService.class 라운드 증가 코드 누락되어 있어서 추가.

* test: LottoDaoTest 테스트 코드 변경

* docs: schema.sql 수정

* fix: WinPrizeDao.class excuteUpdate() 누락 추가

* style: 포맷팅, import 제거

* docs: schema.sql round insert 제거

* refactor: DB h2 memory로 변경 + 앱 실행시 테이블 생성

* refactor: Money.class Objects.requireNonNull() 추가

* refactor: Dao null 리턴 대신 Optional 구현

db 조회 후에 값이 없을 경우 null을 리턴해줬는데
Optional을 사용해보고 싶어서 변경하였지만, 지금 상황에서는 에러처리 외에는 딱히 방법이 없는거 같아서
제대로 활용은 못했지만, 학습용으로 한 번 해봄.
  • Loading branch information
dpudpu authored and 이동규 committed Jun 24, 2019
1 parent 9c88ea0 commit ba30165
Show file tree
Hide file tree
Showing 54 changed files with 1,340 additions and 94 deletions.
5 changes: 5 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ dependencies {
compile('com.sparkjava:spark-core:2.9.0')
compile('com.sparkjava:spark-template-handlebars:2.7.1')
compile('ch.qos.logback:logback-classic:1.2.3')
// runtime('mysql:mysql-connector-java:8.0.16')
compile group: 'com.h2database', name: 'h2', version:'1.4.194'

testCompile('org.junit.jupiter:junit-jupiter:5.4.2')
testCompile('org.assertj:assertj-core:3.11.1')
// testCompile group: 'com.h2database', name: 'h2', version:'1.4.194'

}
11 changes: 5 additions & 6 deletions src/main/java/lotto/ConsoleUILottoApplication.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package lotto;

import lotto.domain.*;
import lotto.service.LottoService;
import lotto.domain.generator.LottosGenerator;
import lotto.view.InputConsoleView;
import lotto.view.InputView;
import lotto.view.OutputConsoleView;
Expand All @@ -18,13 +18,12 @@ public static void main(String[] args) {
Money money = Money.from(inputView.inputMoney());
CountOfManual countOfManual = CountOfManual.of(inputView.inputCountOfManual(), money.getCountOfPurchase());
List<String> manualLottos = inputManualLottos(countOfManual);
List<Lotto> userLottos = LottoService.generateLottos(manualLottos, money);
List<Lotto> userLottos = LottosGenerator.of(manualLottos, money.getCountOfPurchase()).generate();
outputView.printLottos(userLottos, countOfManual.value(), money.getCountOfPurchase());

WinningLotto winningLotto = LottoService.generateWinningLotto(inputView.inputWinningLotto(), inputView.inputBonusNo());
WinPrize winPrize = LottoService.generateWinPrize(userLottos, winningLotto);
WinningLotto winningLotto = new WinningLotto(inputView.inputWinningLotto(), inputView.inputBonusNo());
WinPrize winPrize = winningLotto.generateWinPrize(userLottos);
outputView.printResult(winPrize);
outputView.printRateOfProfit(money, winPrize);
outputView.printRateOfProfit(winPrize);
}

private static List<String> inputManualLottos(final CountOfManual countOfManual) {
Expand Down
78 changes: 71 additions & 7 deletions src/main/java/lotto/WebUILottoApplication.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,86 @@
package lotto;

import lotto.config.DBConnector;
import lotto.config.DataSource;
import lotto.config.TableCreator;
import lotto.controller.*;
import lotto.dao.LottoDao;
import lotto.dao.RoundDao;
import lotto.dao.WinPrizeDao;
import lotto.dao.WinningLottoDao;
import lotto.service.LottoService;
import lotto.service.RoundService;
import lotto.service.WinPrizeService;
import lotto.service.WinningLottoService;
import spark.ModelAndView;
import spark.template.handlebars.HandlebarsTemplateEngine;

import java.util.HashMap;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;

import static spark.Spark.get;
import static spark.Spark.*;

public class WebUILottoApplication {
public static void main(String[] args) {
get("/", (req, res) -> {
Map<String, Object> model = new HashMap<>();
return render(model, "index.html");

public static void main(String[] args) throws Exception {
port(8080);

DBConnector dbConnector = new DBConnector(DataSource.getTestInstance());

createTable(dbConnector);

RoundDao roundDao = new RoundDao(dbConnector);
LottoDao lottoDao = new LottoDao(dbConnector);
WinPrizeDao winPrizeDao = new WinPrizeDao(dbConnector);
WinningLottoDao winningLottoDao = new WinningLottoDao(dbConnector);

RoundService roundService = new RoundService(roundDao);
LottoService lottoService = new LottoService(lottoDao);
WinPrizeService winPrizeService = new WinPrizeService(winPrizeDao);
WinningLottoService winningLottoService = new WinningLottoService(winningLottoDao);

LottoController lottoController = new LottoController(roundService, lottoService);
ResultController resultController = new ResultController(winPrizeService, winningLottoService, lottoService);
ErrorController errorController = new ErrorController();
MainController mainController = new MainController(roundDao);
RoundController roundController = new RoundController(winPrizeService, lottoService, winningLottoService);

externalStaticFileLocation("src/main/resources/templates");

get("/", mainController::main);

get("/round", roundController::round);

post("/lottos", lottoController::addLottos);

get("/lottos", lottoController::getLottos);

post("/result", resultController::doPostResult);

get("/result", resultController::doGetResult);

get("/error", errorController::exception);

exception(Exception.class, (exception, req, res) -> {
String message = null;
try {
message = URLEncoder.encode(exception.getMessage(), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
res.redirect("/error?message=" + message);
});
}

private static String render(Map<String, Object> model, String templatePath) {
private static void createTable(final DBConnector dbConnector) throws Exception {
TableCreator tableCreator = new TableCreator(dbConnector);
tableCreator.create();
}

public static String render(Map<String, Object> model, String templatePath) {
return new HandlebarsTemplateEngine().render(new ModelAndView(model, templatePath));
}


}
24 changes: 24 additions & 0 deletions src/main/java/lotto/config/DBConnector.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package lotto.config;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DBConnector {
private final DataSource dataSource;

public DBConnector(final DataSource dataSource) {
this.dataSource = dataSource;
}

public Connection getConnection() throws SQLException {

try {
Class.forName(dataSource.getDriverClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

return DriverManager.getConnection(dataSource.getUrl(), dataSource.getProperties());
}
}
48 changes: 48 additions & 0 deletions src/main/java/lotto/config/DataSource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package lotto.config;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class DataSource {
private String url;
private Properties properties;
private String driverClassName;

public static DataSource getInstance() {
return LazyHolder.INSTANCE;
}

public static DataSource getTestInstance() {
return LazyHolder.INSTANCE_TEST;
}

private DataSource(String path) {
try {
InputStream in = this.getClass().getClassLoader().getResourceAsStream(path);
properties = new Properties();
properties.load(in);
url = properties.getProperty("url");
driverClassName = properties.getProperty("driver-class-name");
} catch (IOException e) {
e.printStackTrace();
}
}

public String getUrl() {
return url;
}

public Properties getProperties() {
return properties;
}

public String getDriverClassName() {
return driverClassName;
}

private static class LazyHolder {
private static final DataSource INSTANCE = new DataSource("jdbc.properties");
private static final DataSource INSTANCE_TEST = new DataSource("jdbcTest.properties");
}
}
52 changes: 52 additions & 0 deletions src/main/java/lotto/config/TableCreator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package lotto.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.PreparedStatement;

public class TableCreator {
private static final Logger LOGGER = LoggerFactory.getLogger(TableCreator.class);
private static final String SEMICOLON_DELIMITER = ";";

private static boolean flag = false;
private DBConnector dbConnector;

public TableCreator(final DBConnector dbConnector) {
this.dbConnector = dbConnector;
}

public void create() throws Exception {
if (flag) {
return;
}
flag = true;

File file = new File("src/main/resources/schema.sql");
FileInputStream fis = new FileInputStream(file);

String[] querys = getFileContent(fis).split(SEMICOLON_DELIMITER);
for (final String query : querys) {
Connection connection = dbConnector.getConnection();
PreparedStatement ps = connection.prepareStatement(query);
ps.executeUpdate();
ps.close();
LOGGER.info(query);
}
}

public String getFileContent(FileInputStream fis) throws IOException {
StringBuilder sb = new StringBuilder();
Reader r = new InputStreamReader(fis, StandardCharsets.UTF_8); //or whatever encoding
char[] buf = new char[1024];
int amt = r.read(buf);
while (amt > 0) {
sb.append(buf, 0, amt);
amt = r.read(buf);
}
return sb.toString();
}
}
21 changes: 21 additions & 0 deletions src/main/java/lotto/controller/ErrorController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package lotto.controller;

import spark.Request;
import spark.Response;

import java.util.HashMap;
import java.util.Map;

import static lotto.WebUILottoApplication.render;

public class ErrorController {

public ErrorController() {
}

public Object exception(Request req, Response res) {
Map<String, Object> model = new HashMap<>();
model.put("message", req.queryParams("message"));
return render(model, "error.html");
}
}
60 changes: 60 additions & 0 deletions src/main/java/lotto/controller/LottoController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package lotto.controller;


import lotto.domain.CountOfManual;
import lotto.domain.Lotto;
import lotto.domain.Money;
import lotto.domain.generator.LottosGenerator;
import lotto.service.LottoService;
import lotto.service.RoundService;
import spark.Request;
import spark.Response;

import java.util.*;

import static lotto.WebUILottoApplication.render;

public class LottoController {
private static final String DELIMITER = "\r\n";

private final RoundService roundService;
private final LottoService lottoService;

public LottoController(final RoundService roundService, final LottoService lottoService) {
this.roundService = roundService;
this.lottoService = lottoService;
}

public Object addLottos(Request req, Response res) {
int round = roundService.increaseOne();
Money money = Money.from(req.queryParams("money"));
List<String> manualLottos = convertToList(req.queryParams("manualLottos"));
List<Lotto> userLottos = LottosGenerator.of(manualLottos, money.getCountOfPurchase()).generate();
lottoService.save(userLottos, round);

CountOfManual countOfManual = CountOfManual.of(manualLottos.size(), money.getCountOfPurchase());
int countOfAuto = money.getCountOfAuto(countOfManual.value());
res.redirect("/lottos?countOfManual=" + countOfManual.value() + "&countOfAuto=" + countOfAuto);
return null;
}

private List<String> convertToList(final String manualLottos) {
String[] results = manualLottos.split(DELIMITER);
if (results[0].equals("")) {
return new ArrayList<>();
}
return Arrays.asList(results);
}

public Object getLottos(Request req, Response res) {
Map<String, Object> model = new HashMap<>();
int round = roundService.getLatestRound();
List<Lotto> lottos = lottoService.getByRound(round);

model.put("lottos", lottos);
model.put("countOfAuto", req.queryParams("countOfAuto"));
model.put("countOfManual", req.queryParams("countOfManual"));
model.put("round", round);
return render(model, "showLottos.html");
}
}
25 changes: 25 additions & 0 deletions src/main/java/lotto/controller/MainController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package lotto.controller;

import lotto.dao.RoundDao;
import spark.Request;
import spark.Response;

import java.util.HashMap;
import java.util.Map;

import static lotto.WebUILottoApplication.render;

public class MainController {
private final RoundDao roundDao;

public MainController(final RoundDao roundDao) {
this.roundDao = roundDao;
}

public Object main(Request req, Response res) {
Map<String, Object> model = new HashMap<>();
model.put("round", roundDao.getLatest() + 1);
model.put("rounds", roundDao.findAll());
return render(model, "start.html");
}
}
Loading

0 comments on commit ba30165

Please sign in to comment.