Web/Spring
[Inflearn] 스프링 MVC (6) HTTP 응답
UL :)
2022. 1. 31. 17:11
김영한 강사님의 '스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술' 강의 정리
2022.01.31~02.01 진행
강의를 듣고 개인적으로 정리한 글입니다. 코드와 그림 출처는 김영한 강사님께 있습니다. 문제 있을 시 알려주세요.
HTTP 응답
HTTP에서 응답 데이터를 만드는 방식은 크게 3가지 이다.
- 정적 리소스
- 뷰 템플릿 사용
- HTTP 메시지 사용
1. 정적 리소스 응답 - HTML
- 정적 리소스 응답이란, 해당 파일을 변경 없이 그대로 서비스하는 것을 말한다.
- 웹 브라우저에 정적인 HTML, CSS, JS를 제공할 때는 정적 리소스를 사용한다.
- 스프링 부트에서
src/main/resources
는 클래스 패스의 시작 경로로, 리소스를 보관하는 곳이다. - 스프링 부트는 클래스패스의 다음 디렉토리에 있는 정적 리소스를 제공한다.
- 정적 리소스 경로:
src/main/resources/static
- 정적 리소스 경로:
/static
,/public
,/META-INF/resources
2. 동적 리소스 응답 - 뷰 템플릿
- 웹 브라우저에 동적인 HTML을 제공할 때는 뷰 템플릿을 사용한다.
- 뷰 템플릿을 거쳐서 HTML이 생성되고, 뷰가 응답을 만들어서 전달한다.
- 스프링 부트가 제공하는 기본 뷰 템플릿 경로:
src/main/resources/templates
Thymeleaf 를 사용해서 적용해보자
Thymeleaf 스프링 부트 설정
build.gradle에 org.springframework.boot:spring-boot-starter-thymeleaf
라이브러리가 추가되어 있으면
스프링 부트는 자동으로 ThymeleafViewResolver
와 필요한 스프링 빈들을 등록한다.
또한 application.properties
에는 다음 기본 값이 설정되어 있다. (필요할 때에만 변경)
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
반환타입에 따라 달라지는 응답- View or HTTP 메시지
- ModelAndView를 반환하는 경우
- 해당 객체에 등록된 경로로 뷰 리졸버가 실행되어서 뷰를 찾고 랜더링 한다.
- String으로 반환하는 경우
@ResponseBody
가 없는 경우response/hello
로 뷰 리졸버가 실행되어서 뷰를 찾고 랜더링 한다@ResponseBody
가 있는 경우 뷰 리졸버를 실행하지 않고, HTTP 메시지 바디에 직접response/hello
라는 문자가 입력된다.
void를 반환하는 경우는 권장되지 않으므로 생략하였다.
@Controller
public class ResponseViewController {
/** ModelAndView 반환 */
@RequestMapping("/response-view-v1")
public ModelAndView responseViewV1(){
ModelAndView mav = new ModelAndView("response/hello")
.addObject("data","hello!");
return mav;
}
/** 권장, String 반환 */
@RequestMapping("/response-view-v2")
public String responseView2(Model model){
model.addAttribute("date", "hello!");
return "response/hello";
}
/** 권장X void 반환 */
@RequestMapping("/response/hello")
public void responseView3(Model model){
model.addAttribute("date", "hello!");
}
}
3. HTTP 메시지 바디 - 데이터 직접 전달하기
- HTTP API를 제공하는 경우
- 정적 리소스나 뷰 템플릿을 거치지 않고 직접 HTTP 응답 메시지로 데이터를 전달 해야한다.
- HTTP 메시지 바디에 JSON 같은 형식으로 데이터를 실어보낸다.
3.1. 문자처리
HTTP 응답은 앞선 포스팅에서도 다루었으므로 예제 코드로만 정리하겠다.
@Slf4j
@Controller
public class ResponseBodyController {
/** HttpServletResponse 사용 */
@GetMapping("/response-body-string-v1")
public void responseBodyV1(HttpServletResponse response) throws IOException {
response.getWriter().write("ok");
}
/** HttpEntity를 상속받은 ResponseEntity 사용
* HTTP 응답 코드 동적으로 설정 가능 */
@GetMapping("/response-body-string-v2")
public ResponseEntity<String> responseBodyV2() throws IOException {
return new ResponseEntity<>("ok", HttpStatus.OK);
}
/** @ResponseBody 사용*/
@ResponseBody
@GetMapping("/response-body-string-v3")
public String responseBodyV3() {
return "ok";
}
3.2. JSON 처리
/** HttpEntity를 상속받은 ResponseEntity 사용
* HTTP 응답 코드 동적으로 설정 가능 */
@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
애노테이션을 사용하면 다음과 같이 응답 코드를 설정할 수 있지만, 동적인 변경은 불가능하다.
@ResponseStatus(HttpStatus.OK)
@ResponseBody
@GetMapping("/response-body-json-v2")
public HelloData responseBodyJsonV2(){
HelloData helloData = new HelloData();
helloData.setUsername("userA");
helloData.setAge(20);
return helloData;
}
}
❗ 프로그램 조건에 따라 동적으로 응답 코드를 변경하려면 ResponseEntity
를 사용해야 한다.
3.3. @RestController
@ResponseBody
를 클래스 단위에 두면 전체 메서드에 적용이 된다. 이 기능과 @Controller
적용을 합친 것이 @RestController
이다.
@RestController를 적용한 전체 코드는 다음과 같다.
@Slf4j
//@Controller
@RestController /** @Controller + @ResponseBody 효과 */
public class ResponseBodyController {
/** 1. 문자처리 */
@GetMapping("/response-body-string-v1")
public void responseBodyV1(HttpServletResponse response) throws IOException {
response.getWriter().write("ok");
}
/** HttpEntity를 상속받은 ResponseEntity 사용
* HTTP 응답 코드 동적으로 설정 가능 */
@GetMapping("/response-body-string-v2")
public ResponseEntity<String> responseBodyV2() throws IOException {
return new ResponseEntity<>("ok", HttpStatus.OK);
}
/** @ResponseBody 사용*/
// @ResponseBody
@GetMapping("/response-body-string-v3")
public String responseBodyV3() {
return "ok";
}
/**
* 2. JSON 처리
*/
@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)
// @ResponseBody
@GetMapping("/response-body-json-v2")
public HelloData responseBodyJsonV2(){
HelloData helloData = new HelloData();
helloData.setUsername("userA");
helloData.setAge(20);
return helloData;
}
}