2. SpringBoot 입문 - 스프링 웹 개발 기초

2021. 3. 12. 01:28WEB Dev./Spring Boot 입문

스프링 웹 개발 기초

웹 개발에는 크게 3가지 방법이 있다.

  • 정적 컨텐츠
    > 파일을 그대로 웹 브라우저에 보여주는 것
  • MVC와 Template Engine
    > Template Engine? Ex, JSP, PHP, Thymeleaf, Pug ...
    > HTML을 그냥 보여주는 것이 아니라 서버에서 프로그래밍해서 동적으로 바꿔서 보여준다.
  • API
    > 만약 모바일 개발자와 협업을 한다고 하면, 요즘엔 JSON으로 함께 협업한다.
    > 또는 서버끼리 데이터를 주고받는 방식을 API라고도 한다.

이 세 가지 방법에 대해 조금 더 자세하게 알아보자.

 

정적 컨텐츠

스프링 부트는 자동으로 정적 컨텐츠 기능을 제공해준다.

docs.spring.io/spring-boot/docs/2.3.1.RELEASE/reference/html/spring-boot-features.html#boot-features-spring-mvc-static-content

 

Spring Boot Features

Graceful shutdown is supported with all four embedded web servers (Jetty, Reactor Netty, Tomcat, and Undertow) and with both reactive and Servlet-based web applications. It occurs as part of closing the application context and is performed in the earliest

docs.spring.io

 

프로젝트에서 /src/main/resources/static에 아무 파일이나 만들어보자

 

<!DOCTYPE HTML>
<html>
<head>
   <title>static content</title>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
정적 컨텐츠 입니다.
</body>
</html>

localhost:8080/hello-static.html 로 접속하면 위 코드의 내용이 그대로 출력되는 것을 확인할 수 있다.

 

 

정적 컨텐츠 원리

  • 웹 브라우저에서 localhost:8080/hello-static.html로 접속
  • 내장 톰캣 서버가 요청을 받는다.
  • 스프링 컨테이너에서는 먼저 controller에서 hello-static이 있는지 찾아본다. (즉, controller가 먼저 우선순위를 갖는다)
  • 그 다음에 컨테이너에서는 내부에 있는 resources로 접근한다.

MVC와 Template Engine

MVC; Model, View, Controller

 

과거에는 Controller와 View가 따로 분리되지 않았다. JSP에서는 View에 모든 걸 다 했었다. (Model1 방식)

이렇게 개발하면 특정 파일에 많은 코드를 올려놓게 되므로 유지보수를 하기 힘들다. 따라서 현재는 이러한 방식을 채택하지 않는다.

 

Controller

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

외부에서 파라미터를 받는 내용이다.

localhost:8080/hello-mvc?name="파라미터 값"

Controller에서는 파라미터로 받은 값을 model로 view에 전달한다.

 

View

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

 

View는 화면에 관련된 일만 하고, Business Logic 등 서버 뒷 단에 관련된 내용은 Controller에서 처리한다.

Controller에서는 필요한 logic을 처리하고 Model에 필요한 내용을 담아서 View로 전달해준다.

 

위의 내용을 그림으로 다시 확인해보자

MVC Pattern

  • 웹 브라우저에서 localhost:8080/hello-mvc를 넘기면 내장 톰캣 서버를 거친다.
  • 내장 톰캣 서버는 이를 스프링 컨테이너에 전달한다. 컨테이너는 helloController에 Mapping 되어 있는 것을 확인한다.
  • return 값(hello-spring)과 model을 스프링에게 전달한다.
  • 스프링은 viewResolver가 동작하게 한다. viewResolver는 view를 찾아서 템플릿 엔진과 연결하는 역할을 한다.
  • 템플릿 엔진은 렌더링해서 변환한 HTML을 웹 브라우저에 반환해준다.
  • MVC 정리
    > 클라이언트가 요청하는 view를 찾는다 → 템플릿 엔진을 통해 화면을 렌더링 → 웹 브라우저에 리턴

