-
Notifications
You must be signed in to change notification settings - Fork 178
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단계, 추가미션] 에어(김준서) 미션 제출합니다. #298
Conversation
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.
안녕하세요 에어 몇가지 피드백과 질문에 대한 답변 남겨들요.
에어도 말씀하신 것처럼 패스워드를 쿠키에 저장하는 방식은 보안상 매우 취약해보여요
쿠키와 세션에 차이를 학습하고 세션을 적용해보는건 어떨까요?
Q1.
h2, 혹은 사용하시는 database 에서 user 를 예약어로 사용하는 것 같아요
user
와 같이 사용 할 순 있지만, 최대한 예약어는 사용하지 않는 것이 좋을 것 같아요.
Q2.
개인적으로 service 에서 repository로 넘길대는 domain 을 이용하는 편입니다.
Q3.
존재하지 않는 유저가 왜 필요한지 잘 모르겠어요. NULL 이나 User 의 ID 가 0, -1 등으로도 표현 할 수 있을 것 같아요.
model.addAttribute("state", | ||
new GameDTO(id, userService.participatedUsers(id), "새로운게임", true)); | ||
return "chess"; | ||
@PostMapping(path = "/rooms/new-game") |
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.
POST 자체가 new 의 의미를 가지므로
POST /rooms 로도 충분히 의미를 전달 할 수 있을 것 같아요.
@PostMapping("/rooms/{id}/users/blackuser/re-enter") | ||
public String blackUserReEntry(@PathVariable final String id, @ModelAttribute final PasswordDTO passwordDTO, | ||
final HttpServletResponse response) { | ||
UserDTO blackUser = roomService.findBlackUserById(id); | ||
|
||
if (!UNKNOWN_USER.equals(blackUser)) { | ||
userService.checkPassword(Integer.toString(blackUser.getId()), passwordDTO.getPassword()); | ||
playerCookie(response, blackUser.getNickname(), passwordDTO.getPassword(), "black"); | ||
return "redirect:/rooms/" + id; | ||
} | ||
return "redirect:/"; | ||
} | ||
|
||
@PostMapping("/rooms/{id}/users/whiteuser/re-enter") | ||
public String whiteUserReEntry(@PathVariable final String id, @ModelAttribute final PasswordDTO passwordDTO, | ||
final HttpServletResponse response) { | ||
UserDTO whiteUser = roomService.findWhiteUserById(id); | ||
|
||
if (!UNKNOWN_USER.equals(whiteUser)) { | ||
userService.checkPassword(Integer.toString(whiteUser.getId()), passwordDTO.getPassword()); | ||
playerCookie(response, whiteUser.getNickname(), passwordDTO.getPassword(), "white"); | ||
return "redirect:/rooms/" + id; | ||
} | ||
return "redirect:/"; | ||
} |
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.
두 메소드는 거의 동일해보이는데 분리할 필요가 있을까요?
"/rooms/{id}/users/{color}/re-enter"
는 어떤가요?
roomService.addNewRoom(id); | ||
historyService.initializeByRoomId(id); | ||
@GetMapping("/rooms/{id}") | ||
public String enterRoom(@PathVariable final String id, final Model model) { |
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.
메소드 이름과 URI 간에 의미가 다른것 같아요.
int whiteUserId = userService.registerUser(new JoinUserDTO(roomCreateDTO)); | ||
Long roomId = roomService.createRoom(roomCreateDTO.getName(), whiteUserId); | ||
roomService.addNewRoom(roomId); | ||
playerCookie(response, roomCreateDTO.getNickname(), roomCreateDTO.getPassword(), "white"); |
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.
이해하신대로 패스워드를 저장하는 방식은 좋지 않아보이네요.
쿠키 말고 세션을 이용해보는건 어떤가요 ?
src/main/java/chess/dao/UserDAO.java
Outdated
List<UserDTO> users = jdbcTemplate.query("SELECT * FROM player WHERE nickname = ?", | ||
(rs, rowNum) -> new UserDTO(rs.getInt("id"), rs.getString("nickname")), | ||
nickname); | ||
return users.stream().findAny(); |
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.
EmptyResultDataAccessException 를 사용하는 경우랑 위 경우랑은 어떤 차이가 있나요?
src/main/java/chess/dao/UserDAO.java
Outdated
@@ -92,4 +99,58 @@ public String findUserByRoomId(final String query, final String roomId) { | |||
throw new InitialSettingDataException(); | |||
} | |||
} | |||
|
|||
public Optional<UserDTO> findByPlayerIdAndPassword(final String playerId, final String password) { |
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.
persistance 영역에서도 DTO 를 사용한다면 domain(entity) 은 어디서 사용될까요 ?
if (status == 1) { | ||
return "진행중"; | ||
} | ||
if (status == 2) { | ||
return "준비중"; | ||
} | ||
return "종료됨"; | ||
} |
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.
enum 으로 관리하는건 어떤가요?
피드백 적용했습니다! 쿠키대신 세션을 적용해봤어요. 사용법은 쿠키를 사용할 때랑 크게 다를게 없는 것 같은데, 아이디나 패스워드 정보를 한 번 암호화? 하는 느낌인 것 같아요. 또 쿠키와 달리 정보가 서버에 저장된다고 하네요! Q. DAO에서 엔티티를 사용하도록 코드를 바꿔보면서 궁금증이 생겼어요. 서로 다른 테이블을 join해서 결과를 얻어내는 경우 테이블과 1:1 매칭되는 엔티티가 존재하지 않는데, 이 경우는 어떻게 값을 받아야하나 고민이 됐어요. 현재는 join을 사용하지 않고, DAO별로 쿼리를 나눠서 각 쿼리를 엔티티로 받은 다음 service단에서 DTO로 조합하는 식으로 변경했어요. |
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.
어제 머지를 했다고 생각했는데.. 제가 놓쳤네요 죄송합니다.
질문하신 내용에 답변으로 이번 미션은 마무리 하도록 할께요.
좋은 개발자로 성장하는데 조금이나마 도움이 되기를 바랍니다.
저와의 미션은 종료되었지만, 궁금한점이나 어려운점 있으면 편하게 DM 주세요.
다음 미션도 응원하겠습니다.
감사합니다. 🙇
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
import javax.servlet.http.HttpSession; | ||
|
||
@Controller | ||
public final class SpringChessGameController { |
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.
질문하신 내용에 대해서는 여러가지 방법이 있는것 같아요.
- JOIN 의 결과를 담는 객체를 만든다.
- 한쪽 객체에 조인하는 객체의 정보를 포함한다.
- 각각 조회해서 객체의 관계를 맺어준다.
각각의 쓰임새가 조금씩 달라서 어떤게 좋다 말씀드리긴 어렵고, 필요에 따라 잘 사용해야 겠지요 😱
제가 생각하는 DTO 랑 도메인의 궁극적인 차이점은 비지니스 로직의 존재라고 생각해요. 따라서 둘을 합쳐서 만든 데이터 셋이 비지니스 로직을 가지지 않는다면 에어가 말씀하신대로 DTO 라고 할 수 있겠죠.
조인은 말그대로 두 테이블을 함께 조회할 필요가 있을때 사용하는데, 요새는 조인하지 않고 각각 가져오는 경우도 많은 것 같아요.
단 1:1 이 아니라 1: N 의 경우 각각 가져오면 부하가 심하겠죠?
안녕하세요 미립!
3단계 기능은 이전 피드백 받을 때도 구현되어있어서 추가미션 구현하고 제출합니다!
이 요구사항을 보고 쿠키를 써보라는 것으로 해석하고 구현해봤어요.
쿠키를 암호화? 해서 써야한다고 본 것 같은데 검색해보니 Spring Security를 사용하던데 이 부분은 잘 모르겠어서 일단 암호화는 하지 않았습니다!(너무 노출되있는것같아서 찝찝하긴 하네요.)
쿠키를 처음 적응해봐서 맞게 한지도 잘 모르겠네요ㅠㅠ
이번 미션은 아래와 같은 흐름으로 진행했어요
궁금증
Q. 자동 회원가입시 SimpleJdbcTemplate을 사용해서 user 테이블에 추가하려고하니
Unknown column ‘user_id’ in ‘field list’
라는 에러가 발생했어요. 그래서 user 테이블명을 player나 users 등 다른 이름의 테이블로 바꿔보니까 잘 되더라고요.. 테이블 명이 user인 경우만 발생하는 것 같은데 찾아봐도 잘 안나오더라구요. 1, 2단계 때 그냥 insert문으로 user테이블에 추가했을 땐 이런문제 없었어서 더 헷갈리네요.. 원인이 뭘까요??😭Q. 크루들과 이야기하다가 계층간 데이터 이동은 새로운 DTO를 만들어줘서 해야한다는 이야기를 들었어요. 하나의 DTO로 계속 이동시킬 경우 연결 통로가 될 수 있다고 하던데, 미립도 각 계층 이동시마다 매번 새로운 DTO를 사용해서 데이터를 감싸주나요??
Q. 존재하지 않는 유저를 표현하기 위해 UNKNOWN USER라는 UserDTO를 만들었어요. 현재는 어디에 둬야할지 모르겠어서
UserDAO
에 뒀는데, DB에 저장해놓는 것이 좋을까요??피드백 잘 부탁드립니다!!🙏