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

[2단계 - 웹 자동차 경주] 허브(방대의) 미션 제출합니다. #128

Merged
merged 37 commits into from
Apr 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
8217daa
refactor: 서비스 단위테스트 Mockito 사용하도록 변경
greeng00se Apr 16, 2023
dc8a390
refactor: NumberGenerator Bean 설정파일을 이용하여 등록하도록 변경
greeng00se Apr 16, 2023
3f180ae
test: WebRacingGameController 슬라이스 테스트로 변경
greeng00se Apr 16, 2023
5a5bb8c
docs: 요구사항 정리
greeng00se Apr 17, 2023
687c018
refactor: DB 테이블 변경 및 엔티티 클래스 추가
greeng00se Apr 17, 2023
0254c3a
refactor: 게임 반복진행 로직을 게임 내부로 이동
greeng00se Apr 17, 2023
787df6f
refactor: 우승자 및 참가자를 리스트 형태로 받도록 수정
greeng00se Apr 17, 2023
c76a89e
refactor: 참가한 자동차를 전부 반환하는 메서드명 변경
greeng00se Apr 17, 2023
9ee855f
test: 테스트 메서드명 한국어로 변경
greeng00se Apr 17, 2023
8f58fc3
test: TestNumberGenerator 구현체 deque로 변경
greeng00se Apr 17, 2023
8c84be5
refactor: 콘솔 애플리케이션 출력 변경 및 중복 로직 제거
greeng00se Apr 17, 2023
e6dfb73
refactor: 데이터 저장시 SimpleJdbcInsert 사용하도록 변경
greeng00se Apr 17, 2023
afe536a
refactor: 도메인 문자열 상수 제거
greeng00se Apr 17, 2023
8774a6c
refactor: 더욱 의미있는 DTO명으로 변경
greeng00se Apr 17, 2023
a133140
feat: 엔티티를 매핑해주는 역할을 담당하는 클래스 추가
greeng00se Apr 17, 2023
9dc8c73
feat: GameDao가 키를 Optional 형태로 반환하도록 수정
greeng00se Apr 17, 2023
b022338
feat: CarDao 조회 기능 구현
greeng00se Apr 17, 2023
13b849a
feat: Car 엔티티를 받아 GamePlayResponseDto 리스트로 매핑 기능 추가
greeng00se Apr 17, 2023
29f8189
feat: RacingGameService 조회 기능 추가
greeng00se Apr 17, 2023
f2f7d91
feat: RacingGameController 조회 기능 추가
greeng00se Apr 17, 2023
c8b5b21
feat: RacingGameController 조회 기능 추가
greeng00se Apr 17, 2023
5bde85a
feat: request에 validation 적용
greeng00se Apr 17, 2023
ff564cf
remote: 필요없는 코드 제거
greeng00se Apr 18, 2023
55cdf91
refactor: 예외 출력 메시지 수정
greeng00se Apr 18, 2023
ee97a59
refactor: simpleJdbcInsert 변수명 변경
greeng00se Apr 18, 2023
12d6e83
conflict 해결
greeng00se Apr 18, 2023
a957c5c
refactor: Controller에서 ResponseEntity 사용하도록 수정
greeng00se Apr 18, 2023
fbd5d7f
feat: Override 빠진 부분 추가
greeng00se Apr 18, 2023
9934292
test: 테스트 잘못 작성된 부분 수정
greeng00se Apr 18, 2023
3781e59
feat: CarEntity의 필드 final 적용
greeng00se Apr 19, 2023
446e7e4
test: 검증부 개선
greeng00se Apr 19, 2023
9e8e755
refactor: DAO에서 빈 아이디를 반환받는 경우 IllegalStateException을 던지도록 설정
greeng00se Apr 19, 2023
8adb76a
feat: IllegalStateException 예외 핸들링 추가
greeng00se Apr 19, 2023
f913f4e
feat: 통합 테스트 추가
greeng00se Apr 19, 2023
57d98cd
refactor: CarDao 메서드 변수명 변경
greeng00se Apr 19, 2023
4ac2929
feat: 조회시 transactional readOnly 설정
greeng00se Apr 19, 2023
04a45cd
test: 테스트 클래스명 변경
greeng00se Apr 19, 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
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,22 @@
### 요구사항

