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 체스 - 3단계] 다니(이다은) 미션 제출합니다. #299

Merged
merged 26 commits into from
May 2, 2021
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5f3ad77
refactor(dao): DBConnection 삭제
da-nyee Apr 23, 2021
b7c61ef
refactor(dao): @Autowired 삭제
da-nyee Apr 23, 2021
eb7622c
refactor(dao): try-catch 삭제
da-nyee Apr 23, 2021
e11a219
docs(readme): 요구사항 정리
da-nyee Apr 23, 2021
1aeb2c0
docs(readme): DB DDL 수정
da-nyee Apr 25, 2021
95c5b86
feat(room): 체스방 목록 조회 기능 추가
da-nyee Apr 25, 2021
5a02315
docs(readme): DB DDL 수정
da-nyee Apr 25, 2021
10a6bfc
feat(room): 체스방 생성 기능 추가
da-nyee Apr 25, 2021
0fd737e
feat(room): 체스방 참여 기능 추가
da-nyee Apr 25, 2021
046c090
feat(resources): 홈 화면 버튼 추가
da-nyee Apr 25, 2021
0339eb5
fix(chess): 서버를 재시작했을 때 이전 게임이 진행되지 않던 버그 해결
da-nyee Apr 25, 2021
d3452e6
fix(chess): King을 잡아도 게임이 종료되지 않던 버그 해결
da-nyee Apr 25, 2021
0401795
style(dao): 코드 포맷 변경
da-nyee Apr 28, 2021
08ce4a1
refactor(player): 사용하지 않는 메소드 삭제
da-nyee Apr 28, 2021
dde125f
refactor(controller): 게임 시작(방 생성) 요청 및 응답 DTO 생성
da-nyee Apr 28, 2021
41c447b
fix(chess): 객체 직렬화 버그 해결
da-nyee Apr 28, 2021
cfcb45a
test(api-controller): 테스트 작성
da-nyee Apr 29, 2021
d5431c3
refactor(chess): View-Controller 사이 DTO 범위 수정
da-nyee Apr 29, 2021
fede792
refactor(chess): Repository-DAO 사이 DTO 범위 수정
da-nyee Apr 29, 2021
cd90bec
refactor(chess): Service 내 DTO 삭제
da-nyee Apr 29, 2021
eece951
feat(resources): schema.sql 추가
da-nyee Apr 29, 2021
13b02f1
refactor(chess): 메소드명, 변수명, 파라미터명 변경
da-nyee Apr 30, 2021
d222c24
refactor(chess): 메소드명 변경
da-nyee Apr 30, 2021
d1e6aac
refactor(chess): url-pattern 방식 변경
da-nyee Apr 30, 2021
5bc1ba5
refactor(js): window.location.href 주소 수정
da-nyee Apr 30, 2021
7db4006
refactor(dto): 클래스명 변경
da-nyee Apr 30, 2021
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
48 changes: 35 additions & 13 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,54 @@
- Spring Framework를 활용하여 애플리케이션을 구동한다.
- Spark를 대체하여 Spring MVC를 활용하여 요청을 받고 응답을 한다.
- Spring JDBC를 활용하여 DB 접근하던 기존 로직을 대체한다.
<br/>

## step1 프로그래밍 요구사항
- 스프링 애플리케이션으로 체스가 실행 가능 해야한다.
- @Controller나 @RestController를 활용하여 요청을 받아야 한다.
- Spring JDBC에서 제공하는 JdbcTemplate를 이용하여 Connection을 직접 만들어 주는 로직을 대체한다.
- JdbcTemplate는 매번 새로 생성하지 않고 빈 주입을 받아서 사용한다.
<br/>

## step2 요구사항
- 체스 게임을 진행할 수 있는 방을 만들어서 동시에 여러 게임이 가능하도록 하기
<br/>

## step2 프로그래밍 요구사항
### 체스방 만들기
- localhost:8080 요청 시 노출되는 페이지에 체스방을 만들 수 있는 버튼이 있다.
- 체스방 만들기 버튼을 누르면 새로운 체스판이 초기화된다.
- 체스방에는 고유 식별값이 부여된다. (이 고유 식별값은 체스방 주소에서 사용됨)
### 체스방 목록 조회하기
- localhost:8080 요청 시 체스방 목록을 조회할 수 있다.
- 체스방 목록에는 체스방 제목이 표시된다.
### 체스방 참여하기
- localhost:8080 요청 시 체스방 목록에서 체스방을 클릭하면 체스 게임을 이어서 진행할 수 있다.
<br/>