API(Application Programming Interface)

정적 컨텐츠를 제외하면 두 가지 방식만 기억하면 된다.

1) html로 브라우저에 전달하냐

2) API로 데이터에 바로 전달하냐

 

Example 1.

// API 방식
@GetMapping("hello-string")
@ResponseBody   // http에 있는 바디 파트를 의미. 바디 파트에 해당 데이터를 직접 넣겠다는 의미
public String helloString(@RequestParam("name") String name) {
	return "Hello " + name;
}

@ResponseBody?

HTTP 통신 프로토콜(Application Layer)에는 Header와 Body 부분으로 이루어져있다. @ResponseBody 어노테이션은 HTTP의 응답 Body 부분에 데이터를 직접 넣어주는 역할을 한다.

API 방식을 쓰면 view를 통해서 데이터를 전달하는게 아니라 이 데이터 자체를 그대로 보낸다.

 

Example 2.

@Controller
public class HelloController {

	@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;
        } 
    }
}

static 클래스를 만들면 클래스 안에서 또 클래스를 만들 수 있다.

위의 코드로 브라우저에서 확인하면

{"name" : "파라미터 Value" }

이런식으로 JSON 형태로 보내지게 된다. 최근 들어서는 모든 웹 개발은 JSON으로 데이터를 주고받는 추세이다.

 

JSON?

JavaScript Object Notation

> {키-값}의 쌍으로 이루어진 데이터 객체를 전달하기 위한 표준이다.

 

ResponseBody 작동 원리

Getter, Setter.. Java Bean 규약이라고 한다. private으로 된 변수를 다른 파일에서 접근하기 힘들기 때문에 Getter, Setter 등을 통해 접근하게 한다. 또는 Property 접근 방식이라고도 한다.

 

  • 웹 브라우저에서 /hello-api로 접근한다. 
  • 내장 톰캣 서버에서 /hello-api가 왔다고 스프링에게 알려준다.
  • 스프링은 hello-api가 있음을 확인한다.
  • 만약 @ResponseBody 어노테이션이 붙어있다면, HTTP 응답에 그대로 넘겨야한다고 판단한다.
  • Example 1. 처럼 문자 형태의 리턴이었다면 그냥 HTTP 응답으로 넘겼을텐데 Example 2.의 경우처럼 객체를 리턴하는 경우도 있다.
  • 객체를 리턴해야 한다면 JSON 형태로 데이터를 만들어서 HTTP 응답에 반환한다. (HttpMessageConverter의 역할)
    (객체가 아니었다면 기존 MVC 형태처럼 viewResolver에게 전달했을 것이다.)

    기본 문자처리: StringHttpMessageConverter
    기본 객체처리: MappingJackson2HttpMessageConverter
    (객체를 JSON으로 변환해주는 라이브러리: Jackson, GSON)

공부를 하다가 @Controller와 @RestController의 차이점에 대해서 직접 경험을 통해 구분하게 되었다.

일반적으로 Spring framework과 thymeleaf 엔진만 이용해서 @Controller로 view를 전달하는데에 무리가 없었다. 하지만 객체를 전달해야 하는 경우가 생겼다.

아무리 객체를 리턴해도 에러페이지만 발생했고 원인을 알기 힘들었다. 위에 API Example2에서 확인할 수 있듯이 @Controller에서 객체를 전달하려면 @ResponseBody와 함께 이용해야 한다.

하지만 @RestController를 이용하면 이 두 어노테이션의 역할을 모두 해준다.


 

Ref.

Request 할 때, 내가 받고 싶은 포맷이 있다. 이럴 땐 Accept 헤더를 이용한다. 그럼 그 포맷의 converter를 통해 요청된다.


TIP (Mac 기준)

Cmd + P: 파라미터 정보를 확인할 수 있다.

Cmd + shift + Enter: ;와 줄바꿈을 한 번에 끝내준다.

Cmd + N: Getter, Setter, Contructor 등 생성


출처: '스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술'

Java: 11

IDE : IntelliJ