Spring의 간단한 동작방식

guswls·2023년 1월 8일
0

스프링 입문

목록 보기
3/13
post-thumbnail

이 포스트는 김영한 이사님의 스프링 입문 강의를 듣고 작성하였습니다.

웹개발에는 다음과 같이 크게 3가지 방법이 존재한다.

웹 개발 방식

  • 정적 컨텐츠
  • MVC와 템플릿 엔진
  • API

이번엔 이 3가지 방법에 대해서 간단하게 알아보고자 한다.

1. 정적 컨텐츠

정적컨텐츠는 말 그대로 정적인 파일(html)을 브라우저에 띄우는 것을 말한다. 다음과 같이 html파일을 생성해보자.
정적인 파일들은 프로젝트 내에서 /static이라는 경로에 저장된다. 위와 같이 작성하고 별도의 컨트롤러를 작성하지 않은 상태에서 서버를 실행시켜 http://localhost:8080/hello-static.html 로 접속하여보자.
우리가 별도의 매핑을 하지 않았음에도 불구하고 우리가 작성한 파일이 화면에 띄워지게 됐다. 이 이유는 스프링의 동작방식에 있다.

정적 컨텐츠 동작 방식

  1. 우리가 내장 톰켓 서버에서 http://localhost:8080/hello-static.html로 접근한다.

  2. 스프링 컨테이너에서 hello-static에 관한 컨트로러를 찾는다.

  3. 만약 존재하지 않는다면 /resource/statichello-static이라는 파일을 찾아 브라우저에서 띄우게 된다.

2. MVC와 템플릿 엔진

MVC는 간략하게 얘기해서 프로그램을 Model, View ,Controller 3파트로 나누어 개발하는 것을 의미한다.
즉, VIew는 화면을 보여주는 일만 처리하고 Controller에서는 프로젝트 내부의 비지니스 로직을 다루는 방식으로 관심사를 분리하여 개발을 하는 것을 의미한다. 이에 대해선 나중에 다뤄볼 예정이다.

실습은 저번 시간에 먼저 이어서 진행한다. 우리가 전에 만들었던 HelloController에서 helloMvc를 추가해준다.

//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")
    public String hello(Model model){
        model.addAttribute("data", "hello!!");
        return "hello";
    }
    //추가
    @GetMapping("hello-mvc")
    public String helloMvc(@RequestParam("name") String name, Model model){
        model.addAttribute("name", name);
        return "hello-template";
    }
}

그 후 /resources/templateshello-template.html 파일을 작성해주자.

<html xmlns:th="http://www.thymeleaf.org">
<body>
<p th:text="'hello ' + ${name}">hello! empty</p>
</body></html>

이렇게 작성한 후에 http://localhost:8080/hello-mvc주소에 접근하면 오류가 발생한다.
로그를 확인해보면 다음과 같은 오류를 확인할 수 있는데 우리가 인자로 지정해준 name이 없다는 뜻이다.
crtl+p 단축키를 활용하면 다음과 같이 파라미터에 대한 정보를 확인할 수 있다. 위의 화면을 살펴보면 required라는 파라미터가 있는데 default값으로 true가 지정되어있다. 만약 이 인자값을 false로 지정하면 없어도 정상적으로 실행이 된다.

따라서 아무것도 건들지 않는 상태로 쿼리스트링을 통해 인자를 넘겨줘서 실행해보도록 하자.
http://localhost:8080/hello-mvc?name=spring!이렇게 namespring!이라는 값을 넘겨주어 사용하게 되면 다음과 같이 화면이 동작하게 된다.
우리가 쿼리스트링을 통해 전달해준 name=spring!에 대한 결과가 템플릿 엔진을 거쳐 spring!이라는 문자열을 화면에 보여주게 된 것이다. 간단한 동작 방식은 다음과 같다.