## DB DDL
```sql
-- -----------------------------------------------------
-- Table `mydb`.`piece`
-- Table `mychess`.`room`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`piece` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`piece_name` VARCHAR(45) NOT NULL,
`piece_position` VARCHAR(45) NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `mychess`.`room` (
`room_id` BIGINT NOT NULL AUTO_INCREMENT,
`room_name` VARCHAR(45) NOT NULL,
`current_turn` VARCHAR(45) NOT NULL,
PRIMARY KEY (`room_id`)
) CHARSET = utf8, ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `mydb`.`turn`
-- Table `mychess`.`piece`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`turn` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`current_turn` VARCHAR(45) NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `mychess`.`piece` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`piece_name` VARCHAR(45) NOT NULL,
`piece_position` VARCHAR(45) NOT NULL,
`room_id` BIGINT NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`room_id`)
REFERENCES room(`room_id`)
) CHARSET = utf8, ENGINE = InnoDB;
```
19 changes: 14 additions & 5 deletions src/main/java/chess/controller/ChessApiController.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package chess.controller;

import chess.dto.ChessBoardDto;
import chess.dto.request.MoveRequestDto;
import chess.dto.request.TurnChangeRequestDto;
import chess.dto.response.MoveResponseDto;
import chess.service.ChessService;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

@RestController
public class ChessApiController {
Expand All @@ -19,13 +18,23 @@ public ChessApiController(final ChessService chessService) {
this.chessService = chessService;
}

@PostMapping("/room")
public Long start(@RequestBody final String req) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아래 MoveRequestDto처럼 dto를 만들어서 받는 방식이 더 괜찮아보이네요ㅎㅎ

내려줄 때도 마찬가지로 dto를 만들어서 내려주면 클라이언트에서 받기 더 용이할 것 같아요~

return chessService.addRoom(req.split(":")[1].split("\"")[1]);
}

@GetMapping("/board/{roomId}")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

url이 깔끔해졌네요 👍

public ChessBoardDto chess(@PathVariable final Long roomId) {
return chessService.chessBoardFromDB(roomId);
}

