이젠 나머지 기능들을 넣어보자 먼저 수정을 담당하는 PATCH 기능과 예외 처리를 보자.
Dto 볼까
@Getter @Setter
public class BoardPatchDto {
@NotEmpty
private String title;
@NotEmpty
private String content;
}
POST와 구성요서가 당연히 같다. 제목 수정하고 내용 수정할꺼니깐
public Long updateBoard(BoardPatchDto boardPatchDto, Long boardId) {
Board board = findBoardId(boardId);
board.setTitle(boardPatchDto.getTitle());
board.setContent(boardPatchDto.getContent());
return boardRepository.save(board).getBoardId();
}
Service 부분이다. POST와 다른걸 살펴보면 매개변수 두개를 받는다 (BoardPatchDto boardPatchDto, Long boardId)
그 이유는 PATCH는 POST와는 다르게 누군지를 알아야 하기에 ID를 찾아줘야 하는데
Board board = findBoardId(boardId); 여길보면 findBoardId를 호출하는게 보이는데 Service에 메서드를 새로 추가 하였다.
public Board findBoardId(Long boardId) {
return boardRepository.findById(boardId)
.orElseThrow(()->new BusinessLogicException(ExceptionCode.BOARD_NOT_FOUND));
}
boardRepository.findById 여기를 보면 findById 메서드의 역할을 짐작할수 있다. Repository에서 Id를 쏙쏙 찾아오는 녀석이다.
그리고 매개변수 boardId에 저장하고 Board로 다시 return 하는데
예외 처리를 해주었다.
.orElseThrow(()->new BusinessLogicException(ExceptionCode.BOARD_NOT_FOUND));
즉, 값이 없으면 예외로 던지고 람다식을 사용해서 BusinessLogicException을 호출하였다. 내가 예외 코드를 어떻게 만들었나 살펴보자.
public class BusinessLogicException extends RuntimeException{
@Getter
private ExceptionCode exceptionCode;
public BusinessLogicException(ExceptionCode exceptionCode) {
super(exceptionCode.getMessage());
this.exceptionCode = exceptionCode;
}
}
public enum ExceptionCode {
BOARD_NOT_FOUND(400, "board not found");
@Getter
private int status;
@Getter
private String message;
ExceptionCode(int status, String message) {
this.status = status;
this.message = message;
}
}
두개의 코드가 있는데 먼저 첫번째 코드를 설명하면
RuntimeException을 상속받는것으로 보여진다 RuntimeException은 서버 실행중에 터지는 코드들을 로그로 보여주는 기능을 가지고 있는데 super로 RuntimeException 의 생성자를 끌고와서 exceptionCode.getMessage()를 집어 넣는거다.
그러면 RuntimeException에는 exceptionCode.getMessage()가 들어가서 로그에 찍히게 된다 바로 아래처럼 말이다. (boardId 없는걸 요청해 봤음)

그리고 this 부분은 지도 생성자로 호출되서 팔려가야 하니깐 넣어준거고. 간단한 코드이다.
다음으로는 두번째 코드 설명하면 enum이 고정값인건 다들 알것이다. BOARD_NOT_FOUND(400, "board not found"); 처럼 필요한 오류값들을 추가해서 넣어주면서 관리하면 된다. 앞에서 언급했듯 너무 당연한 기초와 중복 설명은 피하겠다.
이러면 예외 처리가 동작하는것이다. Exception 이랑 Service의 설명은 끝났으니 다시 PATCH로 가서 Controller를 살펴보자.
@PatchMapping("/{boardId}")
public ResponseEntity patchBoard(@PathVariable("boardId")Long boardId,
@RequestBody @Validated BoardPatchDto boardPatchDto) {
boardService.updateBoard(boardPatchDto, boardId);
return ResponseEntity.status(HttpStatus.OK).body(boardId);
}
이번에도 POST와 뭔가 다르다.
추가된건 아래 두 부분이다.
@PatchMapping("/{boardId}")
@PathVariable("boardId")Long boardId
어렵게 생각할것 없다
@PathVariable("boardId")Long boardId 를 보자. @PathVariable는 외부에서 값을 받아 오는데 그걸 ("boardId") 에다 저장한다. 언급했듯 작명 센스는 상관없지만 알아보기 쉬운걸로 하는게 좋다 나 같은 초보들은 매개변수가 무슨 기능이 있는줄 알고 겁먹는데 ("boardId") 가 아니라 ("bodngnkdgndgndgkardId") 이렇게 해도 정상 작동한다. 물론.
@PatchMapping("/{boardId}") 이거랑 같이 맞춰 줘야 한다. 왜냐하면 여기서 {} 부분을 인식하기 때문이다. 요청을 어떻게 보내는지 POSTMAN 으로 보여주겠다.

localhost:8080/api/boards/1 여기서 숫자 1이 보이는가? 그리고 나는 PATCH를 선택해서 SEND 버튼을 눌렀다.
즉, @PatchMapping 은 PATCH 요청을 받아들이는 녀석이고 매개변수를 ("/{boardId}") 이걸로 설정해서 / 앞에 있는 값을 인식하는 녀석이다.
그걸 @PathVariable("boardId") 한테 던지고 @PathVariable 는 괄호 안의 값을 비교해서 맞는걸 가져오는거다 POSTMAN의 예를 들면 숫자 1이 되는거고 그래서 숫자 1을 가져와서 옆에 Long boardId 한테 던지는거다.
규칙이다. Long boardId 를 딴대로 옮기면 바로 컴파일 에러가 발작을 한다. 외워라.
어떤가 매우 쉽지 않은가? 삭제도 빠르가 봐보자.
public void deleteBoard(Long boardId) {
findBoardId(boardId);
boardRepository.deleteById(boardId);
}
Delete Service 부분이다. 이젠 보기만 해도 딱 반응이 올꺼라 믿는다 그런데 왜 리턴 타입이 void 일까?
왜냐하면 삭제하면 그만이기 때문이다 뭐 값을 돌려줄 필요가 있겠는가? 삭제해서 날렸는데.
바로 Controller 가보자.
@DeleteMapping("/{boardId}")
public ResponseEntity deleteBoard(@PathVariable("boardId") Long boardId) {
boardService.deleteBoard(boardId);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
삭제 기능이다. 삭제는 뭐가 달라졌을까 당연히 삭제가 목적이지 Dto는 안쓸꺼고. 그리고 삭제가 목적이니 표시할 데이터도 없다 그래서 .build() 로 마무리를 한거다.
다음으로는 GET을 살펴보자.
'스프링boot > 정리' 카테고리의 다른 글
Spring MVC) 사용자를 만들어 보자 1 (0) | 2023.04.18 |
---|---|
Spring MVC) 댓글을 만들어 보자 (1) | 2023.04.09 |
Spring MVC) 게시판을 만들어 보자 4 (0) | 2023.04.07 |
Spring MVC) 게시판을 만들어 보자 2 (1) | 2023.04.05 |
Spring MVC) 게시판을 만들어 보자 1 (1) | 2023.04.05 |