[ Spring ]/Spring 입문

[Spring 입문] 스프링 웹 개발 기초 (정적 컨텐츠, MVC와 템플릿 엔진, API)

쿠릉쿠릉 쾅쾅 2022. 2. 13. 22:46
728x90

 

 

웹 개발 3가지 방법

  • 정적 컨텐츠
    • 서버가 작업을 하지 않은 채, 파일을 그대로를 웹 브라우저에 내려주는 것
  • MVC 와 템플릿 엔진
    • 템플릿 엔진 : 서버에서 작업을 거쳐서 동적인 HTTP 파일로 만드는 것
    • 템플릿 엔진 예) JSP, PHH
  • API
    • 데이터 구조 포맷(format)으로 클라이언트한테 데이터를 전달하는 것
    • 요새는 데이터를 JSON 형식으로 보낸다. 
    • 사용할 때
      • API로 리액트나 뷰.js에게 데이터만 주고 화면은 클라이언트가 알아서 만들도록 하는 방식
      • 서버끼리 통신할 때

 

 

 

정적 컨텐츠

  • 스프링 부트는 정적 컨텐츠 기능을 제공한다.

 

📌 hello-static.html

<!DOCTYPE HTML>
<html>
<head>
    <title>static content</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
정적 컨텐츠 입니다.
</body>
</html>
  • 스프링 부트는 정적 컨텐츠 기능을 제공하기 때문에 http://localhost:8080/hello-static.html 사이트로 접속하면 해당 정적 컨텐츠 파일이 뜬다.

 

🔍 동작원리

  • 웹 브라우저에 url을 치면 내장 톰켓 서버로 요청이 간다.
  • 톰켓은 먼저 스프링 컨테이너 안에 해당 파일인 hello-static 관련 컨트롤러가 있는지 없는지 찾는다.
    • 컨트롤러의 우선권이 정적 컨텐츠보다 더 높다.
  • 스프링 컨테이너 안에서 hello-static 관련 컨트롤러 파일을 못 찾을 경우 resources 폴더에 static/hello-static.html 파일을 찾는다.
  • 있으면 다시 웹 브라우저에게 반환해준다.

 

 

 

MVC와 템플릿 엔진

  • MVC : Model, View, Controller
  • 사용자가 입력을 담당하는 View를 통해 요청을 보내면 해당 요청을 Controller가 받고, Controller는 Model을 통해 데이터를 가져온다. 해당 데이터를 바탕으로 출력을 담당하는 View를 제어해서 사용자에게 전달한다.
  • MVC 패턴을 사용하면 Model과 View가 다른 컴포넌트들에 종속되지 않아 변경에 유리하다는 장점을 가질 수 있다.
  • Model 
    • 애플리케이션이 무엇을 할 것인지 정의한다.
    • 내부 비즈니스 로직을 처리하기 위한 역할을 한다.
    • 즉, 데이터 저장소(DB)와 연동하여 사용자가 입력한 데이터나 사용자에게 출력할 데이터를 다룬다.
    • 여러 개의 데이터 변경 작업(추가/변경/삭제)을 하나의 작업으로 묶는 트랜잭션을 다루는 일도 한다.
  • View
    • 최종 사용자에게 무엇을 화면(UI)으로 보여준다.
    • 화면에 무엇을 보여주기 위한 역할을 한다.
    • 즉, 모델이 처리한 데이터나 그 작업 결과를 가지고 사용자에게 출력할 화면을 만든다. 만든 화면은 웹 브라우저가 출력한다.
  • Controller
    • Model이 데이터를 어떻게 처리할지 알려주는 역할을 한다.
    • 클라이언트의 요청을 받으면 해당 요청에 대한 실제 업무를 수행하는 Model을 호출한다.
    • 클라이언트가 보낸 데이터가 있다면, Model을 호출할 때 전달하기 쉽게 가공한다.
    • Model이 업무 수행이 완료하면 그 결과를 가지고 화면을 생성하도록 View에게 전달한다.
    • 즉, 클라이언트의 요청에 대해 Model과 View를 결정하여 전달하는 일종의 조정자 역할을 한다.

 

🔍 Controller

📌 HelloController.java