@PostMapping(value = "/move", produces = MediaType.APPLICATION_JSON_VALUE)
public MoveResponseDto move(@RequestBody MoveRequestDto moveRequestDto) {
public MoveResponseDto move(@RequestBody final MoveRequestDto moveRequestDto) {
return chessService.move(moveRequestDto);
}

@PostMapping(value = "/turn", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Void> turn(@RequestBody TurnChangeRequestDto turnChangeRequestDto) {
public ResponseEntity<Void> turn(@RequestBody final TurnChangeRequestDto turnChangeRequestDto) {
chessService.changeTurn(turnChangeRequestDto);
return new ResponseEntity<>(HttpStatus.OK);
}
Expand Down
41 changes: 13 additions & 28 deletions src/main/java/chess/controller/ChessController.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package chess.controller;

import chess.dto.ChessBoardDto;
import chess.dto.StringChessBoardDto;
import chess.dto.response.RoomResponseDto;
import chess.dto.response.ScoreResponseDto;
import chess.service.ChessService;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.List;

@Controller
public class ChessController {
Expand All @@ -17,34 +18,18 @@ public ChessController(final ChessService chessService) {
this.chessService = chessService;
}

@GetMapping("/start")
public String start() {
chessService.makeRound();
return makeNewGame();
}

@GetMapping("/reset")
public String reset() {
chessService.resetRound();
return makeNewGame();
@GetMapping("/room-list")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

음 제가 사용하는 url pattern 방식은 아래와 같이 api의 경우 앞에 api를 명시해주어 일반적인 컨트롤러와 분리합니다
ApiController -> /api/rooms
Controller -> /rooms
이렇게 사용하면 /room-list도 패턴에 맞게 적용할 수 있겠네요 ^_^

public String roomList(final Model model) {
List<RoomResponseDto> rooms = chessService.rooms();
model.addAttribute("rooms", rooms);
return "room-list";
}

@GetMapping("/chess")
public String chess(final Model model) throws JsonProcessingException {
ChessBoardDto chessBoard = chessService.chessBoardFromDB();
String jsonFormatChessBoard = chessService.jsonFormatChessBoard(chessBoard);
model.addAttribute("jsonFormatChessBoard", jsonFormatChessBoard);
String currentTurn = chessService.currentTurn();
model.addAttribute("currentTurn", currentTurn);
chessService.updateRound(chessBoard, currentTurn);

ScoreResponseDto scoreResponseDto = chessService.scoreResponseDto();
@GetMapping("/chess/{roomId}")
public String chess(@PathVariable final Long roomId, final Model model) {
ScoreResponseDto scoreResponseDto = chessService.scoreResponseDto(roomId);
model.addAttribute("roomId", roomId);
model.addAttribute("score", scoreResponseDto);
return "chess";
}

private String makeNewGame() {
chessService.initialize();
return "redirect:/chess";
}
}
62 changes: 16 additions & 46 deletions src/main/java/chess/dao/PieceDao.java
Original file line number Diff line number Diff line change
@@ -1,75 +1,45 @@
package chess.dao;

import chess.dao.setting.DBConnection;
import chess.dto.request.MoveRequestDto;
import chess.dto.response.ChessResponseDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;

@Repository
public class PieceDao extends DBConnection {
@Autowired
public class PieceDao {
private final JdbcTemplate jdbcTemplate;

public PieceDao(DataSource dataSource) {
public PieceDao(final DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}

public void initializePieceStatus(final String pieceName, final String piecePosition) {
String query = "INSERT INTO piece (piece_name, piece_position) VALUE (?, ?)";
try {
jdbcTemplate.update(query, pieceName, piecePosition);
} catch (Exception e) {
e.printStackTrace();
}
public void initializePieceStatus(final String pieceName, final String piecePosition, Long roomId) {
String query = "INSERT INTO piece (piece_name, piece_position, room_id) VALUE (?, ?, ?)";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

시간이 되신다면 batch insert도 학습해보시면 도움되실 것 같아요
(적용하실 필요는 없습니다!!)

jdbcTemplate.update(query, pieceName, piecePosition, roomId);
}

public List<ChessResponseDto> showAllPieces() {
List<ChessResponseDto> pieces = new ArrayList<>();
String query = "SELECT * FROM piece";

try {
pieces = jdbcTemplate.query(
query, (rs, rowNum) -> new ChessResponseDto(
rs.getLong("id"),
rs.getString("piece_name"),
rs.getString("piece_position"))
);
} catch (Exception e) {
e.printStackTrace();
}
public List<ChessResponseDto> showAllPieces(final Long roomId) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DTO, entity의 차이를 짚고 넘어가시면 미션 진행하는데 도움이 되실거에요 ^_^

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

키워드 감사합니다~! 개인 블로그에 정리하고 학습 로그에 기록했어요! 🙌

List<ChessResponseDto> pieces;
String query = "SELECT * FROM piece WHERE room_id = ?";
pieces = jdbcTemplate.query(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

바로 return 해줘도 좋겠네요~

query, (rs, rowNum) -> new ChessResponseDto(
rs.getLong("id"),
rs.getString("piece_name"),
rs.getString("piece_position")), roomId
);
return pieces;
}

public void movePiece(final MoveRequestDto moveRequestDto) {
String query = "UPDATE piece SET piece_position=? WHERE piece_position=?";
try {
jdbcTemplate.update(query, moveRequestDto.getTarget(), moveRequestDto.getSource());
} catch (Exception e) {
e.printStackTrace();
}
}

public void removeAllPieces() {
String query = "DELETE FROM piece";
try {
jdbcTemplate.update(query);
} catch (Exception e) {
e.printStackTrace();
}
jdbcTemplate.update(query, moveRequestDto.getTarget(), moveRequestDto.getSource());
}

public void removePiece(final MoveRequestDto moveRequestDto) {
String query = "DELETE FROM piece WHERE piece_position=?";
try {
jdbcTemplate.update(query, moveRequestDto.getTarget());
} catch (Exception e) {
e.printStackTrace();
}
jdbcTemplate.update(query, moveRequestDto.getTarget());
}
}
56 changes: 56 additions & 0 deletions src/main/java/chess/dao/RoomDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package chess.dao;

import chess.dto.request.TurnChangeRequestDto;
import chess.dto.response.RoomResponseDto;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;

import javax.sql.DataSource;
import java.sql.PreparedStatement;
import java.util.List;
import java.util.Objects;

@Repository
public class RoomDao {
private final JdbcTemplate jdbcTemplate;

public RoomDao(final DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}

public Long addRoom(final String roomName) {
KeyHolder keyHolder = new GeneratedKeyHolder();
String query = "INSERT INTO room (room_name, current_turn) VALUES (?, ?)";
jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(query, new String[]{"room_id"});
ps.setString(1, roomName);
ps.setString(2, "white");
return ps;
}, keyHolder);
return Objects.requireNonNull(keyHolder.getKey()).longValue();
}

public List<RoomResponseDto> showAllRooms() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

취향차이일 수도 있지만 일반적으론 find, select, update, insert와 같은 키워드를 많이 사용합니다 ^_^

List<RoomResponseDto> rooms;
String query = "SELECT * FROM room";
rooms = jdbcTemplate.query(
query, (rs, rowName) -> new RoomResponseDto(
rs.getLong("room_id"),
rs.getString("room_name"),
rs.getString("current_turn"))
);
return rooms;
}

public String showCurrentTurn(final Long roomId) {
String query = "SELECT current_turn FROM room WHERE room_id=?";
return jdbcTemplate.queryForObject(query, String.class, roomId);
}

public void changeTurn(final TurnChangeRequestDto turnChangeRequestDto) {
String query = "UPDATE room SET current_turn=? WHERE room_id=?";
jdbcTemplate.update(query, turnChangeRequestDto.getNextTurn(), turnChangeRequestDto.getRoomId());
}
}
66 changes: 0 additions & 66 deletions src/main/java/chess/dao/TurnDao.java

This file was deleted.

Loading