jpa 를 사용하다가 ResponseEntity 클래스를 많이 사용하는데 왜 사용하는지 모르겠어서 공부를 하게 되었다.
일단 예시 코드를 먼저 살펴보자.
// 공지사항 조회(공지사항 번호로)
@GetMapping("/{noticeNo}")
public ResponseEntity<NoticeDto.Response> getNotice(@PathVariable Long noticeNo) {
return ResponseEntity.ok(noticeService.findNotice(noticeNo));
}
공지사항을 조회하는 메소드인데, 이런 간단한 CRUD 기능을 전부 RepsonseEntity클래스로 사용했다.
웹 개발 과정에서 우리는 다양한 HTTP 상태 코드를 마주하게 된다. 대표적인 예로 클라이언트 측 오류를 나타내는 404 (Not Found), 서버 측 오류를 의미하는 500 (Internal Server Error) 등이 있다. 이러한 오류 발생 시, 개발자는 코드를 직접 수정하여 문제 해결에 나서야 한다.
하지만 스프링 프레임워크의 ResponseEntity 클래스를 사용하면 이러한 HTTP 상태 코드를 개발자가 명시적으로 설정하여 응답을 정할 수 있다. RESTful API 를 구축할 때 서버는 클라이언트에서 완성된 뷰 대신 데이터(JSON, XML)을 반환해야 한다.(원칙임)
RESTful API의 각 요청은 성공 혹은 실패 여부, 그리고 요청한 데이터의 상태를 HTTP 상태 코드를 통해 명확하게 전달하는 것이 중요하다.
ResponsEntity는 이러한 RESTful API의 요구 사항을 해결해준다. 이제 ResponseEntity의 기능에 대해 알아보자.
1. 명확한 상태 코드 설정
- 각 API의 엔드포인트의 처리 결과에 따라 적절한 HTTP 상태 코드를 직접 지정할 수 있다.
- 성공적인 데이터 조회에는 200 OK, 새로운 리소스 생성 성공시에는 201 Created, 요청이 잘못되었을 경우에는 400 Bad Request 등
return ResponseEntity.ok(noticeService.findNotice(noticeNo));
@GetMapping("/{noticeNo}")
- 여기서 엔드포인트는 상단의 예시 코드에서 이 부분에 해당한다.
- 클라이언트가 서버와 통신하기 위해 접근하는 URL 주소를 의미한다.
2. 응답 본문(Body) 설정
- 클라이언트에게 전송할 실제 데이터를 설정할 수 있다.
- ResoponseEntity 제네릭 타입에 맞춰서 리턴하면 된다.
//공지사항 등록
@PostMapping
public ResponseEntity<String> addNotice(@RequestBody NoticeDto.Create noticeDto) {
Long noticeNo = noticeService.createNotice(noticeDto);
System.out.println("반환된 noticeNo: " + noticeNo);
return ResponseEntity.ok(noticeNo.toString());
}
제네릭 타입이 String 이기 때문에 실제 반환 값인 Long 타입의 noticeNo 객체를 toString 메소드로 문자열로 변환 시켜 return 시켰다.
3. HTTP 헤더 정보 설정
- 응답에 필요한 HTTP 헤더(콘텐트 타입 등)를 직접 설정할 수 있다.
@PostMapping("/items")
public ResponseEntity<Item> createItem(@RequestBody Item newItem) {
// 아이템 저장 로직 (가정)
Item savedItem = saveItem(newItem);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(URI.create("/items/" + savedItem.getId())); // Location 헤더 설정 (새로운 리소스의 URI)
headers.setContentType(MediaType.APPLICATION_JSON); // Content-Type 헤더 설정
return new ResponseEntity<>(savedItem, headers, HttpStatus.CREATED); // 201 Created와 함께 헤더 및 본문 반환
}
- 반환할 때, 위의 예시 코드를 보면 알 수 있듯이 직접 지정해줄 수 있다.
4. 다양한 편의 메소드 제공 (사실상 이게 제일 좋은듯)
- ResponseEntity.ok(body): 상태 코드 200 (OK)와 함께 본문 설정
- ResponseEntity.created(location): 상태 코드 201 (Created)와 함께 Location 헤더 설정
- ResponseEntity.notFound(): 상태 코드 404 (Not Found) 설정
- ResponseEntity.badRequest(): 상태 코드 400 (Bad Request) 설정
- ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorMessage): 특정 상태 코드와 함께 본문 설정
특징
1. 불변성 : ResponseEntity 객체는 한번 생성되면 내부 상태를 변경할 수 없는 불변 객체이다.
2. 제네릭 타입 지원 : 위에 적어놓은 것 처럼 제네릭 타입을 사용하여 응답 본문의 데이터 타입을 명시할 수 있어 타입 안전성을 높인다.
3. 유연성 : 상태코드, 헤더, 본문을 조합하여 다양한 형태의 HTTP 응답을 생성할 수 있어 웹 API 개발의 유연성을 높인다.
4. RESTful API 설계 지원 : HTTP 상태 코드를 의미론적으로 정확하게 사용하여 RESTful APU 설계를 용이하게 한다.
ResponseEntity 클래스는 주로 MVC 패턴 중 Controller 에서 사용되어 HTTP 응답을 생성하고 관리한다.
컨트롤러에서 웹 요청을 받아 처리한 후 그 결과를 클라이언트에게 다시 응답하는 역할을 담당하는데,
이때 ResponseEntity의 응답 상태 코드, 헤더, 본문 등을 세밀하게 제어할 수 있기 때문이다.
package com.kh.jpa.controller;
import com.kh.jpa.dto.NoticeDto;
import com.kh.jpa.service.NoticeService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/notice")
@RequiredArgsConstructor
public class NoticeController {
private final NoticeService noticeService;
//공지사항 등록
@PostMapping
public ResponseEntity<String> addNotice(@RequestBody NoticeDto.Create noticeDto) {
Long noticeNo = noticeService.createNotice(noticeDto);
System.out.println("반환된 noticeNo: " + noticeNo);
return ResponseEntity.ok(noticeNo.toString());
}
// 공지사항 조회(공지사항 번호로)
@GetMapping("/{noticeNo}")
public ResponseEntity<NoticeDto.Response> getNotice(@PathVariable Long noticeNo) {
return ResponseEntity.ok(noticeService.findNotice(noticeNo));
}
// 공지사항 수정(공지사항 번호로)
@PutMapping("/{noticeNo}")
public ResponseEntity<NoticeDto.Response> updateNotice(
@PathVariable Long noticeNo,
@RequestBody NoticeDto.Update updateDto){
return ResponseEntity.ok(noticeService.updateNotice(noticeNo, updateDto));
}
// 공지사항 삭제(공지사항 번호로)
@DeleteMapping("/{noticeNo}")
public ResponseEntity<Void> deleteNotice(@PathVariable Long noticeNo) {
noticeService.deleteNotice(noticeNo);
return ResponseEntity.ok().build();
}
}
저번주 과제였는데, 컨트롤러에 전부 ResponseEntity 클래스를 사용했다.
'Spring' 카테고리의 다른 글
| [Java] Dependency Injection에 대해서, 그리고 왜 사용할까? (0) | 2025.05.21 |
|---|---|
| [Spring] Spring 프레임워크란 무엇일까? (2) | 2025.05.20 |
| [JPA] JPA 에 대해 (0) | 2025.05.13 |
| [Spring] Spring 프레임워크에서 자주 사용되는 인터페이스, 어노테이션 정리 (0) | 2025.05.13 |
| [Java] 어노테이션은 무엇일까? (1) | 2025.04.28 |