package hello.hellospring.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class HelloController {

    @GetMapping("hello")  // 주소명 적어 줄 것  → localhost:8080/hello 의미
    public String hello(Model model) {

        // ${data} 를 hello!! 로 변환
        model.addAttribute("data" , "hello!!");
        return "hello";  // html 파일 이름을 적어 줄 것 → hello.html 의미
    }

    @GetMapping("hello-mvc")
    public String helloMvc(@RequestParam("name") String name, Model model) {
        model.addAttribute("name", name);  // 데이터를 뷰로 전달한다.
        return "hello-template";
    }


}
  • @RequestParam
    • @RequestParam 애노테이션은 HttpServletRequest 객체와 같은 역할을 한다.
      • HttpServletRequest에서는 getParameter() 메서드를 이용하지만 @RequestParam을 이용해서 값을 받아 올 수 있다.
    • value 값으로 단일 파라미터만 전달 받을 수 있다.
    •  @RequestParam("가져올_데이터_이름") [데이터타입] [가져온_데이터를_담을_변수]
      • ex) @RequestParam("name") String name
      • 애노테이션 value 속성 값인 "name"에 해당하는 부분은 URL 쿼리 파라미터에 해당한다.
      • 그래서 URL 주소에 ?name="데이터" 이런 형태로 적어야 한다. 
      • 그러면 URL 주소에 적힌 쿼리파라미터 값이 String 타입의 name 변수에 들어가게 된다.
    • @RequestParam 애노테이션으로 가져온 값을 Model 객체를 이용해서 뷰로 값을 넘겨준다.

 

 

🔍 View

📌 hello-template.html

<html xmlns:th="http://www.thymeleaf.org">
<body>
<p th:text="'hello ' + ${name}">hello! empty</p>
</body>
</html>
  • Model 객체를 통해서 ${name} 부분에 데이터가 들어온다.
    • Model.addAttribute() 메서드를 통해서 해당하는 key 값에 value값을 넣어준다.
    • URL 주소에 http://localhost:8080/hello-mvc?name=spring 이렇게 적으면 name 쿼리 파라미터값인 spring이 Model 객체를 통해서 View로 데이터가 넘어와서 ${name} 부분에 데이터가 들어간다.

 

 

🔍 동작원리

  • 웹 브라우저가 톰켓에게 http://localhost:8080/hello-mvc 주소를 넘긴다.
  • helloController 클래스에 hello-mvc 메서드가 매핑이 되어있어서 helloMvc() 메서드를 호출해준다. 
  • helloMvc() 메서드를 호출하고 스프링에게 반환 값인 hello-template 과 model 객체를 통해서 데이터를 전달한다.
  • viewResolver가 hello-template.html 파일을 찾아서 템플릿 엔진에게 넘긴다.     
    • viewResolver는 사용자가 요청하는 것에 대한 응답 view를 렌더링하는 역할이다.
    • 간단히 말하자면 view 이름으로부터 사용될 view 객체를 매핑하는 역할을 한다.
    • viewResolver는 view를 찾아주고 템플릿 엔진을 연결시켜준다.
  • 템플릿 엔진이 렌더링을 해서 HTML로 변환을 하고 웹 브라우저로 넘겨준다.

 

 

 

 

API

  • MVC 방식은 화면에 렌더링하여 웹 브라우저에게 HTML로 전달한다.
  • 그러나 API는 데이터 형태로 전달해준다.

 

📌 HelloController.java

package hello.hellospring.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {

    @GetMapping("hello")  // 주소명 적어 줄 것  → localhost:8080/hello 의미
    public String hello(Model model) {

        // ${data} 를 hello!! 로 변환
        model.addAttribute("data", "hello!!");
        return "hello";  // html 파일 이름을 적어 줄 것 → hello.html 의미
    }

    @GetMapping("hello-mvc")  // localhost:8080/hello-mvc 의미미
    public String helloMvc(@RequestParam("name") String name, Model model) {
        model.addAttribute("name", name);
        return "hello-template";  // hello-template.html 의미
    }

    @GetMapping("hello-string")
    @ResponseBody
    public String helloString(@RequestParam("name") String name) {
        return "hello " + name;
    }

    @GetMapping("hello-api")
    @ResponseBody
    public Hello helloApi(@RequestParam("name") String name) {
        Hello hello = new Hello();
        hello.setName(name);
        return hello;
    }

    static class Hello {
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

}
  • @ResponseBody
    • @ResponseBody가 붙은 파라미터에는 HTTP 요청의 본문 body 부분이 그대로 전달된다.
    • 즉, HTTP 요청 body 부분을 자바 객체로 전달 받을 수 있다.
    • HTTP 메시지에 헤더와 바디가 나눠어져 있다.
    • 바디 부분에 이 데이터(리턴값)를 직접 넣어주겠다는 의미
    • 반환값은 클라이언트에 그대로 간다. 
    • MVC 패턴과 달리 API 방식은 뷰가 없다. 그냥 데이터 형태로 날라간다.
  • 웹 브라우저의 URL에 http://localhost:8080/hello-api?name=spring 를 입력하면쿼리파라미터인 키 값인 name과 value 값인 spring이 JSON 형태로 화면이 출력된다.

 

참고) @RequestBody

  • 일반적인 GET/POST의 요청 파라미터라면 @ResquestBody 애노테이션을 사용할 일이 없다.
  • 그러나 xml이나 JSON 기반의 메시지를 사용하는 요청의 경우에는 이 방법이 매우 유용하다.
  • HTTP 요청의 바디 내용을 통째로 자바 객채로 변환해서 매핑된 메서드 파라미터로 전달해준다.

 

