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

[Spring 체스 - 2단계] 레넌(조형래) 미션 제출합니다. #473

Merged
merged 33 commits into from
May 4, 2022
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
32f961a
refactor: 의존성 주입 생성자 방식으로 변경
brorae Apr 26, 2022
ededdea
refactor: init.sql 순서 변경
brorae Apr 26, 2022
d34266f
refactor: DB 수정 및 schema.sql추가
brorae Apr 30, 2022
8776d77
feat: CRUD 가능하도록 GameDao, BoardDao 작성
brorae Apr 30, 2022
230bbf5
feat: ChessService 로직 작성
brorae Apr 30, 2022
77c91ae
feat: 체스방에 참여하는 기능 구현
brorae Apr 30, 2022
71f92a3
chore: spark 관련 dependency 제거
brorae Apr 30, 2022
50e0dfa
test: 가짜 객체를 통한 service test 작성
brorae Apr 30, 2022
aafbc20
refactor: 줄바꿈 제거 및 파일 이름 수정
brorae Apr 30, 2022
6ba5fc4
chore: 패키지 이름 dao로 변경
brorae Apr 30, 2022
f680413
chore: 사용하지 않는 클래스 제거
brorae Apr 30, 2022
0830307
refactor: RoomDto로 데이터 전달받도록 수정
brorae Apr 30, 2022
61caa0e
refactor: Model을 주입 받는 방식으로 수정 및 메소드 이름 & 매핑 방식 수정
brorae May 1, 2022
9c5fd5e
refactor: FakeDao 패키지 이동 및 누락된 테스트 코드 작성
brorae May 1, 2022
08f0fc7
refactor: StatusDto scores를 파라미터로 받도록 수정
brorae May 1, 2022
9543f60
chore: css파일 분리 및 password 타입 변경
brorae May 1, 2022
f8d9cbb
refactor: 방 이름 검증 로직 Dto로 변경 및 예외처리
brorae May 1, 2022
1d62f32
refactor: 테스트 코드에서만 사용되는 메소드 제거
brorae May 1, 2022
7bcec61
refactor: toString 메소드 사용 제거
brorae May 1, 2022
3ce5c9e
refactor: 미사용 메서드 제거
brorae May 1, 2022
f147843
refactor: DB Column의 길이에 맞춰 검증로직 추가
brorae May 1, 2022
35f936e
refactor: Game Entity 추가하여 GameDao에서 반환하도록 변경
brorae May 1, 2022
784f209
test: 누락된 delete 메서드 테스트 추가
brorae May 1, 2022
7155bb8
refactor: 테스트 코드에서만 사용되는 메서드 제거
brorae May 1, 2022
f0baa68
refactor: 공백 제거
brorae May 2, 2022
cd07be2
refactor: 파라미터 변경 및 코드 간단하게 수정
brorae May 2, 2022
df34419
chore: application.yml 분리
brorae May 2, 2022
cb753c7
refactor: state, piece 상수 enum에서 관리하도록 수정
brorae May 3, 2022
60193c5
refactor: dto 정적팩토리 메서드 작성 및 코드 수정
brorae May 3, 2022
1b2948e
refactor: RowMapper 적용 및 Dto로 책임 분리
brorae May 4, 2022
976edbe
refactor: Game에 비밀번호가 같은지 메시지를 던지도록 수정
brorae May 4, 2022
2bbcf46
refactor: 불필요 메서드 제거
brorae May 4, 2022
0d728d7
refactor: 공백 제거
brorae May 4, 2022
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
3 changes: 0 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ repositories {
}

