Spring MVC : 정적 리소스, 뷰 템플릿, HTTP API

    Spring MVC 응답


    1. 정적 리소스
      • 웹 브라우저에 정적인 HTML, CSS, JS를 제공할 때 사용(파일을 그대로 전달)
    2. 뷰 템플릿 사용
      • 웹 브라우저에 동적인 HTML을 제공. 뷰 템플릿을 사용(SSR)
    3. HTTP 메세지 사용
      • HTTP API를 제공하는 경우, HTML이 아닌 데이터를 전달한다. 주로, HTTP 메세지 바디에 JSON 같은 형식으로 데이터를 제공한다.

    Spring MVC에서 응답을 만드는 방법은 위 3가지다.

     

    정적 리소스 제공


    Spring은 아래 디렉토리에 있는 정적 리소스를 제공한다

    • /static 
    • /public
    • /resources
    • /META-INF/resources 
    • /src/main/webapp/WEB-INF (이 경우 외부에서 직접 접근 불가능)

    /static에 넣어둔 HTML은 스프링부트가 내장 TOMCAT 서버를 서빙할 때, 자동으로 제공해준다. 정적 리소스는 말한 것처럼 파일 있는 그대로가 출력이 된다.

    • static 파일 위치 → src/main/resources/static/basic/hello-form.html
    • 브라우저 실행 경로 → localhost:8080/basic/hello-form.html

    static 폴더에 있는 파일을 브라우저에 실행할 때는 위의 경로를 참고해서 실행하면 된다. 

     

     

    뷰 템플릿 사용 → 주로 Thymeleaf


    뷰 템플릿을 거쳐서 HTML이 생성되고, 뷰가 응답을 만들어서 전달한다. 뷰템플릿은 일반적으로 HTML을 동적으로 생성하는 용도로 사용한다. 다른 용도로도 사용이 가능한데, 뷰 템플릿이 만들 수 있는 것이라면 무엇이든지 가능하다고 한다. 

    뷰 템플릿 기본 경로 : /src/main/resources/templates

     

    뷰 템플릿 만들기

    <!-- resources/templates/response/hello.html-->
    <!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>
    • 위는 Thymeleaf를 사용한 간단한 뷰 템플릿을 사용한 것이다.
    • Thymeleaf는 HTML의 속성을 설정해서 사용하는 뷰 템플릿이다.
    • Thymleaf를 사용하기 위해서는 HTML 태그 안에 이 속성을 설정해줘야한다. xmlns:th="http://www.thymeleaf.org">

     

    뷰 템플릿을 호출하는 컨트롤러 만들기 버전1

    @GetMapping("/response-view-v1")
    public ModelAndView responseViewV1() {
        return new ModelAndView("response/hello").
                addObject("data","hello!");
    }
    
    • ModelAndView에 ViewName으로 "response/hello"를 넣어주었다. 
    • Model에 "data"라는 이름으로 "hello!"라는 값을 넣어주었다.
    • 반환된 ModelAndView는 DispatcherServlet의 ThyemeleafViewResolver에서 View가 만들어진다. 
      • 최종경로는 "/resources/templates/response/hello.html"로 변경된다.
      • 스프링 Thymeleaf의 기본경로는 prefix : resources > templates  /// suffix : .html이다.

     

     

    뷰 템플릿을 호출하는 컨트롤러 만들기 버전2

    @GetMapping("/response-view-v2")
    public String responseViewV2(Model model) {
        model.addAttribute("data", "hello!");
        return "response/hello";
    }
    
    • 버전 1에서는 ModelAndView를 직접 만들어서 반환했다. 그런데 매번 ModelAndView를 만들어서 보내면 번거롭다.
    • 매개변수로 Model을 받고, Model에 필요한 값을 저장해준다.
    • 원하는 ViewTemplate 경로를 Return 해주면 @Controller 기반에서는 이것을 viewName으로 인식한다.

     

    뷰 템플릿을 호출하는 컨트롤러 만들기 버전3

    @GetMapping("/response/hello")
    public void responseViewV3(Model model) {
        model.addAttribute("data", "hello!");
    }
    • ViewTemplate의 경로와 Mapping URL이 같고, return Type이 Void인 경우 스프링이 관례적으로 Mapping URL을 ViewTemplate 경로로 인식한다.
    • 단, 명시성이 없기 때문에 추천하지는 않는다고 한다.

     

    반환 타입에 따른 ViewResolver의 동작 여부


    String을 반환하는 경우 → ViewName 혹은 HTTP 메세지 바디로 인식

    • @ResponseBody가 없으면 viewName으로 인식한다. ViewResolver가 실행되어서 뷰를 찾고 렌더링 한다.
    • @ResponseBody가 있으면 View Resolver 실행 X, View를 거치지 않고 해당 String을 HTTP 메세지 바디에 직접 넣어준다. 

    Void를 반환하는 경우

    • @Controller를 사용하고, HttpServletResponse, OuputStream(Writer)처럼 HTTP 메세지 바디를 처리하는 파라미터가 없으면 요청 URL을 참고해서 viewName으로 사용한다.
    • 요청 URL : /resource/hello
    • 실행 : templates/resource/hello

    HTTP 메세지

    @RestonController, @ResponseBody, @HttpEntity, @ResponseEntity, OutputStreadm(Writer)를 사용하면 HTTP 메세지 바디에 직접 응답 데이터를 출력할 수 있다. 

     

    Thymeleaf의 스프링 부트 설정방법


    // build.gradle > dependencies
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

    원래는 이런저런 조치를 많이 해야하지만, 스프링부트는 ThymeLeaf의 사용 설정을 아주 쉽게 해준다. 위의 코드를 build.gradle에 넣어줘도 되고, 스프링 스타터에서 프로젝트를 생성할 때 dependencies로 "THYMELEAF"를 넣어줘도 된다.

    //application.properties
    
    spring.thymeleaf.prefix=classpath:/templates/
    spring.thymeleaf.suffix=.html
    spring.thymeleaf.cache=true

    application.properties에 위의 속성을 추가해서 thymeLeaf에 대한 기본 설정을 할 수 있다. 기본값은 위와 같다. 

     

     

    HTTP 응답 - HTTP API, 메세지 바디에 직접 입력


    HTTP API를 제공하는 경우 HTTP Body에 HTML이 아닌 데이터를 직접 전달해야한다. 주로 JSON 형식으로 데이터를 전달한다고 한다. 

    이 때 구분해야할 것은 View Templates으로 응답하는 것도 HTML 데이터가 바디에 적재되어서 전달된다. HTTP 응답은 HTML 데이터를 바디에 넣는 것이 아니라 JSON 형식의 데이터를 직접 전달하는 것이기 때문에 구별해서 알아둘 필요가 있다. 

    Body에 직접 데이터를 넣어주는 방법은 아래가 있는 것으로 알고 있다.

    • @ResponseController(@Controller + @ResponseBody) → 클래스 전체에 적용
    • @ResponseBody → 메서드에만 적용
    • response.getWriter().write("...") 
    • HttpEntity, ResponseEntity 값을 반환

     

    HTTP Body에 문자열을 직접 리턴1

    @GetMapping("/response-body-string-v1")
    public void responseBodyV1(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.getWriter().write("ok");
    }
    • HttpServletResponse 객체를 이용해서 Writer(OutPutStream)을 얻는다.
    • Writer에서 write() 메서드를 사용해주면, 필요한 String 메세지를 바디에 직접 적을 수 있다.

     

    HTTP Body에 문자열을 직접 리턴2

    @GetMapping("/response-body-string-v2")
    public ResponseEntity<String> responseBodyV1() {
        return new ResponseEntity<String>("ok", HttpStatus.OK);
    }
    • HttpEntity, ResponseEntity를 반환하는 방식이다.
    • HttpEntity, ResponseEntity는 HTTP 메세지의 헤더, 바디 정보등을 가지고 있다.
    • HttpEntity, ResponseEntity에 Body 메세지, 상태 코드등을 직접 셋팅해서 반환해준다.
    • HttpEntity, ResponseEntity를 사용하면 HTTP 메세지 컨버터를 통해서 HTTP 메세지를 직접 입력할 수 있다.

     

    HTTP Body에 문자열을 직접 리턴3

    @ResponseBody
    @GetMapping("/response-body-string-v3")
    public String responseBodyV2(){
        return "ok";
    }
    
    • @ResponseBody 어노테이션을 사용했다.
    • @ResponseBody 어노테이션을 사용하면, 반환되는 모든 값이 바디 메세지에 저장된다.
    • @ResponseBody를 사용하면 View를 사용하지 않고, HTTP 메세지 컨버터를 통해서 HTTP 메세지를 직접 입력할 수 있다. 

     

    HTTP Body에 JSON 반환 1

    @GetMapping("/response-body-json-v1")
    public ResponseEntity<HelloData> responseBodyJsonV1() {
    
        HelloData helloData = new HelloData();
        helloData.setAge(20);
        helloData.setUsername("userA");
    
        return new ResponseEntity<HelloData>(helloData, HttpStatus.CREATED);
    }
    • ResponseEntity를 활용해서 JSON을 리턴하는 방식이다.
    • ResponseEntity에 객체를 넣으면, 이 객체는 HTTP 메세지 컨버터를 통해서 HelloData의 Properties들이 JSON 형식으로 변환된다.
    • JSON 형식으로 변환된 값은 View를 거치지 않고 바로 HTTP Body에 들어간다.

     

    HTTP Body에 JSON 반환 2 + 응답코드 설정

    @ResponseStatus(HttpStatus.OK)
    @ResponseBody()
    @GetMapping("/response-body-json-v2")
    public HelloData responseBodyJsonV2(){
        HelloData helloData = new HelloData();
        helloData.setAge(20);
        helloData.setUsername("userA");
    
        return helloData;
    }
    
    • @ResponseBody를 통해서 값을 Return하면 이 값은 모두 HTTP 메세지 컨버터를 통해 Body에 직접 들어간다.
    • HelloData를 Return하면 HelloData의 properties들에 대해 자동으로 파싱되어 JSON으로 만들어진다.
    • JSON으로 만들어진 값은 View를 거치지 않고 자동으로 HTTP 메세지 바디에 들어가게 된다.
    • 응답코드 설정은 @ResponseStatus로 할 수 있다.

     

    댓글

    Designed by JB FACTORY