💡 @RequestBody 와 @ResponseBody 정리

  • 클라이언트가 서버에게 필요한 데이터를 요청하기 위해 JSON 데이터를 요청 본문에 담아서 서버로 보낸다.
  • 서버는 @ReqeustBody 애노테이션을 사용하여 HTTP 요청 본문에 담긴 값들을 자바 객체로 변환시켜, 객체에 저장한다.
  • 서버가 클라이언트에게 응답 데이터를 전송하기 위해 @ResponseBody 애노테이션을 사용하여 자바 객체를 HTTP 응답 본문의 객체로 변환하여 클라이언트로 전송한다.

 

 

💡 클라이언트와 서버의 비동기 통신

  • 클라이언트에서 서버로 통신하는 메시지를 요청(request) 메시지라고 하며, 서버에서 클라이언트로 통신하는 메시지를 응답(response) 메시지라고 한다.
  • 웹에서 화면전환(새로고침) 없이 이루어지는 동작들은 대부분 비동기 통신으로 이루어진다.
  • 비동기 통신을 하기 위해서는 클라이언트에서 서버로 요청 메시지를 보낼 때, 본문에 데이터를 담아서 보내야 하고, 서버에서 클라이언트로 응답을 보낼 때에도 본문에 데이터를 담아서 보내야 한다.
  • 이 때 본문이 바로 body다.
  • 즉 요청 본문 requestBody, 응답 본문 responseBody를 담아서 보내야 한다.
  • 본문에 담기는 데이터 형식은 여러가지 형태가 있겠지만 대표적으로 사용 되는 것이 JSON이다.
  • 즉, 비동기식 클라-서버 통신을 위해 JSON 형식의 데이터를 주고 받는 것이다.

 

 

🔍 동작 원리

  • 웹 브라우저가 톰켓에게 url 주소를 던진다.
  • 톰켓은 스프링에게 hello-api를 전달한다.
  • 스프링은 helloController에 hello-api과 매핑된 메서드를 찾고 호출한다.
  • 근데 @ResponseBody가 붙어있기 때문에 viewResolver 에게 넘기지 않고 HttpMessageConver에게 반환값을 넘긴다.
  • 반환 타입이 기본 문자일 경우 : StringHtppMessageConverter가 처리한다.
  • 반환 타입이 객체인 경우 : MappingJackson2HttpMessageConverter가 처리한다.
    • Jackson2는 객체를 Json으로 변환해주는 라이브러리다.
  • 참고로 HTTP Accept 헤더와 서버의 컨트롤러 반환 타입 정보를 토대로 HttpMessageConverter의 종류가 선택된다.

 

 


👀 참고 자료

https://hongku.tistory.com/119

 

SpringMVC :: @RequestParam 을 이용한 값 받아오기

@ReuqestParam 을 이용한 값 받아오기 @ReuqestParam 어노테이션은 HttpServletRequest 객체와 같은 역할을 한다. HttpServletRequest에서는 getParameter() 메소드를 이용했지만, @RequestParam을 이용해서 받아..

hongku.tistory.com

 

https://januaryman.tistory.com/131?category=959308 

 

ViewResolver란

- ViewResolver란 ViewResolver는 사용자가 요청한 것에 대한 응답 view를 렌더링하는 역할. 간단히 말하자면 view 이름으로부터 사용될 view 객체를 맵핑하는 역할을 한다. 그렇다면 ViewResolver를 생성하지

januaryman.tistory.com

 

https://cheershennah.tistory.com/179

 

[Spring] @RequestBody / @ResponseBody 어노테이션 이란?

스프링에서 비동기 처리를 하는 경우 @RequestBody , @ResponseBody를 사용한다. 비동기 처리를 위해 이 어노테이션들은 어떻게 작동할까? 클라이언트와 서버의 비동기 통신  클라이언트에서 서버로 통

cheershennah.tistory.com

 

https://tecoble.techcourse.co.kr/post/2021-04-26-mvc/

 

728x90