@RestController는 Spring MVC에서 RESTful 웹 서비스를 개발하기 위해 사용하는 어노테이션입니다.
기존의 @Controller와 @ResponseBody의 조합을 대체하여, 더 간결하게 RESTful API를 개발할 수 있습니다.
| 특징 | @Controller | @RestController |
|---|---|---|
| 뷰 반환 여부 | 뷰 템플릿(JSP, Thymeleaf 등)을 반환. | 데이터(JSON/XML 등)를 반환. |
| 응답 본문 처리 | @ResponseBody와 함께 사용해야 응답 본문에 데이터 포함. | 메서드 반환 값이 기본적으로 HTTP 응답 본문에 포함. |
| 주요 사용 사례 | 웹 애플리케이션, 뷰 렌더링이 필요한 서비스. | RESTful API, 데이터 전송이 주 목적. |
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController // RESTful API를 위한 컨트롤러
@RequestMapping("/api")
public class HelloController {
// 단순 문자열 응답
@GetMapping("/hello")
public String sayHello() {
return "Hello, World!";
}
// JSON 객체 응답
@GetMapping("/user")
public User getUser() {
return new User(1, "홍길동", "hong@example.com");
}
}
GET /api/hello
Hello, World!
GET /api/user
{
"id": 1,
"name": "홍길동",
"email": "hong@example.com"
}
Spring Boot는 클라이언트의 Accept 헤더를 기반으로 JSON, XML, 텍스트 등 다양한 응답 포맷을 자동으로 결정합니다.
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ContentNegotiationController {
// 텍스트 응답
@GetMapping(value = "/text", produces = MediaType.TEXT_PLAIN_VALUE)
public String getText() {
return "This is plain text!";
}
// JSON 응답
@GetMapping(value = "/json", produces = MediaType.APPLICATION_JSON_VALUE)
public User getJson() {
return new User(1, "홍길동", "hong@example.com");
}
// XML 응답
@GetMapping(value = "/xml", produces = MediaType.APPLICATION_XML_VALUE)
public User getXml() {
return new User(2, "이몽룡", "lee@example.com");
}
}
/textThis is plain text!
/json{
"id": 1,
"name": "홍길동",
"email": "hong@example.com"
}
/xml<user>
<id>2</id>
<name>이몽룡</name>
<email>lee@example.com</email>
</user>
RESTful API에서는 적절한 HTTP 상태 코드를 설정하는 것이 중요합니다.
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.Optional;
@RestController
public class StatusCodeController {
// 사용자 데이터 예시
private final List<User> users = List.of(
new User(1, "홍길동", "hong@example.com"),
new User(2, "이몽룡", "lee@example.com")
);
// 사용자 조회 API
@GetMapping("/users/{id}")
public ResponseEntity<User> getUserById(@PathVariable int id) {
Optional<User> user = users.stream()
.filter(u -> u.getId() == id)
.findFirst();
return user.map(ResponseEntity::ok) // HTTP 200
.orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND).build()); // HTTP 404
}
}
/users/1 (성공):200 OK{
"id": 1,
"name": "홍길동",
"email": "hong@example.com"
}
/users/3 (실패):404 Not Foundimport org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<String> handleRuntimeException(RuntimeException ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("오류 발생: " + ex.getMessage());
}
}
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/users")
public class UserController {
private final List<User> users = new ArrayList<>();
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
users.add(user);
return ResponseEntity.status(HttpStatus.CREATED).body(user); // HTTP 201
}
}
{
"id": 3,
"name": "성춘향",
"email": "sung@example.com"
}
201 Created{
"id": 3,
"name": "성춘향",
"email": "sung@example.com"
}