프로젝트 시간의 반정도를 잡아먹은 controller 구현 및 테스트 입니다.
여태까지는 spring 프로젝트에 html 템플릿을 담고서 controller에서 해당 템플릿으로 데이터를 넘겨주는 형식으로만 프로젝트를 만들어봤기에 http 통신을 spring 으로 제대로 해본건 처음이였습니다.
사실 지금도 각 어노테이션에 대해 완벽하게 이해하고 있지는 않고 느낌적으로 쓰는것이기에 추후에 update 기능을 추가하면서 시간을 들여 여러가지 시도하면서 학습할 계획입니다.
// controller
controller는 원래 계획대로라면 node.js 의 html 페이지와 통신을 해야하지만, node.js 코드를 다시 읽고 고치려니 꽤 시간이 많이 잡아먹힐 것 같아서 일단 postman 으로 통신을 테스트 하였습니다.
UserController
//@Controller
@RestController // json 형식의 응답
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@PostMapping("/user/new")
public ResponseEntity<Object> newUser(
@RequestBody @Valid UserForm userForm) {
try {
User user = new User(userForm.getEmail(),
userForm.getPassword(),
userForm.getNickname(),
userForm.getQuestion(),
userForm.getAnswer());
Long newUserId = userService.join(user);
URI uri = URI.create("/user/" + newUserId); // 확인차 작성한것, 아마 "/"로 쓸듯
return ResponseEntity.created(uri).build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.CONFLICT).build();
}
}
// 로그인 미완성
@PostMapping("/user/login")
public ResponseEntity<Object> login(@RequestBody @Valid UserForm userForm) {
HttpHeaders headers = new HttpHeaders();
try {
User login = userService.Login(userForm.getEmail(), userForm.getPassword());
System.out.println("login success");
return ResponseEntity.status(HttpStatus.OK).build(); // 세션 생성 필요
} catch (Exception e) {
System.out.println("e = " + e);
return new ResponseEntity<>(e.getMessage(), headers, HttpStatus.CONFLICT);
}
}
}
post형식으로 계정생성과 로그인 기능을 만들었습니다.
패스워드는 프론트에서 암호화해서 보낸다는 상황을 가정했습니다.
로그인 기능을 만들다가 생각난건데, node.js에서 세션기능을 외부 모듈을 끌어와서 제작했었다는 걸 뒤늦게 눈치챘습니다. 아직 제가 완벽히 수행하기에는 이른 프로젝트 였던것 같습니다.
뭐 어쩌겠습니까. 구현한 것만이라도 제대로 작동되는지 확인해봐야지.
계정생성 기능 성공.
-----
-----
순서대로 각각 로그인 성공, email 조회불가, password 불일치 테스트입니다.
아마 exception 메세지도 저처럼 string 타입을 그대로 보내는 형식이 아니라 json 으로 가공해서 보내는게 맞는 방법일텐데 일단은 원하는 결과값을 받은것에 만족합니다.
CommentController
순서대로라면 BoardController가 맞겠지만 BoardController 부분에서 언급할 것이 많고 그러기 위해서는 CommentController 부분이 먼저 언급되어야 하기에 앞에 두었습니다.
무엇보다 CommentController는 별거없습니다.
@RestController
@RequiredArgsConstructor
public class CommentController {
private final CommentService commentService;
@PostMapping("/board/{boardId}/new-comment")
public ResponseEntity<Object> newComment(
@RequestBody @Valid CommentForm commentForm,
@PathVariable("boardId") Long boardId) {
commentService.create(commentForm.getContent(), commentForm.getUserId(), boardId);
URI uri = URI.create("/board/" + boardId);
return ResponseEntity.created(uri).build();
}
}
별거 없습니다. 앞서 계속 언급했던 board와의 양방향 연관관계 덕분에 따로 서치하는 작업을 넣을 필요가 없었습니다.
원하는 결과값을 잘 받아낼 수 있었습니다. (여기까진 쉬웠지.)
BoardController
대망의 BoardController 입니다. 여기서 버그가 터져서 무려 3시간 가까이 잡아먹힌....
버그는 끝에 언급드리고 일단은 코드와 테스트 결과부터.
@RestController
@RequiredArgsConstructor
public class BoardController {
private final BoardService boardService;
@PostMapping("/board/new")
public ResponseEntity<Object> newBoard(
@RequestBody @Valid BoardForm boardForm) {
Board board = new Board(
null,
boardForm.getTitle(),
boardForm.getContent());
Long boardId = boardService.create(board, boardForm.getUserId());
URI uri = URI.create("/board/" + boardId);
return ResponseEntity.created(uri).build();
}
@GetMapping("/board/{boardId}")
public BoardForm getBoard(@PathVariable("boardId") String pathVariable) {
Long boardId = Long.parseLong(pathVariable);
return boardService.findOne(boardId).toBoardForm(true);
}
@GetMapping("/board")
public List<BoardForm> getPage(
@RequestParam(name = "page", defaultValue = "1") int page) {
return boardService.getListFromPage(page).stream()
.map(board -> board.toBoardForm(false))
.collect(Collectors.toList());
}
}
기능은 각각 게시글 작성, 게시글 확인, 최근 게시글 리스트로 가져오기 (페이지 탐색) 이 있습니다.
-----
-----
위부터 각각 게시글 작성, 게시글 및 해당 게시글의 댓글 가져오기, 최근 게시글 탐색 이며 제가 원하는 결과값을 (기여코) 받아낼 수 있었습니다....
오류
오류는 게시글 생성, 댓글 생성 이후 게시글 탐색에서 발생했습니다. postman이 값을 받아오지 못하고 IDA의 콘솔창은 미친듯이 올라가다 멈췄습니다.
오류 내용을 검색해봐도 원하는 결과를 얻지 못해 시간이 오래 걸렸습니다.
게시글 리스트 탐색에서는 오류가 안났고, 오로지 게시글 및 댓글을 가져오는 기능에서만 났기에 댓글이 문제인 것 같아 comment 엔티티를 중심으로 이것저것 해보고 마침내 원인을 찾아낼 수 있었습니다.
오류의 원인은 board 와 comment 간의 양방향 연관관계로 서로의 객체를 들고있었기 때문입니다.
정확히 말하자면 해당 부분이 문제가 된다기보단 서로 의존하고 있는 관계를 가진 객체를 JSON 형식으로 보내려고 한 행위가 문제였습니다.
객체를 자동으로 JSON으로 만들어주는 과정에서 board가 들고있는 comment를 JSON으로 매핑하는데 그 과정에서 comment 가 들고있는 board를 매핑하는... 무한반복.
board에서 comment 리스트를 연관관계로 가져온 후 form으로 바꾸기 귀찮아서 그대로 쓰려고 한 저의 게으른 생각때문에 벌어진 일이였습니다. 덕분에 하나 배웠습니다만.
그렇습니다. entity 설계에서 언급한 최종코드에서의 toForm 매서드는 약 3시간을 뺑이치다가 만들어진 결과물입니다.
지름길로 가려다가 빙 돌아서 DTO의 중요성만 깨닫고 가네요.
// 계획 (사족)
미완성이니만큼 기능구현도 해야겠지만, 만들면서도 여러가지 리팩토링 아이디어가 떠올랐습니다.
생성자를 정적 팩토리 메서드로 변경, db를 mysql로 변경, 인터페이스를 의존하게끔 수정, db저장방식에 시퀀스 사용 등등.
일단 node.js 로 만든 프론트 서버와 통신이 처음 목표지만 자바스크립트를 몇달동안 안봐서 제가만든 코드 읽는것도 힘든데 프론트 서버에 맞게 어느정도 수정도 해줘야하니 막막합니다.
무엇보다 코드스테이츠 부트캠프 진행중이라 시간이 없는것도 한몫하네요. 메인프로젝트 진행기간 전까지 목표로 잡은 강의들이 많이 남았고. js만질 시간이 있을지....
어쨋든 단 이틀이지만, 오랜만에 토이프로젝트 하면서 열정을 확인한 것 같아서 좋았습니다. 이 기세로 열심히 해야겠네요.
'프로젝트' 카테고리의 다른 글
토이프로젝트 / NodeToSpring - 페이징 기능 개선 (SqlResultSetMapping ) (0) | 2022.12.25 |
---|---|
토이프로젝트 - NodeToSpring 4. 리팩토링 약간... (0) | 2022.12.13 |
토이프로젝트 - NodeToSpring 2. repository / service (C, R) (0) | 2022.12.04 |
토이프로젝트 - NodeToSpring 1. entity 설계 (0) | 2022.12.04 |
spring - 댓글 기능 (0) | 2022.10.07 |