-
Notifications
You must be signed in to change notification settings - Fork 0
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
다즐을 사칭한 누누 #14
base: main
Are you sure you want to change the base?
다즐을 사칭한 누누 #14
Changes from all commits
0ab7397
1999be3
fac4aef
173c37a
ab63e63
43fcd82
43b56af
80eff78
41ed14d
24ef594
d16475c
54c5c7d
9b090dd
31868f4
96c63b0
fabeaca
50f676f
97ac688
17c545b
fab6d55
2817635
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,120 @@ | ||
# jwp-racingcar | ||
|
||
## 개요 | ||
|
||
해당 레포지토리는 자동차 경주 게임을 웹 애플리케이션으로 전환하고 DB를 연동한 레포지토리입니다. | ||
|
||
## 기능 목록 | ||
|
||
### 컨트롤러 | ||
|
||
- [x] 자동차 경주 게임을 플레이하기 위한 요청을 받아 우승자와 최종 위치를 응답한다. | ||
|
||
- 요청 형식 | ||
```text | ||
POST /plays HTTP/1.1 | ||
|
||
content-type: application/json; charset=UTF-8 | ||
host: localhost: 8080 | ||
|
||
{ | ||
"names": "브리,토미,브라운", | ||
"count": 10 | ||
} | ||
``` | ||
|
||
- 응답 형식 | ||
```text | ||
HTTP/1.1 200 | ||
Content-Type: application/json | ||
|
||
{ | ||
"winners": "브리", | ||
"racingCars": [ | ||
{ | ||
"name": "브리", | ||
"position": 9 | ||
}, | ||
{ | ||
"name": "토미", | ||
"position": 7 | ||
} | ||
] | ||
} | ||
``` | ||
- [x] 자동차 경주 게임 플레이 이력 조회 요청을 받아 플레이 이력을 응답한다. | ||
|
||
- 요청 형식 | ||
```text | ||
GET /plays HTTP/1.1 | ||
``` | ||
|
||
- 응답 형식 | ||
```text | ||
HTTP/1.1 200 | ||
Content-Type: application/json | ||
|
||
[ | ||
{ | ||
"winners": "브리", | ||
"racingCars": [ | ||
{ | ||
"name": "브리", | ||
"position": 6 | ||
}, | ||
{ | ||
"name": "토미", | ||
"position": 4 | ||
}, | ||
{ | ||
"name": "브라운", | ||
"position": 3 | ||
}, | ||
] | ||
}, | ||
{ | ||
"winners": "브리,토미,브라운", | ||
"racingCars": [ | ||
{ | ||
"name": "브리", | ||
"position": 6 | ||
}, | ||
{ | ||
"name": "토미", | ||
"position": 6 | ||
}, | ||
{ | ||
"name": "브라운", | ||
"position": 6 | ||
}, | ||
] | ||
} | ||
] | ||
``` | ||
|
||
### 서비스 | ||
|
||
- [x] 자동차 경주 게임을 진행 후 결과를 생성한다. | ||
- [x] 자동차 경주 게임 플레이 이력을 조회한다. | ||
|
||
### 레포지토리 | ||
|
||
- [x] 자동차 경주 도메인을 저장한다. | ||
- [x] 자동차 경주 도메인 목록을 조회한다. | ||
|
||
### Dao | ||
|
||
- [x] 자동차 경주 게임 정보를 저장한다. | ||
- [x] 자동차 경주 게임 정보를 조회한다. | ||
- [x] 자동차 경주가 끝난 자동차 정보를 저장한다. | ||
- [x] 자동차 경주가 끝난 자동차 정보를 조회한다. | ||
- [x] 자동차 경주 우승자 정보를 저장한다. | ||
|
||
### DB | ||
|
||
- [x] RacingGame 테이블 생성한다. | ||
- id, trial_count, date | ||
- [x] RacingCar 테이블 생성한다. | ||
- id, game_id, name, position | ||
- [x] RacingWinner 테이블 생성한다. | ||
- id, game_id, car_id | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 정갈하네 역시 누누! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,23 @@ | ||
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' | ||
testImplementation 'org.springframework.boot:spring-boot-starter-test' | ||
implementation 'org.springframework.boot:spring-boot-starter-jdbc' | ||
implementation 'org.springframework.boot:spring-boot-starter-validation' | ||
runtimeOnly 'com.h2database:h2' | ||
} | ||
|
||
tasks.named('test') { | ||
useJUnitPlatform() | ||
useJUnitPlatform() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package racingcar; | ||
|
||
import racingcar.controller.RacingCarConsoleController; | ||
import racingcar.domain.RandomNumberGenerator; | ||
import racingcar.repository.RacingCarConsoleRepository; | ||
import racingcar.service.RacingCarService; | ||
import racingcar.view.InputView; | ||
import racingcar.view.OutputView; | ||
|
||
import java.util.Scanner; | ||
|
||
public class RacingCarConsoleApplication { | ||
|
||
public static void main(String[] args) { | ||
final RacingCarConsoleController racingCarConsoleController = new RacingCarConsoleController( | ||
inputView(), | ||
outputView(), | ||
new RacingCarService(new RacingCarConsoleRepository(), new RandomNumberGenerator()) | ||
Comment on lines
+15
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 변수로 빼주면 가독성이 좋아질거 같아요 |
||
); | ||
racingCarConsoleController.run(); | ||
} | ||
|
||
private static InputView inputView() { | ||
return new InputView(scanner()); | ||
} | ||
|
||
private static Scanner scanner() { | ||
return new Scanner(System.in); | ||
} | ||
|
||
private static OutputView outputView() { | ||
return new OutputView(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package racingcar.controller; | ||
|
||
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.request.RacingCarRequest; | ||
import racingcar.dto.response.RacingGameResponse; | ||
import racingcar.service.RacingCarService; | ||
|
||
import javax.validation.Valid; | ||
import java.util.List; | ||
|
||
@RestController | ||
public class RacingCarApiController { | ||
|
||
private final RacingCarService racingCarService; | ||
|
||
public RacingCarApiController(final RacingCarService racingCarService) { | ||
this.racingCarService = racingCarService; | ||
} | ||
|
||
@PostMapping("/plays") | ||
public ResponseEntity<RacingGameResponse> play(@Valid @RequestBody RacingCarRequest racingCarRequest) { | ||
final RacingGameResponse result = racingCarService.play(racingCarRequest.getNames(), racingCarRequest.getCount()); | ||
return ResponseEntity.ok(result); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 201이 더 좋은 코드같아보이는데? 어떻게 생각해 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 새로운 리소스가 생성되었다는 관점에서 동의합니다 누누 체고 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 누누가 아니라 다즐이었어? ㅇㄴ |
||
} | ||
|
||
@GetMapping("/plays") | ||
public ResponseEntity<List<RacingGameResponse>> findPlays() { | ||
final List<RacingGameResponse> result = racingCarService.findPlays(); | ||
return ResponseEntity.ok(result); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package racingcar.controller; | ||
|
||
import racingcar.dto.response.RacingGameResponse; | ||
import racingcar.service.RacingCarService; | ||
import racingcar.view.InputView; | ||
import racingcar.view.OutputView; | ||
|
||
public class RacingCarConsoleController { | ||
|
||
private final InputView inputView; | ||
private final OutputView outputView; | ||
private final RacingCarService racingCarService; | ||
|
||
public RacingCarConsoleController(final InputView inputView, final OutputView outputView, final RacingCarService racingCarService) { | ||
this.inputView = inputView; | ||
this.outputView = outputView; | ||
this.racingCarService = racingCarService; | ||
} | ||
|
||
public void run() { | ||
final RacingGameResponse racingGameResponse = playRacingGame(); | ||
outputView.printRacingGameResult(racingGameResponse); | ||
} | ||
|
||
private RacingGameResponse playRacingGame() { | ||
while (true) { | ||
try { | ||
return racingCarService.play(inputView.readCarNames(), inputView.readCount()); | ||
} catch (IllegalArgumentException e) { | ||
outputView.printErrorMessage(e.getMessage()); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package racingcar.dao; | ||
|
||
import org.springframework.jdbc.core.BatchPreparedStatementSetter; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
import org.springframework.stereotype.Repository; | ||
import racingcar.entity.RacingCarEntity; | ||
|
||
import java.sql.PreparedStatement; | ||
import java.sql.SQLException; | ||
import java.util.List; | ||
|
||
@Repository | ||
public class RacingCarDao { | ||
|
||
private final JdbcTemplate jdbcTemplate; | ||
|
||
public RacingCarDao(JdbcTemplate jdbcTemplate) { | ||
this.jdbcTemplate = jdbcTemplate; | ||
} | ||
|
||
public void saveAll(final List<RacingCarEntity> racingCarEntities) { | ||
final String sql = "INSERT INTO RACING_CAR (game_id, name, position) VALUES (?, ?, ?)"; | ||
|
||
jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 쩌는데?
|
||
@Override | ||
public void setValues(PreparedStatement ps, int i) throws SQLException { | ||
ps.setLong(1, racingCarEntities.get(i).getGameId()); | ||
ps.setString(2, racingCarEntities.get(i).getName()); | ||
ps.setInt(3, racingCarEntities.get(i).getPosition()); | ||
} | ||
|
||
@Override | ||
public int getBatchSize() { | ||
return racingCarEntities.size(); | ||
} | ||
}); | ||
Comment on lines
+24
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. simpleInsert 사용 해보면 어때? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 써봤다가 Insert 쿼리 1개에 너무 의존적인 객체인 것 같아서 모든 쿼리에 범용적으로 사용할 수 있는 JdbcTemplate으로 돌아왔어 진짜 깔끔해지기는 하더라 좋은 의견 감사합니다 👍 |
||
} | ||
|
||
public List<RacingCarEntity> findAllByGameId(final Long gameId) { | ||
final String sql = "SELECT * FROM RACING_CAR WHERE game_id = ?"; | ||
|
||
return jdbcTemplate.query( | ||
sql, | ||
(rs, rowNum) -> RacingCarEntity.builder() | ||
.id(rs.getLong(1)) | ||
.gameId(rs.getLong(2)) | ||
.name(rs.getString(3)) | ||
.position(rs.getInt(4)) | ||
.build(), | ||
gameId | ||
Comment on lines
+44
to
+50
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 왜 빌더를 둔거야? 궁금스 궁금스 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
사실 필드가 적다면 생성자나 정적 팩터리 메서드 사용하는게 훨씬 좋을 것 같아 🥳 |
||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package racingcar.dao; | ||
|
||
import org.springframework.jdbc.core.JdbcTemplate; | ||
import org.springframework.jdbc.support.GeneratedKeyHolder; | ||
import org.springframework.jdbc.support.KeyHolder; | ||
import org.springframework.stereotype.Repository; | ||
import racingcar.entity.RacingGameEntity; | ||
|
||
import java.sql.PreparedStatement; | ||
import java.sql.Timestamp; | ||
import java.util.List; | ||
import java.util.Objects; | ||
|
||
@Repository | ||
public class RacingGameDao { | ||
Comment on lines
+14
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이거까지 빈이라면 개발자가 어떤 것을 사용해야되는지 감을 잡기 어려울 것 같아서 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 어떤 것을 사용해야되는지가 어떤 의미일까용? |
||
|
||
private final JdbcTemplate jdbcTemplate; | ||
|
||
public RacingGameDao(JdbcTemplate jdbcTemplate) { | ||
this.jdbcTemplate = jdbcTemplate; | ||
} | ||
|
||
public Long save(final RacingGameEntity racingGameEntity) { | ||
final String sql = "INSERT INTO RACING_GAME (trial_count) VALUES (?)"; | ||
|
||
final KeyHolder keyHolder = new GeneratedKeyHolder(); | ||
jdbcTemplate.update(connection -> { | ||
final PreparedStatement preparedStatement = connection.prepareStatement(sql, new String[]{"id"}); | ||
preparedStatement.setInt(1, racingGameEntity.getTrialCount()); | ||
return preparedStatement; | ||
}, keyHolder); | ||
|
||
return Objects.requireNonNull(keyHolder.getKey()).longValue(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Objects.requireNonNull(); 사용한 이유는 뭐야?? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. https://hudi.blog/java-requirenonnull/ intelliJ의 추천이었지만, 리뷰를 보고 저도 찾아보게 되었습니다 👍 |
||
} | ||
|
||
public List<RacingGameEntity> findAll() { | ||
final String sql = "SELECT * FROM RACING_GAME"; | ||
|
||
return jdbcTemplate.query( | ||
sql, | ||
(rs, rowNum) -> RacingGameEntity.builder() | ||
.id(rs.getLong(1)) | ||
.trialCount(rs.getInt(2)) | ||
.date(new Timestamp(rs.getDate(3).getTime()).toLocalDateTime()) | ||
.build() | ||
); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
꼼꼼하시네요!