Skip to content

Commit

Permalink
[라빈] 체스 스프링 4단계 미션 제출합니다. (#195)
Browse files Browse the repository at this point in the history
* docs: README.md 수정 - 레벨 4

* feat: 데이터베이스 스키마 업데이트

schema.sql 에 game 테이블 정보 추가, history 테이블과 game 테이블 연결

* feat: 테스트용 데이터베이스 설정

application.properties test의 resources 디렉토리에 생성, h2 사용

* feat: 게임 생성 후 DB에 저장 기능 구현

Game entity 생성
schema.sql 테이블이 없는 경우에만 생성하도록 변경
GameRepositoryTest 테스트 코드 추가

* feat: 게임 DB에 조회 기능 구현

GameRepository findAll() 오버라이드
GameRepositoryTest 조회 테스트 작성
Game Equals 오버라이드

* style: 컨벤션을 위한 수정

* feat: game 업데이트 기능 구현

GameRepository findByUuid() 추가
GameRepositoryTest 업데이트 테스트 작성
Game 어노테이션 컨벤션 수정
History 어노테이션 컨벤션 수정

* feat: history 추가 구현

History GameRef와 의존
schema.sql history_game테이블 생성
HistoryRepositoryTest 테스트 코드 추가

* feat: Game에 해당하는 히스토리 전체 조회

Game histories 추가
schema.sql history_game 테이블 삭제
GameRepositoryTest 게임에 해당하는 전체 히스토리 조회 테스트 추가

* fix: 종료된 게임은 전체 조회 목록에서 제외하도록 수정

GameRepository findAll에 쿼리문 추가

* feat: 게임을 생성하고 해당 게임을 불러오는 기능 추가

SpringChessController /new로 post 요청을 보내는 라우트 추가
SpringDataJDBCChessService createGameBy로 메서드명 수정

* style: javascript 컨벤션을 지키기 위해 4칸에서 2칸으로 탭 수정

* feat: move와 loading 관련 api에 gameId를 이용하도록 구현

SpringChessController id를 라우트에 추가
SpringDataJDBCChessService id를 이용해서 해당 게임 정보를 가져오도록 수정
chess.js id를 이용하여 리퀘스트를 보내도록 수정

* feat: 게임이 종료되면 결과 페이지로 넘어가는 기능 구현

SpringChessController result get 라우트 구현
SpringDataJDBCChessService updateCanContinueToFalse를 사용
chess.js 종료시 result.hbs로 이동

* feat: 진행가능한 게임 목록을 보여주는 기능 구현

SpringChessController /games get 라우트 추가
GamesDto 추가
GameRepository findAvailableGames로 메서드명 변경
SpringDataJDBCChessService selectAvailableGames 메서드 추가
index.js 게임 목록을 가져와 보여주는 기능 추가

* feat: 게임 중 나가기 기능 추가

chess.hbs 나가기 링크 추가

* refactor: 사용하지 않는 레포지토리 제거

SpringDataJDBCChessService 리팩토링에 따른 수정
HistoryRepository.java 삭제

* style: index.hbs 뷰 수정

* style: chess.hbs, result.hbs 뷰 수정

* fix: 게임 이름을 입력하지 않으면 빈 보드로 넘어가는 버그 수정

* style: 프로젝트 전체 파일 컨벤션 수정

* fix: 사용자가 데이터베이스에 저장되어 있지 않은 게임 아이디로 정보를 전달할 때 예외 처리 기능 구현

SpringChessController 예외 정보를 담은 Dto 생성해 반환
SpringDataJDBCChessService 예외 발생 시 예외 전달

Co-authored-by: toneyparky <[email protected]>
  • Loading branch information
giantim and toneyparky authored May 4, 2020
1 parent df71d9b commit 64a5f56
Show file tree
Hide file tree
Showing 32 changed files with 847 additions and 508 deletions.
32 changes: 30 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,34 @@
# 체스 3단계 - Spring Data JDBC 적용하기

## **프로그래밍 요구사항**
- Spring Data JDBC를 활용하여 기존에 사용하던 DB에 접근하기
- Spring Data JDBC를 활용하여 기존에 사용하던 DB에 접근하기.
- 엔티티 클래스를 만들어 DB 테이블과 맵핑한다.
- Spring Data JDBC에서 제공하는 Repository를 활용하여 DB에 접근한다.
- Spring Data JDBC에서 제공하는 Repository를 활용하여 DB에 접근한다.

# 체스 4단계 - 동시에 여러 게임 하기

## **프로그래밍 요구사항**
- 체스 게임을 진행할 수 있는 방을 만들어서 동시에 여러 게임이 가능하도록 하기.

### 체스방 만들기

- localhost:8080 요청 시 노출되는 페이지에 체스방을 만들 수 있는 버튼이 있다.
- 체스방 이름 입력하기 input을 추가한다.
- 체스방 만들기 버튼을 누르면 새로운 체스판이 초기화 된다.
- 체스방에는 고유식별값이 랜덤으로 부여된다.

### 체스방 목록 조회하기

- localhost:8080 요청 시 체스방 목록을 조회할 수 있다
- 체스방 목록에는 체스방 제목이 표시된다.
- 방법은 '/'로 GET 요청을 보내면 체스방에 대한 JSON이 반환된다.
- 그리고 해당 JSON을 index.js에서 처리하여 보여준다.

### 체스방 참여하기

- localhost:8080 요청 시 체스방 목록에서 체스방을 클릭하면 체스 게임을 이어서 진행할 수 있다.

### 엔티티

- Game : id(auto increment), UUID, name, canContinue
- History : id, start, end, gameId
1 change: 0 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ dependencies {
implementation 'net.rakugakibox.spring.boot:logback-access-spring-boot-starter:2.7.1'
implementation 'pl.allegro.tech.boot:handlebars-spring-boot-starter:0.3.1'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.google.code.gson:gson:2.8.6'
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')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ private String postBoard(Request req, Response res) {
Map<String, Object> model = new HashMap<>();

try {
MoveStatusDto moveStatusDto = sparkChessService.move(new MovingPosition(req.queryParams("source"), req.queryParams("destination")));
MoveStatusDto moveStatusDto = sparkChessService.move(new MovingPosition(req.queryParams("source"),
req.queryParams("destination")));

model.put("normalStatus", moveStatusDto.getNormalStatus());
model.put("winner", moveStatusDto.getWinner());
Expand Down Expand Up @@ -108,7 +109,8 @@ private Map<String, Object> getMovablePositions(Request req, Response res) throw
private Map<String, Object> move(Request req, Response res) {
Map<String, Object> model = new HashMap<>();

DestinationPositionDto destinationPositionDto = sparkChessService.chooseDestinationPosition(req.queryParams("destination"));
DestinationPositionDto destinationPositionDto = sparkChessService.chooseDestinationPosition(
req.queryParams("destination"));

model.put("normalStatus", destinationPositionDto.getNormalStatus().isNormalStatus());
model.put("position", destinationPositionDto.getPosition());
Expand Down
161 changes: 91 additions & 70 deletions src/main/java/wooteco/chess/controller/SpringChessController.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,94 +7,115 @@
import wooteco.chess.domain.game.NormalStatus;
import wooteco.chess.domain.position.MovingPosition;
import wooteco.chess.dto.ChessGameDto;
import wooteco.chess.dto.GamesDto;
import wooteco.chess.dto.MovablePositionsDto;
import wooteco.chess.dto.MoveStatusDto;
import wooteco.chess.service.SpringDataJDBCChessService;
import wooteco.chess.web.JsonTransformer;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

@Controller
public class SpringChessController {
@Autowired
private SpringDataJDBCChessService springChessService;
@Autowired
private SpringDataJDBCChessService springDataJDBCChessService;

@GetMapping("/")
public ModelAndView routeMainPage() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("index");
modelAndView.addObject("normalStatus", NormalStatus.YES.isNormalStatus());
return modelAndView;
}
@GetMapping("/")
public ModelAndView routeMainPage() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("index");
modelAndView.addObject("normalStatus", NormalStatus.YES.isNormalStatus());
return modelAndView;
}

@GetMapping("/new")
public ModelAndView startNewGame() throws SQLException {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("chess");
modelAndView.addObject("normalStatus", NormalStatus.YES.isNormalStatus());
springChessService.clearHistory();
return modelAndView;
}
@GetMapping("/games")
@ResponseBody
public String showGames() {
GamesDto games = springDataJDBCChessService.selectAvailableGames();
return JsonTransformer.toJson(games);
}

@GetMapping("/board")
@ResponseBody
public String setBoard() throws SQLException {
ChessGameDto chessGameDto = springChessService.setBoard();
return JsonTransformer.toJson(chessGameDto);
}
@PostMapping("/new")
@ResponseBody
public String saveNewGame(@RequestBody Map<String, Object> param) {
System.out.println(param.get("gameName"));
ChessGameDto chessGameDto = springDataJDBCChessService.createGameBy((String) param.get("gameName"));

@GetMapping("/source")
@ResponseBody
public String getMovablePositions(@RequestParam String source) throws SQLException {
Map<String, Object> model = new HashMap<>();
try {
MovablePositionsDto movablePositionsDto = springChessService.findMovablePositions(source);
model.put("movable", movablePositionsDto.getMovablePositionNames());
model.put("position", movablePositionsDto.getPosition());
model.put("normalStatus", NormalStatus.YES.isNormalStatus());
return JsonTransformer.toJson(model);
} catch (IllegalArgumentException | UnsupportedOperationException | NullPointerException e) {
model.put("normalStatus", NormalStatus.NO.isNormalStatus());
model.put("exception", e.getMessage());
return JsonTransformer.toJson(model);
}
}
return JsonTransformer.toJson(chessGameDto);
}

@GetMapping("/destination")
@ResponseBody
public String checkMovable(@RequestParam String startPosition, @RequestParam String destination) {
Map<String, Object> model = new HashMap<>();
MoveStatusDto moveStatusDto = springChessService.checkMovable(
new MovingPosition(startPosition, destination));
@GetMapping("/game/{id}")
@ResponseBody
public ModelAndView startGame() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("chess");
modelAndView.addObject("normalStatus", NormalStatus.YES.isNormalStatus());
return modelAndView;
}

model.put("normalStatus", moveStatusDto.getNormalStatus());
model.put("exception", moveStatusDto.getException());
return JsonTransformer.toJson(model);
}
@GetMapping("/board/{id}")
@ResponseBody
public String setBoard(@PathVariable Long id) {
ChessGameDto chessGameDto = springDataJDBCChessService.setBoardBy(id);
return JsonTransformer.toJson(chessGameDto);
}

@PostMapping("/board")
public ModelAndView saveHistory(@RequestBody MovingPosition movingPosition) throws SQLException {
ModelAndView modelAndView = new ModelAndView();
@GetMapping("/board/{id}/source")
@ResponseBody
public String getMovablePositions(@PathVariable Long id, @RequestParam String source) {
Map<String, Object> model = new HashMap<>();
try {
MovablePositionsDto movablePositionsDto = springDataJDBCChessService.findMovablePositions(id, source);
model.put("movable", movablePositionsDto.getMovablePositionNames());
model.put("position", movablePositionsDto.getPosition());
model.put("normalStatus", NormalStatus.YES.isNormalStatus());
return JsonTransformer.toJson(model);
} catch (IllegalArgumentException | UnsupportedOperationException | NullPointerException e) {
model.put("normalStatus", NormalStatus.NO.isNormalStatus());
model.put("exception", e.getMessage());
return JsonTransformer.toJson(model);
}
}

MoveStatusDto moveStatusDto = springChessService.move(movingPosition);
if (moveStatusDto.getWinner().isNone()) {
modelAndView.setViewName("chess");
return modelAndView;
}
modelAndView.setViewName("result");
modelAndView.addObject("winner", moveStatusDto.getWinner());
springChessService.clearHistory();
return modelAndView;
}
@GetMapping("/board/{id}/destination")
@ResponseBody
public String checkMovable(@PathVariable Long id, @RequestParam String startPosition,
@RequestParam String destination) {
Map<String, Object> model = new HashMap<>();
MoveStatusDto moveStatusDto = springDataJDBCChessService.checkMovable(id,
new MovingPosition(startPosition, destination));

@GetMapping("/loading")
public ModelAndView loadGame() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("chess");
modelAndView.addObject("normalStatus", NormalStatus.YES.isNormalStatus());
model.put("normalStatus", moveStatusDto.getNormalStatus());
model.put("exception", moveStatusDto.getException());
return JsonTransformer.toJson(model);
}

return modelAndView;
}
@PostMapping("/board/{id}")
@ResponseBody
public String saveHistory(@PathVariable Long id, @RequestBody MovingPosition movingPosition) {
try {
MoveStatusDto moveStatusDto = springDataJDBCChessService.move(id, movingPosition);
return JsonTransformer.toJson(moveStatusDto);
} catch (IllegalArgumentException e) {
MoveStatusDto moveStatusDto = new MoveStatusDto(false, e.getMessage());
return JsonTransformer.toJson(moveStatusDto);
}
}

@GetMapping("/loading/{id}")
public ModelAndView loadGame() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("chess");
modelAndView.addObject("normalStatus", NormalStatus.YES.isNormalStatus());
return modelAndView;
}