MVC와 템플릿 엔진의 동작 방식

  1. http://localhost:8080/hello-mvc?name=spring!로 접근하면 내장 톰캣서버에서 스프링 컨테이너로 전달된다.

  2. HelloContoller에서 해당 주소와 컨트롤러가 맵핑된다.

  3. 컨트롤러는 hello-template 문자열을 반환하고 modelname(key)=spring!(value)이 추가되게 된다

  4. viewResolvertemplates/hello-template을 찾고 Thymeleaf엔진으로 템플릿 변환을 요청한다.

  5. 변환된 html파일이 화면에 보여지게 된다.

웹페이지를 개발자 도구를 통해 보면 다음과 같이 변환된 html이 브라우저로 전달되었음을 확인해볼 수 있다.


3. API 방식

바로 실습을 진행하며 보자.

//HelloContoller.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")
    public String hello(Model model){
        model.addAttribute("data", "hello!!");
        return "hello";
    }
    
    @GetMapping("hello-mvc")
    public String helloMvc(@RequestParam("name") String name, Model model){
        model.addAttribute("name", name);
        return "hello-template";
    }

    //추가
    @GetMapping("hello-string")
    @ResponseBody //응답 바디에 직접 값을 넣어줌
    public String helloString(@RequestParam("name") String name){
        return "hello " + name;
    }
}

위와 같이 hello-string에 맵핑된 컨트롤러를 추가하고 http://localhost:8080/hello-string?name=spring 주소에 접속해보자.
응답 바디hello string이 바로 전달된 것을 확인할 수 있다.
즉, 위에 실습했던 두 경우와 같이 어떤 html 파일을 화면에 전달하는 것이 아닌 http의 응답 바디로 바로 값을 넘겨준 것이다.

이 방식을 사용하는 가장 큰 이유는 데이터로 값을 넘겨줄 수 있다는 점이다. 객체를 생성하여 값을 넘겨주는 실습을 진행하여보자.

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")
    public String hello(Model model){
        model.addAttribute("data", "hello!!");
        return "hello";
    }

    @GetMapping("hello-mvc")
    public String helloMvc(@RequestParam("name") String name, Model model){
        model.addAttribute("name", name);
        return "hello-template";
    }

    @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 void setName(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }
    }
}

hello-api라는 주소에 맵핑되는 컨트롤러를 추가하여 주었다. 이 컨트롤러는 객체를 반환하며 name은 쿼리스트링으로 전달받은 값으로 초기화하여 준다.

참고로 InteliJ에서 Getter 및 Setter에 대한 단축키는 Alt + Insert이다.

이제 http://localhost:8080/hello-api?name=spring 주소로 접속하면 다음과 같은 화면을 볼 수 있다. 응답 바디에 전달해준 객체Json형태로 반환된 것을 확인할 수 있다.

동작방식에 관해 간략하게 살펴보면 다음과 같다.

@ResponseBody 동작원리

  1. http://localhost:8080/hello-api?name=spring로 접근하면 내장 톰캣에서 스프링 컨테이너로 주소가 전달된다.

  2. HelloContoller에서 해당 주소와 매핑되는 컨트롤러를 수행한다.

  3. @ResponseBody 어노테이션이 붙어있으면 viewResolve가 아닌 HttpMessageConverter가 동작한다.

  4. 만약 컨트롤러에서 객체를 반환했다면 JsonConverter가 동작하여 객체Json형태로 변환한다.

  5. Json형태로 변환된 객체가 응답바디에 들어가 클라이언트로 전달된다.

4. 총정리

이번엔 스프링의 기초적인 동작방식 3가지에 대해서 간략하게 살펴보았다. 이를 크게 보면 두 가지로 나눌 수 있을 것이다.

  1. View로써 html파일을 직접 클라이언트에 전달하는 형태
  2. 응답 바디에 값을 Json으로 전달해주는 형태

프론트 엔드와 협업으로 프로젝트를 하면 대부분 2번의 형태로 Json을 반환하여 주는 방식으로 진행하게 된다. 장고를 공부했던 기억을 떠올리며 공부를 하니 훨씬 머리에 잘 와닿았고 동작 방식에 대한 흐름을 정리할 수 있었다.

profile
안녕하세요

0개의 댓글