- [x] 자동차 경주 코드 가져오기
- [x] 웹 요청/응답 구현하기
- [x] 게임 실행 기능
- [x] 게임 실행 요청 구현
- [x] 게임 저장 기능 구현
- [x] 자동차 저장 기능 구현
- [x] 게임 조회 기능
- [x] 게임 조회 요청 구현
- [x] 콘솔 애플리케이션 출력 변경
- [x] 중간 과정을 출력하는 로직 제거
- [x] 우승자와 플레이어별 최종 이동거리를 출력하도록 수정
- [x] 콘솔과 웹의 중복 코드 제거
- [x] DB 연동하기

### Database

<img width="517" alt="image" src="https://user-images.githubusercontent.com/58586537/232510797-0c0ea14f-4ce9-4d74-a997-1ecdc3175491.png">

### API

[API 명세](http-request.http)
19 changes: 10 additions & 9 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.9'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
id 'java'
id 'org.springframework.boot' version '2.7.9'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

sourceCompatibility = '11'

repositories {
mavenCentral()
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
testImplementation 'org.springframework.boot:spring-boot-starter-test'

implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'com.h2database:h2'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'com.h2database:h2'
}

tasks.named('test') {
useJUnitPlatform()
useJUnitPlatform()
}
18 changes: 18 additions & 0 deletions http-request.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
### 게임 실행

POST localhost:8080/plays
Content-Type: application/json

{
"names": [
"브리",
"토미",
"브라운"
],
"count": 10
}

### 게임 조회

GET http://localhost:8080/plays
Content-Type: application/json
33 changes: 33 additions & 0 deletions src/main/java/racingcar/ConsoleRacingGameApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package racingcar;

import java.util.Scanner;
import racingcar.controller.ConsoleRacingGameController;
import racingcar.dao.ConsoleCarDao;
import racingcar.dao.ConsoleGameDao;
import racingcar.domain.RandomNumberGenerator;
import racingcar.service.RacingGameMapper;
import racingcar.service.RacingGameService;
import racingcar.view.InputParser;
import racingcar.view.InputView;
import racingcar.view.OutputView;

public class ConsoleRacingGameApplication {
public static void main(String[] args) {
final RacingGameService racingGameService = generateRacingGameService();
final ConsoleRacingGameController racingGameController = new ConsoleRacingGameController(
racingGameService,
new InputView(new InputParser(), new Scanner(System.in)),
new OutputView()
);
racingGameController.run();
}

private static RacingGameService generateRacingGameService() {
return new RacingGameService(
new RandomNumberGenerator(),
new RacingGameMapper(),
new ConsoleGameDao(),
new ConsoleCarDao()
);
}
}
39 changes: 0 additions & 39 deletions src/main/java/racingcar/RacingGameApplication.java

This file was deleted.

7 changes: 3 additions & 4 deletions src/main/java/racingcar/WebRacingGameApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
@SpringBootApplication
public class WebRacingGameApplication {

public static void main(String[] args) {
SpringApplication.run(WebRacingGameApplication.class, args);
}

public static void main(String[] args) {
SpringApplication.run(WebRacingGameApplication.class, args);
}
}
15 changes: 15 additions & 0 deletions src/main/java/racingcar/config/RacingGameConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package racingcar.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import racingcar.domain.NumberGenerator;
import racingcar.domain.RandomNumberGenerator;