dependencies {
implementation 'com.sparkjava:spark-core:2.9.3'
implementation 'com.sparkjava:spark-template-handlebars:2.7.1'

implementation 'ch.qos.logback:logback-classic:1.2.10'
testImplementation 'org.assertj:assertj-core:3.22.0'
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2'
Expand Down
16 changes: 9 additions & 7 deletions docker/db/mysql/init/init.sql
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
create table game
(
id int auto_increment
primary key,
title varchar(20) not null,
password varchar(20) not null,
state varchar(20) not null
);

create table board
(
position varchar(5) not null,
Expand All @@ -9,10 +18,3 @@ create table board
foreign key (game_id) references game (id)
on update cascade on delete cascade
);

create table game
(
id int auto_increment
primary key,
state varchar(20) not null
);
6 changes: 6 additions & 0 deletions src/main/java/chess/controller/ErrorController.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package chess.controller;

import org.springframework.beans.BeanInstantiationException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
Expand All @@ -8,6 +9,11 @@
@ControllerAdvice
public class ErrorController {

@ExceptionHandler(BeanInstantiationException.class)
public ResponseEntity<String> errorBeanResponse(IllegalArgumentException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}

@ExceptionHandler({IllegalStateException.class, IllegalArgumentException.class})
public ResponseEntity<String> errorResponse(Exception e) {
return ResponseEntity.badRequest().body(e.getMessage());
Expand Down
78 changes: 51 additions & 27 deletions src/main/java/chess/controller/WebController.java
Original file line number Diff line number Diff line change
@@ -1,64 +1,88 @@
package chess.controller;

import chess.domain.chessboard.ChessBoard;
import chess.domain.piece.generator.NormalPiecesGenerator;
import chess.dto.BoardDto;
import chess.dto.GameDto;
import chess.dto.MoveDto;
import chess.dto.RoomDto;
import chess.dto.StatusDto;
import chess.service.ChessService;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class WebController {

private final ChessService chessService;

@Autowired
public WebController(ChessService chessService) {
this.chessService = chessService;
}

@GetMapping("/")
public ModelAndView selectGame() {
BoardDto boardDto = chessService.selectBoard();
String winner = chessService.selectWinner();
public String selectGame(Model model) {
List<GameDto> games = chessService.findGame();
model.addAttribute("game", games);
return "index";
}

@PostMapping("/game")
public String insertGame(RoomDto roomDto) {
chessService.insertGame(roomDto, new ChessBoard(new NormalPiecesGenerator()));
brorae marked this conversation as resolved.
Show resolved Hide resolved
return "redirect:/";
}

Map<String, Object> model = new HashMap<>();
model.put("board", boardDto);
model.put("winner", winner);
@GetMapping("/game/{gameId}")
public String startGame(@PathVariable int gameId, Model model) {
BoardDto boardDto = chessService.selectBoard(gameId);
String winner = chessService.selectWinner(gameId);
String state = chessService.selectState(gameId);

return new ModelAndView("index", model);
model.addAttribute("board", boardDto);
model.addAttribute("id", gameId);
model.addAttribute("winner", winner);
model.addAttribute("state", state);

return "game";
}

@GetMapping("/game")
public ModelAndView insertGame() {
chessService.insertGame();
return new ModelAndView("redirect:/");
@PutMapping("/game/board/{gameId}")
public String movePiece(@PathVariable int gameId, MoveDto moveDto) {
chessService.movePiece(gameId, moveDto.getFrom(), moveDto.getTo());
return "redirect:/game/" + gameId;
}

@PutMapping("/game/board")
public ModelAndView updateBoard(MoveDto moveDto) {
chessService.updateBoard(moveDto.getFrom(), moveDto.getTo());
return new ModelAndView("redirect:/");
@PutMapping("/game/{gameId}")
public String restartGame(@PathVariable int gameId) {
chessService.restartGame(gameId);
return "redirect:/game/" + gameId;
}

@GetMapping("/game/status")
@GetMapping("/game/status/{gameId}")
@ResponseBody
public ResponseEntity<StatusDto> selectStatus() {
StatusDto statusDto = chessService.selectStatus();
public ResponseEntity<StatusDto> selectStatus(@PathVariable int gameId) {
StatusDto statusDto = chessService.selectStatus(gameId);
return ResponseEntity.ok().body(statusDto);
}

@DeleteMapping("/game")
public ModelAndView deleteGame() {
chessService.deleteGame();
return new ModelAndView("redirect:/");
@PutMapping("/game/end/{gameId}")
public String endGame(@PathVariable int gameId) {
chessService.endGame(gameId);
return "redirect:/";
}

@DeleteMapping("/game/{gameId}")
public String deleteGame(@PathVariable int gameId, String password) {
chessService.deleteGame(gameId, password);
return "redirect:/";
}
}
16 changes: 16 additions & 0 deletions src/main/java/chess/dao/BoardDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package chess.dao;

import chess.domain.chessboard.ChessBoard;
import chess.domain.piece.Piece;
import chess.domain.position.Position;

public interface BoardDao {

void save(ChessBoard chessBoard, int gameId);

ChessBoard findById(int id);

int update(Position position, Piece piece, int gameId);

void delete(int gameId);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package chess.repository;
package chess.dao;

import chess.domain.chessboard.ChessBoard;
import chess.domain.piece.Piece;
Expand All @@ -7,31 +7,35 @@
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class BoardDao {
public class BoardDaoImpl implements BoardDao {

@Autowired
private JdbcTemplate jdbcTemplate;

public void save(ChessBoard chessBoard, Long gameId) {
public BoardDaoImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

@Override
public void save(ChessBoard chessBoard, int gameId) {
String sql = "insert into board (position, symbol, color, game_id) values (?, ?, ?, ?)";

List<Object[]> board = chessBoard.getPieces().entrySet().stream()
.map(entry -> new Object[]{entry.getKey().toString(), entry.getValue().getSymbol().name(),
.map(entry -> new Object[]{entry.getKey().getValue(), entry.getValue().getSymbol().name(),
entry.getValue().getColor().name(), gameId})
.collect(Collectors.toList());
brorae marked this conversation as resolved.
Show resolved Hide resolved

jdbcTemplate.batchUpdate(sql, board);
}

public ChessBoard find() {
String sql = "select position, symbol, color from board";
@Override
public ChessBoard findById(int id) {
String sql = "select position, symbol, color from board where game_id = ?";

List<Map<String, Object>> squares = jdbcTemplate.queryForList(sql);
List<Map<String, Object>> squares = jdbcTemplate.queryForList(sql, id);
Map<Position, Piece> board = new HashMap<>();
for (Map<String, Object> square : squares) {
board.put(
Expand All @@ -41,8 +45,15 @@ public ChessBoard find() {
return new ChessBoard(board);
}

public int update(Position position, Piece piece, Long gameId) {
@Override
public int update(Position position, Piece piece, int gameId) {
String sql = "update board set symbol = (?), color = (?) where game_id = (?) and position = (?)";
return jdbcTemplate.update(sql, piece.getSymbol().name(), piece.getColor().name(), gameId, position.toString());
return jdbcTemplate.update(sql, piece.getSymbol().name(), piece.getColor().name(), gameId, position.getValue());
}

@Override
public void delete(int gameId) {
String sql = "delete from board where game_id = ?";
jdbcTemplate.update(sql, gameId);
}
}
20 changes: 20 additions & 0 deletions src/main/java/chess/dao/GameDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package chess.dao;

import chess.domain.state.State;
import chess.entity.Game;
import java.util.List;

public interface GameDao {

int save(String title, String password, String state);
brorae marked this conversation as resolved.
Show resolved Hide resolved

List<Game> findAll();

Game findById(int id);

State findState(int id);

int update(String state, int id);

int delete(int id);
}
75 changes: 75 additions & 0 deletions src/main/java/chess/dao/GameDaoImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package chess.dao;

import chess.domain.state.State;
import chess.entity.Game;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Repository;

@Repository
public class GameDaoImpl implements GameDao {
brorae marked this conversation as resolved.
Show resolved Hide resolved

private JdbcTemplate jdbcTemplate;

public GameDaoImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

@Override
public int save(String title, String password, String state) {
SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("game")
.usingGeneratedKeyColumns("id");
Map<String, String> params = new HashMap<>();
params.put("title", title);
params.put("password", password);
params.put("state", state);

int id = simpleJdbcInsert.executeAndReturnKey(params).intValue();
return id;
}

@Override
public List<Game> findAll() {
String sql = "select * from game";
return jdbcTemplate.query(sql, (rs, rowNum) -> {
Game game = new Game(rs.getInt("id"), rs.getString("title"), rs.getString("password"),
rs.getString("state"));
return game;
});
}

@Override
public Game findById(int id) {
String sql = "select * from game where id = ?";
return jdbcTemplate.queryForObject(sql, (rs, rowNum) -> {
Game game = new Game(rs.getInt("id"), rs.getString("title"), rs.getString("password"),
rs.getString("state"));
return game;
}, id);
}

@Override
public State findState(int id) {
String sql = "select state from game where id = ?";
return jdbcTemplate.queryForObject(sql, (rs, rowNum) -> {
State state = State.of(rs.getString("state"));
return state;
}, id);
}

@Override
public int update(String state, int id) {
String sql = "update game set state=? where id=?";
jdbcTemplate.update(sql, state, id);
return id;
}

@Override
public int delete(int id) {
String sql = "delete from game where id = ?";
return jdbcTemplate.update(sql, id);
}
}
2 changes: 1 addition & 1 deletion src/main/java/chess/domain/chessboard/ChessBoard.java
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,6 @@ public Map<Position, Piece> getPieces() {
public Map<String, Piece> toMap() {
return pieces.entrySet()
.stream()
.collect(Collectors.toMap(m -> m.getKey().toString(), Map.Entry::getValue));
.collect(Collectors.toMap(m -> m.getKey().getValue(), Map.Entry::getValue));
}
}
5 changes: 0 additions & 5 deletions src/main/java/chess/domain/position/Column.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,4 @@ public Column move(final int value) {
public int getValue() {
return value;
}

@Override
public String toString() {
return name().toLowerCase(Locale.ROOT);
}
}
9 changes: 8 additions & 1 deletion src/main/java/chess/domain/position/Position.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,15 @@ public int hashCode() {
return Objects.hash(column, row);
}

public String getValue() {
return column.name().toLowerCase(Locale.ROOT) + row.getValue();
}

@Override
public String toString() {
return column.toString() + row.toString();
return "Position{" +
"column=" + column +
", row=" + row +
'}';
}
}
5 changes: 0 additions & 5 deletions src/main/java/chess/domain/position/Row.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,4 @@ public Row move(final int value) {
public int getValue() {
return value;
}

@Override
public String toString() {
return Integer.toString(value);
}
}
Loading