5. springboot ResponseEntity 적용
in Gitlog on springboot-restful
restful 방식으로 게시판으로 변경
개발 환경 및 내용
- OS: Window 10
- Dev Tool: Intellij - 2019.2.3
- JDK: 1.8(_221)
- JAVA: 8
- Framework: Springboot v2.1.8
- Build Tool: Gradle v3
- RDBMS: MariaDB
관련 URL
ResponseEntity 로 변경
Spring4 이상부터 @Controller와 @ResponseBody 을 합쳐놓은 @RestController를 지원하기애 기본적으로 ResponseBody로 리턴하고 있다. 그러면 ResponseEntity는? 일반적으는 하는 역할은 동일하다. 하지만 ResponseEntity로 리턴하는 경우는 본문정보와 헤더 정보, HTTP 상태코드를 좀 더 세밀하게 개발자가 처리하기 수월하면서 HATEOAS, builder패턴 등을 활용해서 개발하기 용이하다.
ResponseBody vs ResponseEntity<T>
@GetMapping(value = "/board/{id}") //@ResponseBody
public Board getBoard(@PathVariable int id) {
Board board = boardService.selectBoard(id);
return board;
}
@GetMapping(value = "/board/{id}")
ResponseEntity<Board> getBoard(@PathVariable int id) {
Board board = boardService.selectBoard(id);
return new ResponseEntity<Board>(board, HttpStatus.OK);
//return ResponseEntity.ok().body(board);
}
HATEOAS(Hypermedia As The Engine Of Application State)
HATEOAS는 독립된 시스템에서 클라이언트서버가 RESTful하게 디자인 된 API서버에 의해 동적으로 상호작용이 가능하다. 쉽게 말하면 클라이언트가 서버에 요청시 서버는 header에 POST, GET, PUT, DELETE 등 URI를 동적으로 설정하고 response를 한다.
그러면 클라이언트에서 서버에서 받은 URI로 적용해서 호출하다면, API서버에서 URI가 변경되어도 클라이언트는 호출URI를 변경할 필요가 없다. 또한 권한에 따른 URI를 제한을 할 수 있다. 그리고 클라이언트는 본문응답과 URI정보를 통해서 요청한 후에 해당 리소스에 대해 예측가능하게 한다.
왜 예측가능하게 설계를 하면. RESTful은 독립적인 진화이다. 독립된 시스템이기에 클라이언트와 API서버는 독립적으로 개발을 진행되기에 단순히 응답 값을 성공과 실패로 주면 파악하기 쉽지 않기 때문이다. 우선 hateoas 를 맛보기 위해서 hateoas dependency를 추가하고 실제로 POSTMAN으로 API 테스트해 보는게 와닿는다.
build.gradle
implementation 'org.springframework.boot:spring-boot-starter-hateoas'
@RestController
//등록
@PostMapping
public ResponseEntity boardInsert(@RequestBody Board board) throws Exception {
Integer idx = this.boardService.insertBoardSelectKey(board);
return ResponseEntity.created(linkTo(BoardApiController.class).slash(idx).toUri()).build();
}
POSTMAN Headers값
location: http://localhost:8080/v2/api/board/36
추후에 JPA 포스팅 할 때 HATEOAS와 Self-Descriptive를 적용하도록 해서 WEB API서버에서 좀 더 RESTful한 API로 갈 수 있게 포스팅하겠습니다.
우선 아래는 RESTful에 한단계 다가간 ResponseEntity과 HTTP 상태코드 활용에 포커스이다.
BoardApiController.java
@Slf4j
@RestController
@RequestMapping("/v2/api/board")
public class BoardApiController {
@Autowired
private BoardService boardService;
//목록
@GetMapping
public ResponseEntity<List<Board>> boardList(HttpServletRequest request, @ModelAttribute Board board) throws Exception {
List<Board> list = this.boardService.selectBoardList(request, board);
return ResponseEntity.ok().body(list);
}
//상세
@GetMapping("{boardIdx}")
public ResponseEntity<Board> boardDetail(HttpServletRequest request, @PathVariable(name="boardIdx", required=true) int boardIdx) throws Exception {
Board detail = this.boardService.selectBoard(request, boardIdx);
return ResponseEntity.ok().body(detail);
}
//등록
@PostMapping
public ResponseEntity boardInsert(@RequestBody Board board) throws Exception {
Integer idx = this.boardService.insertBoardSelectKey(board);
return ResponseEntity.created(linkTo(BoardApiController.class).slash(idx).toUri()).build();
}
//수정
@PutMapping("{boardIdx}")
public ResponseEntity<String> boardUpdate(@PathVariable(name="boardIdx", required=true) int boardIdx, @RequestBody Board board) throws Exception {
int cnt = this.boardService.selectBoardCnt(boardIdx);
if (cnt > 0) {
board.setBoardIdx(boardIdx);
this.boardService.updateBoard(board);
return new ResponseEntity<>(HttpStatus.OK);
} else {
Integer idx = this.boardService.insertBoardSelectKey(board);
return ResponseEntity.created(linkTo(BoardApiController.class).slash(idx).toUri()).build();
}
}
//삭제
@DeleteMapping("{boardIdx}")
public ResponseEntity<String> boardDelete(@PathVariable(name="boardIdx", required=true) int boardIdx) throws Exception {
int ret = this.boardService.deleteBoard(boardIdx);
if (ret > 0) {
return ResponseEntity.noContent().build();
} else {
return ResponseEntity.notFound().build();
}
}
}
이번 포스팅 끝.
[참고]
- https://en.wikipedia.org/wiki/HATEOAS
- https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/ResponseEntity.html