@Configuration
public class RacingGameConfig {

@Bean
public NumberGenerator numberGenerator() {
return new RandomNumberGenerator();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package racingcar.controller;

import racingcar.dto.GamePlayRequestDto;
import racingcar.dto.GamePlayResponseDto;
import racingcar.service.RacingGameService;
import racingcar.view.InputView;
import racingcar.view.OutputView;

public class ConsoleRacingGameController {
private final RacingGameService racingGameService;
private final InputView inputView;
private final OutputView outputView;

public ConsoleRacingGameController(
final RacingGameService racingGameService,
final InputView inputView,
final OutputView outputView
) {
this.racingGameService = racingGameService;
this.inputView = inputView;
this.outputView = outputView;
}

public void run() {
try {
final GamePlayRequestDto request = inputView.readGamePlayRequest();
final GamePlayResponseDto response = racingGameService.play(request);
outputView.printResult(response);
} catch (final IllegalArgumentException e) {
outputView.printErrorMessage(e.getMessage());
}
}
}
55 changes: 0 additions & 55 deletions src/main/java/racingcar/controller/RacingGameController.java

This file was deleted.

21 changes: 17 additions & 4 deletions src/main/java/racingcar/controller/WebRacingGameController.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package racingcar.controller;

import java.util.List;
import javax.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import racingcar.dto.GameRequest;
import racingcar.dto.GameResponse;
import racingcar.dto.GamePlayRequestDto;
import racingcar.dto.GamePlayResponseDto;
import racingcar.service.RacingGameService;

@RestController
Expand All @@ -16,7 +21,15 @@ public WebRacingGameController(final RacingGameService racingGameService) {
}

@PostMapping("/plays")
public GameResponse plays(@RequestBody final GameRequest gameRequest) {
return racingGameService.play(gameRequest);
public ResponseEntity<GamePlayResponseDto> play(@RequestBody @Valid final GamePlayRequestDto request) {
final GamePlayResponseDto result = racingGameService.play(request);
return ResponseEntity.status(HttpStatus.CREATED)
.body(result);
}

@GetMapping("/plays")
public ResponseEntity<List<GamePlayResponseDto>> findAll() {
final List<GamePlayResponseDto> result = racingGameService.findAll();
return ResponseEntity.ok(result);
}
}
6 changes: 4 additions & 2 deletions src/main/java/racingcar/dao/CarDao.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package racingcar.dao;

import java.util.List;
import racingcar.domain.Car;
import racingcar.entity.CarEntity;

public interface CarDao {
void saveAll(final int gameId, final List<Car> cars);
void saveAll(final List<CarEntity> cars);

List<CarEntity> findAll();
}
47 changes: 26 additions & 21 deletions src/main/java/racingcar/dao/CarJdbcDao.java
Original file line number Diff line number Diff line change
@@ -1,38 +1,43 @@
package racingcar.dao;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Component;
import racingcar.domain.Car;
import racingcar.entity.CarEntity;

@Component
public class CarJdbcDao implements CarDao {
private final JdbcTemplate jdbcTemplate;
private final SimpleJdbcInsert jdbcInsert;
private final RowMapper<CarEntity> rowMapper = (resultSet, rowNum) -> new CarEntity(
resultSet.getInt("id"),
resultSet.getString("name"),
resultSet.getInt("position"),
resultSet.getBoolean("winner"),
resultSet.getInt("game_id")
);

public CarJdbcDao(final JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
this.jdbcInsert = new SimpleJdbcInsert(jdbcTemplate)
.withTableName("Car")
.usingGeneratedKeyColumns("id");
}

public void saveAll(final int gameId, final List<Car> cars) {
final String sql = "INSERT INTO car(name, position, game_id) VALUES (?, ?, ?)";
final BatchPreparedStatementSetter batchPreparedStatementSetter = new BatchPreparedStatementSetter() {

@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
final Car car = cars.get(i);
ps.setString(1, car.getName());
ps.setInt(2, car.getPosition());
ps.setInt(3, gameId);
}
@Override
public void saveAll(final List<CarEntity> cars) {
final BeanPropertySqlParameterSource[] parameterSources = cars.stream()
.map(BeanPropertySqlParameterSource::new)
.toArray(BeanPropertySqlParameterSource[]::new);
jdbcInsert.executeBatch(parameterSources);
}

@Override
public int getBatchSize() {
return cars.size();
}
};
jdbcTemplate.batchUpdate(sql, batchPreparedStatementSetter);
@Override
public List<CarEntity> findAll() {
final String sql = "SELECT * FROM CAR";
return jdbcTemplate.query(sql, rowMapper);
}
}
15 changes: 15 additions & 0 deletions src/main/java/racingcar/dao/ConsoleCarDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package racingcar.dao;

import java.util.List;
import racingcar.entity.CarEntity;

public class ConsoleCarDao implements CarDao {
@Override
public void saveAll(final List<CarEntity> cars) {
}

@Override
public List<CarEntity> findAll() {
return List.of();
}
}
Loading