아직 스프링 부트 초심자라 제가 학습한 내용을 올리는 것입니다. 기록을 남기기 위해 포스팅했습니다.
✅학습목표
**Spring Boot로 Hello API 만들어 보기**
1. @RestController와 @GetMapping을 사용한다.
2. @Controller, @ResponseBody
1. @RestController 가 뭘까?
클래스가 HTTP 요청을 처리해서 JSON이나 문자열을 반환한다는 뜻이다.
@RestController 어노테이션이 붙어진 클래스는 클라이언트에서 요청이 들어오면 응답을 줄 준비가 되어 있다는 뜻이다.
@RestController는 @Controller와 @ResponseBody의 조합이다.
@RestController는 화면(html)을 렌더링 하지 않고 데이터를 바로 브라우저나 클라이언트로 보내준다.
우선 RestController로 API를 구현해 보자.
package hello.myspring;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController //@Controller+ @ResponseBody의 조합
public class RestControllerTest {
@GetMapping("/testA")
public String hello() {
return "클라이언트, 브라우저에 문자열을 보냅니다.!";
}
}
2. @GetMapping
HTTP GET 요청을 처리하는 메서드에 붙이는 어노테이션이다.
HTTP에는 여러 요청 방식이 있는데 그중 GET은 브라우저 주소창으로 요청하는 기본적인 방식이다.
그래서 결론은 @GetMapping의 핵심은 HTTP GET 요청 처리하며 위치는 메서드 위에 붙인다. 주된 사용은 페이지 조회, 간단한 데이터 요청 등이다.
3. 아래 코드는 @RestController가 아닌 @Controller와 @ResponseBody로 클라이언트에게 문자열을 넘겨주는 코드이다.
package hello.myspring;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class BasicController {
@ResponseBody
@GetMapping("/basic")
public String method() {
return "클라이언트, 브라우저에 문자열을 보냅니다.";
}
}
4. @ResponseBody
HTTP 응답 본문에 직접 데이터를 쓰겠다는 역할을 지닌다.
view를 찾지 않고, 문자열이나 JSON 등 데이터를 그대로 브라우저에 전송한다.
@ResponseBody 메서드의 리턴값은 HTTP 응답 본문에 직접 넣어주는 어노테이션이다.
( View (html) 렌더링 하지 않고, 문자 그대로 (또는 JSON으로) 응답한다. )
만약 저 위의 코드에서 @ResponseBody를 지우면 어떻게 될까?
package hello.myspring;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class BasicController {
//@ResponseBody
@GetMapping("/basic")
public String method() {
return "클라이언트, 브라우저에 문자열을 보냅니다.";
}
}
스프링을 실행시키고 똑같이 url에 "localhost:8080/basic"을 입력하면,
There was an unexpected error (type=Internal Server Error, status=500). 화면이 안 나온다.
그 이유는 @Controller는 return "문자열"을 HTML 파일 이름으로 인식한다. 저 코드에서 return 된 값은 "클라이언트, 브라우저에 문자열 보냅니다." resources/templates/클라이언트, 브라우저에 문자열을 보냅니다. html 같은 파일은 당연히 없다.
다시 말해 Controller는 기본적으로 문자열을 리턴하면 그 문자열을 View 이름으로 인식한다.
View 인식을 막고 클라이언트에게 문자열, JSON 그대로 응답하기 위해서는 @ResponseBody를 사용해야 한다.
@ResponseBody 안 쓰고 View렌더링 과정 (Model과 Thymeleaf 사용)
package hello.myspring.repository;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class SayController {
@GetMapping("say-hi")
public String say(Model model){
model.addAttribute("show","환영해여!!!");
return "say-hi";
}
}
resources/templates/say-hi.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http:///www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>say-hi html 파일</h1>
<div th:text="${show}"></div>
</body>
</html>
@Controller
@Controller는 Spring MVC의 Controller로 등록한다.
브라우저에서 요청이 오면, 해당 요청을 처리하고 HTML View를 반환하는 역할이다.
@Controller는 웹 요청을 받아 뷰를 반환하는 역할을 하는 어노테이션이다.
Spring MVC 동작 흐름
1. 브라우저 GET 요청 (/home)
2. HomeController의 home() 실행
3. "home" 문자열 반환
4. resource/templates/home.html 렌더링
5. HTML 페이지 브라우저에 응답
@RestController vs (@Controller, @ResponseBody)
항목 | @Controller | @RestController |
목적 | 화면(HTML) 보여준다. | 데이터(JSON 등) 응답 |
리턴값 | View 이름(파일명) | 문자열/객체 |
어노테이션 포함 여부 | X | @Controller + @ResponseBody 포함 |
사용 예 | 웹 페이지 | API 서버 |
<더 세밀한 차이점>
구분 | @RestController | @Controller+@ResponseBody |
선언위치 | 클래스 위 | @Controller는 클래스 위, @ResponseBody는 메서드 위 |
사용 목적 | REST API 전용 | HTML, 필요 시 API |
코드 간결성 | 간결함 | 메서드마다 @ResponseBody를 붙여야 함 |
유지보수 | API 중심이라 명확 | 뷰/데이터 섞이면 헷갈릴 수 있음 |
뷰 반환 | 불가 | 가능 |
@Controller + @ResponseBody를 사용해 @RestController와 비슷한 수행을 할 수 있다.
JSON 응답 예제
package hello.myspring;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class Ex {
@GetMapping("example")
@ResponseBody
public User main() {
User user = new User("홍길동", 33);
return user;
}
static class User {
private final String name;
private int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
}
{"name":"홍길동","age":33}