Study

[STUDY] 스프링 입문 기록(1) - 코드로 배우는 스프링부트, 웹 MVC, DB 접근 기술

jeonniu 2023. 2. 23. 15:47

01. Spring 웹 개발 기초 

웹 개발 시엔 크게 3가지 방법이 있다.

 

 

 

(1) 정적 컨텐츠

- 서버에서 하는 것 없이 파일을 그대로 웹브라우저에 띄우는 것

 

 

정적 컨텐츠 이미지

 

  1. 웹 브라우저에서 loalhost:8080/hello-static.html을 입력하면, 내장 톰캣 서버가 요청을 받는다.
  2. 내장 톰캣 서버가 hello-static.html을 스프링에게 넘기면 스프링은 컨트롤러(Controller)를 우선순위로 두고 hello-static이라는 컨트롤러가 있는지 확인 한다.
  3. 해당 컨트롤러가 없을 경우 Stpring Boot는 resources내부에 있는 static/hello-static.html 을 찾은 후 웹브라우저에 반환하는 과정으로 동작이 이루어진다. 

 

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>

 

 

정적컨텐츠 - 실행 결과

 

 

 

 

 


 

(2) MVC와 템플릿 엔진

- MVC: Model, View, Controller

  • Model: 컨트롤러로 처리된 후, 화면에 필요한 것들을 담아서 화면 쪽으로 보내주는 것 
  • View: 화면을 그리는 데에 역량을 집중하는 것 
  • Controller: 비즈니스 로직이나 내부적인 것을 처리하는 데에 집중하는 것

- 템플릿 엔진: JSP, PHP와 같이 HTML을 그냥 주는 것이 아닌 서버에서 프로그래밍 해서 HTML을 동적으로 바꿔서 내리는 것

 

 

Controller

 

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

 

View

hello-templates.html

 

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

 

 

MVC - 실행 결과 (hello-templates.html의 절대경로를 입력)

 

 

주소창에 http://localhost:8080/hello-mvc 입력 결과

 

 

파라미터를 전달하지 않았기 때문에 오류 발생

 

 

Solution: Controller(hello-mvc)의 name 파라미터에 jeonniu!를 추가

ex) http://localhost:8080/hello-mvc?name=jeonniu!

 

- 컨트롤러에서 name은 jeonniu!로 바뀌고 Model에 담긴 후,  hello-templates.html에 넘어가면 Model KEY 값인 name에 jeonniu!를 출력하는 형식

 

 

파라미터 전달할 시엔 정상 출력

 

 

MVC, 템플릿 엔진 이미지

 

  1. 웹 브라우저에서 localhost:8080/hello-mvc를 띄우면 내장 톰캣 서버가 hello-mvc를 스프링에 넘긴다.
  2. helloController에 hello-mvc가 매핑 된 것을 확인 후 호출한다. (해당 메서드를 return 할 때는 hello-templates, Model에는 key는 name, 값은 jeonniu!로 넣어준다.)
  3. 화면 해결자인 viewResolver가 templates 파일 내부에 hello-templates라는 return의 String name과 똑같은 것을 찾으면, 템플릿 엔진이 변환한 html을 웹브라우저에 반환한다. 

 

  • 정적 컨텐츠와의 차이: 정적 컨텐츠는 파일을 그대로 웹브라우저에 띄우는 방식의 웹개발이지만, MVC는 서버에서 HTML을 변환해서 내려주는 방식이라는 점에서 차이가 있다.

 

 

 

 

 


 

(3) API

- Json 데이터 구조 포맷으로 클라이언트에게 데이터를 전달해주는 방식 

- API로 데이터만 내려주면, 화면은 클라이언트가 알아서 그리고 정리하는 방식을 사용

- 서버끼리 통신할 경우엔 HTML을 내릴 필요가 없이 데이터의 흐름을 아는 것이 중요하기 때문에 주로 사용 

 

 

 

 

(1) 문자를 받는 방식

 

Controller

 

    @GetMapping("hello-string")
    @ResponseBody // http의 Response body부에 해당 내용을 직접 넣어주겠다는 의미
    public String helloString(@RequestParam("name") String name) {
        return "hello" + name; // "hello (요청한 내용)"
    }

 

@ResponseBody 를 사용하면 뷰 리졸버( viewResolver )를 사용하지 않는다.

또한 HTTP의 BODY에 문자 내용을 직접 반환한다는 의미를 가지고 있다.

 

 

@ResponseBody 적용한 페이지 소스

 

해당 템플릿 엔진은 데이터를 그대로 내려주는 방식이기 때문에 페이지의 소스를 보면 HTML 태그가 없는 것을 확인할 수 있다. 

 

 

 

 

MVC와 템플릿 엔진 페이지 소스

 

반면 MVC 방식은 View라는 템플릿이 있는 상태에서 조작하는 방식으로 페이지 소스를 확인하면 HTML 태그가 있는 것을 확인할 수 있다.

 

 

 

 

(2) 객체를 받는 방식

 

Controller

 

