@Controller의 문제
Controller에서 유저로부터 요청을 받았을 때 String 값을 반환하면, 스프링 프레임웍은 해당 String에 매핑되는 리소스를 찾아 반환한다. 때문에 우리가 특정한 객체를 반환하게 될 경우 해당 객체를 특정 리소스에 매핑시키지 않으면, 리소스를 찾을 수 없기 때문에 404 Not Found 애러가 뜬다.
예를 들어 다음과 같은 코드를 살펴보자.
@Controller
class HomePageController {
@GetMapping("/blog/info")
fun getBlogInfo(): BlogInfo {
return BlogInfo("조세영의 Kotlin World", 3)
}
}
data class BlogInfo(val name: String, val year: Int)
이 코드에서는 /blog/info path로 리소스를 요청했을 때 BlogInfo 객체를 반환한다. 하지만, 이 /blog/info 로 HTTP Request를 날리면, 다음과 같은 오류가 나는 것을 볼 수 있다.
그 이유는 해당 BlogInfo 객체에 매핑된 리소스를 찾을 수 없기 때문이다. 하지만, 일반적으로 저런 형태의 Data class를 반환할 때, 우리가 원하는 것은 해당 객체를 JSON 형태로 반환하는 것이다. 여기서 @ResponseBody가 등장한다.
@ResponseBody 사용해 객체 반환하기
Controller 레벨에 @ResponseBody 어노테이션을 붙이면, 해당 컨트롤러에서 처리되는 모든 메서드에서 객체를 Json 형태로 반환할 수 있게 한다. 예를 들어 다음과 같이 Controller위에 ResponseBody를 붙여보자.
@ResponseBody
@Controller
class HomePageController {
@GetMapping("/blog/info")
fun getBlogInfo(): BlogInfo {
return BlogInfo("조세영의 Kotlin World", 3)
}
}
다시 애플리케이션을 실행한 후, http://localhost:8080/blog/info로 GET 요청을 날리면 다음과 같은 응답을 볼 수 있다. Content-Type이 application/json이고, 응답값은 BlogInfo 객체를 JSON 형태로 표현한 값이다.
Controller의 일부 메서드만 @ResponseBody로 처리하기
Controller의 일부 메서드만 위와 같은 형태로 처리하고, 나머지는 리소스를 반환하도록 만들고 싶으면, 함수 레벨에 @ResponseBody를 붙이면 된다. 예를 들어 /homepage 경로는 index.html 리소스를 반환하고 /blog/info 경로는 기존과 같이 객체를 JSON 형태로 만들어 응답을 하고 싶다면, 다음과 같이 getBlogInfo 위에만 @ResponseBody를 붙이면 된다.
@Controller
class HomePageController {
@ResponseBody
@GetMapping("/blog/info")
fun getBlogInfo(): BlogInfo {
return BlogInfo("조세영의 Kotlin World", 3)
}
@GetMapping("/homepage")
fun getHomePage(): String {
return "index.html"
}
}
그러면 /blog/info 경로의 요청은 그림3과 같이 application/json 형태의 응답을 반환하고, /homepage 경로의 요청은 그림4와 같이 text/html 형태의 응답을 반환하는 것을 볼 수 있다.
정리
- @ResponseBody 어노테이션을 컨트롤러 레벨에 붙이면 하위의 모든 함수가 @ResponseBody 가 붙은 것처럼 처리된다.
- @ResponseBody를 개별 함수에 붙임으로써 일부 함수만 객체를 JSON 형태의 응답으로 반환하도록 만들 수 있다.