@GetMapping("/result/{winner}")
public ModelAndView showResult(@PathVariable String winner) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("result");
modelAndView.addObject("winner", winner);
return modelAndView;
}
}
3 changes: 2 additions & 1 deletion src/main/java/wooteco/chess/dto/BoardDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import wooteco.chess.domain.piece.pieces.Pieces;
import wooteco.chess.domain.position.Position;

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

Expand All @@ -17,6 +18,6 @@ public BoardDto(Pieces pieces) {
}

public Map<Position, PieceDto> getBoard() {
return board;
return Collections.unmodifiableMap(board);
}
}
21 changes: 17 additions & 4 deletions src/main/java/wooteco/chess/dto/ChessGameDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
import wooteco.chess.domain.game.Turn;

public class ChessGameDto {
private BoardDto boardDto;
private Turn turn;
private ScoreResult score;
private boolean normalStatus;
private Long gameId;
private final BoardDto boardDto;
private final Turn turn;
private final ScoreResult score;
private final boolean normalStatus;

public ChessGameDto(BoardDto boardDto, Turn turn, ScoreResult score, boolean normalStatus) {
this.boardDto = boardDto;
Expand All @@ -16,6 +17,18 @@ public ChessGameDto(BoardDto boardDto, Turn turn, ScoreResult score, boolean nor
this.normalStatus = normalStatus;
}

public ChessGameDto(Long gameId, BoardDto boardDto, Turn turn, ScoreResult score, boolean normalStatus) {
this.gameId = gameId;
this.boardDto = boardDto;
this.turn = turn;
this.score = score;
this.normalStatus = normalStatus;
}

public Long getGameId() {
return gameId;
}

public BoardDto getBoardDto() {
return boardDto;
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/wooteco/chess/dto/DestinationPositionDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import wooteco.chess.domain.game.NormalStatus;

public class DestinationPositionDto {
private String position;
private NormalStatus normalStatus;
private final String position;
private final NormalStatus normalStatus;

public DestinationPositionDto(String position, NormalStatus normalStatus) {
this.position = position;
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/wooteco/chess/dto/GamesDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package wooteco.chess.dto;

import java.util.Collections;
import java.util.Map;

public class GamesDto {
private final Map<Long, String> games;

public GamesDto(Map<Long, String> games) {
this.games = games;
}

public Map<Long, String> getGames() {
return Collections.unmodifiableMap(games);
}
}
7 changes: 4 additions & 3 deletions src/main/java/wooteco/chess/dto/MovablePositionsDto.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
package wooteco.chess.dto;

import java.util.Collections;
import java.util.List;

public class MovablePositionsDto {
private List<String> movablePositionNames;
private String position;
private final List<String> movablePositionNames;
private final String position;

public MovablePositionsDto(List<String> movablePositionNames, String position) {
this.movablePositionNames = movablePositionNames;
this.position = position;
}

public List<String> getMovablePositionNames() {
return movablePositionNames;
return Collections.unmodifiableList(movablePositionNames);
}

public String getPosition() {
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/wooteco/chess/dto/MoveStatusDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
public class MoveStatusDto {
private static final String EMPTY_STRING = "";

private boolean normalStatus;
private Color winner;
private String exception;
private final boolean normalStatus;
private final Color winner;
private final String exception;

public MoveStatusDto(boolean normalStatus, String exception) {
this.normalStatus = normalStatus;
Expand Down
Loading

0 comments on commit 64a5f56

Please sign in to comment.