[ Spring ]/SpringMVC 1편
[Spring] HTTP 응답을 보내는 방법 (정적 리소스 / 뷰 템플릿 / HTTP 메시지 )
쿠릉쿠릉 쾅쾅
2022. 2. 26. 15:29
728x90
HTTP 응답
- 서버에서 응답 데이터를 만드는 방법은 3가지다.
- 정적 리소스
- 예) 웹 브라우저에 정적인 HTML, css, js를 제공할 때 정적 리소스를 사용한다.
- 뷰 템플릿
- 예) 웹 브라우저에 동적인 HTML을 제공할 때 뷰 템플릿을 사용한다.
- HTTP 메시지
- HTTP API를 제공하는 경우에는 HTML이 아니라 데이터를 전달해야 하므로, HTTP 메시지 바디에 데이터를 JSON 형식으로 보낸다.
- 정적 리소스
정적 리소스
- 스프링 부트는클래스패스가 해당 디렉토리에 있는 정적 리소스들을 제공한다.
- /static
- /public
- /resource/
- /META-INF/resorces
- 'src/main/resource'는 리소스를 보관하는 곳이며, 클래스 패스의 시작 경로다.
- 정적 리소스는 해당 파일을 변경 없이 그대로 서비스 하는 것이다.
뷰 템플릿
- 뷰 템플릿을 거쳐서 HTML이 생성되고, 뷰가 응답을 만들어서 클라이언트로 전달한다.
- 일반적으로 HTML을 동적으로 생성하는 용도로 쓰인다.
- 스프링 부트는 기본적으로 뷰 템플릿 경로를 제공한다.
- src/main/resource/templates
🔍 뷰 템플릿 생성
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p th:text="${data}">empty</p>
</body>
</html>
- 타임리프를 쓰기 위해서는 <html xmlns:th="http://www.thymeleaf.org"> 를 꼭 적어줘야 한다.
- <p th:text="${data}">empty</p>
- data에 들어올 데이터가 empty 대신 출력된다.
🔍 뷰 템플릿을 호출하는 컨트롤러
package hello.springmvc.basic.response;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class ResponseViewController {
@RequestMapping("/response-view-v1")
public ModelAndView responseViewV1() {
ModelAndView mav = new ModelAndView("response/hello")
.addObject("data", "hello!");
return mav;
}
@RequestMapping("/response-view-v2")
public String responseViewV2(Model model) {
model.addAttribute("data", "hello");
return "response/hello";
}
@RequestMapping("/response/hello")
public void responseViewV3(Model model) {
model.addAttribute("data", "hello!");
}
}
💡 첫 번째 방법
@RequestMapping("/response-view-v1")
@RequestMapping("/response-view-v1")
public ModelAndView responseViewV1() {
ModelAndView mav = new ModelAndView("response/hello")
.addObject("data", "hello!");
return mav;
}
- 뷰 주소가 담긴 ModelAndView 객체 반환
💡 두 번째 방법
@RequestMapping("/response-view-v2")
@RequestMapping("/response-view-v2")
public String responseViewV2(Model model) {
model.addAttribute("data", "hello");
return "response/hello";
}
- Model 객체 사용
- 반환타압이 String 이므로, 반환 값에 해당하는 뷰를 조회한다.
- 만약에 해당 메서드에 @ResponseBody 애노테이션 또는 HttpEntity를 사용하면, 반환 타입이 String 이여도 뷰 리졸버를 실행하지 않고 반환 값은 HTTP 메시지 바디에 직접 전달된고 출력된다.
💡 세 번째 방법
@RequestMapping("/response/hello")
@RequestMapping("/response/hello")
public void responseViewV3(Model model) {
model.addAttribute("data", "hello!");
}
- 두 번째 방법과 달리 세 번째 방법은 반환 타입이 void다.
- 그러므로 @RequestMapping과 같은 주소의 논리 이름의 뷰를 조회한다.
- 즉, /response/hello의 매핑 주소에서 맨 앞의 슬러쉬(/) 를 떼고, response/hello의 논리 주소와 같은 뷰를 조회한다.
- 요청 URL : /rsponse/hello
- 실행 : templates/response/hello.html
- 이 방법은 직관적이지 않으므로, 반환타입을 void로 하는 방법은 비 추천한다.
HTTP API / 메시지 바디에 직접 입력
- HTTP API를 제공하는 경우에 HTML이 아니라 데이터를 전달해야 하므로, HTTP 메시지 바디에 데이터를 JSON 같은 형식으로 보낸다.
- 정적 리소스, 뷰 템플릿을 거치지 않고 직접 HTTP 응답 메시지를 전달하는 경우다.
🔍 HTTP API 응답 컨트롤러
package hello.springmvc.basic.response;
import hello.springmvc.basic.HelloData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@RestController
public class ResponseBodyController {
@GetMapping("/response-body-string-v1")
public void responseBodyV1(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.getWriter().write("ok");
}
@GetMapping("/response-body-string-v2")
public HttpEntity<String> responseBodyV12() {
return new ResponseEntity<>("ok", HttpStatus.OK);
}
@GetMapping("/response-body-string-v3")
public String responseBodyV3() {
return "ok";
}
@GetMapping("/response-body-json-v1")
public ResponseEntity<HelloData> responseBodyJsonV1() {
HelloData helloData = new HelloData();
helloData.setUsername("userA");
helloData.setAge(20);
return new ResponseEntity<>(helloData, HttpStatus.OK);
}
@ResponseStatus(HttpStatus.OK)
@GetMapping("/response-body-json-v2")
public HelloData responseBodyJsonV2() {
HelloData helloData = new HelloData();
helloData.setUsername("userA");
helloData.setAge(20);
return helloData;
}
}
- @RestController
- @ResponseBody 와 @Controller를 합친 애노테이션이다.
- 해당 애노테이션이 적용된 클래스의 메서드들은 뷰 리졸버를 실행시키지 않고, 직접 HTTP 응답 메시지로 전달된다.
- Rest API (HTTP API)를 만들 때 사용되는 컨트롤러다.
💡 첫 번째 방법 - 단순 텍스트로 응답
@GetMapping("/response-body-string-v1")
@GetMapping("/response-body-string-v1")
public void responseBodyV1(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.getWriter().write("ok");
}
- 서블릿을 직접 다룰 때 처럼 HttpServletResponse 객체를 통해서 HTTP 메시지 바디에 직접 응답 메시지를 전달한다.
💡 두 번째 방법 - 단순 텍스트로 응답
@GetMapping("/response-body-string-v2")
@GetMapping("/response-body-string-v2")
public HttpEntity<String> responseBodyV12() {
return new ResponseEntity<>("ok", HttpStatus.OK);
}
- ResponseEntity 객체를 통해 HTTP 응답 메시지와 HTTP 상태 코드를 같이 전달할 수 있다.
💡 세 번째 방법 - 단순 텍스트로 응답
@GetMapping("/response-body-string-v3")
@GetMapping("/response-body-string-v3")
public String responseBodyV3() {
return "ok";
}
- 이 메서드의 클래스에 @RestController 애노테이션이 적용되어 있기 때문에 반환 타입이 String 이여도 뷰 리졸버 실행 없이 HTTP 메시지 컨버터를 통해서 HTTP 메시지를 직접 입력할 수 있다.
💡 네 번째 방법 - json 형식으로 응답
@GetMapping("/response-body-json-v1")
@GetMapping("/response-body-json-v1")
public ResponseEntity<HelloData> responseBodyJsonV1() {
HelloData helloData = new HelloData();
helloData.setUsername("userA");
helloData.setAge(20);
return new ResponseEntity<>(helloData, HttpStatus.OK);
}
- ResponseEntity 객체를 통해 HTTP 메시지와 HTTP 상태 코드를 같이 보낼 수 있다.
- HTTP 메시지 컨버터를 통해 JSON 형식으로 변환되어 반환된다.
💡 다섯 번째 방법 - json 형식으로 응답
@GetMapping("/response-body-json-v2")
@ResponseStatus(HttpStatus.OK)
@GetMapping("/response-body-json-v2")
public HelloData responseBodyJsonV2() {
HelloData helloData = new HelloData();
helloData.setUsername("userA");
helloData.setAge(20);
return helloData;
}
- @ResponseStatus 애노테이션을 통해 HTTP 상태 코드를 같이 보낼 수 있다.
- @ResponseStatus는 애노테이션이기 때문에 응답 코드를 동적으로 변경할 수 없다.
- 프로그램 조건에 따라 동적으로 변경하려면 ResponseEntity 객체를 사용할 것.
👀 참고 자료
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1#
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의
웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., -
www.inflearn.com
728x90