[ 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