// Spring에서 객체를 반환하고 ResponseBody를 사용할 경우, json으로 반환하는 것이 기본적
// @ResponseBody 를 사용하면 뷰 리졸버( viewResolver )를 사용하지 않음
    @GetMapping("hello-api")
    @ResponseBody
    public Hello helloApi(@RequestParam("name") String name) {
        Hello hello = new Hello();
        hello.setName(name);
        return hello;
    }

    public class Hello {
        private String name;

        // getter setter window 단축키: alt+insert
        public String getName() {
            return name;
        }

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

 

Getter/Setter 방식 사용하는 근본적인 이유는 '객체지향'에서 말하는 캡슐화(encapsulation)를 달성하기 위함이다. 

캡슐화란 서로 관련이 있는 데이터와 그 데이터를 다루는 메서드를 하나의 클래스로 묶는 것을 의미하는데, 캡슐화의 가장 큰 장점은 다른 객체에서 자신의 정보를 은닉하고, 오직 연산을 통해서만 접근할 수 있는 정보은닉(Information Hiding)이 가능하다는 것이다.

 

 

Getter

- 서로 다른 객체 A, B가 있다고 가정할 때, 객체 A는 객체 B의 변수 x를 참조하고 있다.

 

public class A {
    B B = new B();
    int x = B.x;
}
public class B {
    int x;
}

 

여기서 객체 B의 변수명인 x를 x1으로 수정하고 싶다면? 객체 A는 x1을 사용할 수 없을 것이다.

이는 캡슐화가 제대로 이루어지지 않았다고 할 수 있다.

 

 

이 때 Getter 방식을 사용해보자.

 

 

public class A {
    B B = new B();
    int x = B.getX();
}
public class B {
    int x1;
    
    public int getX() {
        return x1;
    }
}

 

객체 B의 변수명 x가 x1으로 객체 A에는 아무런 영향 없이 기존의 x 값을 사용할 수 있게 된다.

 

 

 

 

Setter

- 서로 다른 객체 A, B가 있다고 가정할 때, 객체 A의 x 값을 객체 B의 x 값으로 전달하고 싶다. 

public class A {
    int x = 0;
    B B = new B();
    B.x = x;
}
public class B {
    int x;
}

 

하지만 위의 방식으로 값을 전달할 경우, 객체 B의 x에 직접 선언해주는 것이 되어 캡슐화를 제대로 이룰 수 없다.

 

 

이 때 Setter 방식을 사용해보자.

 

 

public class A {
    int x = 0;
    B B = new B();
    B.setX(x);
}
public class B {
    int x;
    
    public void setX(int x) {
        this.x = x;
    }
}

 

 

이렇게 하면 간접적으로 객체 A의 x 값을 객체 B의 x값으로 전달할 수 있게 되어

캡슐화의 목적을 달성할 수 있다.

 

 

 

 

JSON 방식

KEY=VALUE  형태로 이루어져 있는 것을 확인할 수 있다.

 

 

@ResponseBody 사용 원리

  1. 웹브라우저에서 localhost8080//hello-api 를 검색할 경우 톰캣 내장 서버에서 hello-api가 왔음을 Spring에 던진다.
  2. Spring은 hello-api를 찾는다.
  3. 이 때, @ResponseBody가 붙어 있을 경우 뷰 리졸버(viewResolver)에게 던지지 않고 http 응답에 그대로 데이터를 넘긴다.
  4. 하지만 보낼 데이터가 문자가 아닌 객체이기 때문에  Json 방식으로 변형한 객체를 http 응답에 반환한다. (Spring의 디폴트 값)

 


@ResponseBody 를 사용할 경우

- HTTP의 BODY에 문자 내용을 직접 반환
- viewResolver 대신에 HttpMessageConverter 가 동작
- 기본 문자처리: StringHttpMessageConverter
- 기본 객체처리: MappingJackson2HttpMessageConverter

  • 만약 해당 데이터가 단순 문자라면 SpringConverter가 동작, 객체라면 JsonConverter가 동작한다는 뜻
  • byte 처리 등등 기타 여러 HttpMessageConverter가 기본으로 등록되어 있다.

 

 

 

해당 내용들을 정리하면 다음과 같다.

 

 

 

 

 

웹 개발의 3가지 방법

 

01. 정적컨텐츠

- 서버에서 하는 것 없이 파일 그대로 웹 브라우저에 띄우는 방식

 

02. MVC와 템플릿 엔진

- 서버에서 뷰 리졸버(viewResolver)를 통해 HTML을 변환해서 웹 브라우저에 내려주는 방식

 

03. API

- @ResponseBody 를 사용한다.

- 크게 문자/객체를 받을 두가지 상황으로 나눠져 있다.

- 문자를 받는 경우: SpringConverter가 동작하여 HTTP의 BODY에 문자 내용을 직접 반환하는 방식

- 객체를 받는 경우: JsonConverter가 동작하여 Json 방식으로 변형한 객체를 HTTP 응답에 반환하는 방식 

 

 

 

 

 

 

 

참고: 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 (https://inf.run/PWvM)