김영한의 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 강의를 공부하며 작성한 글입니다.
스프링 웹 개발 방식은 3가지로 분류할 수 있다.
└─src
├─main
│ ├─java
│ │ └─com
│ │ └─example
│ │ └─hello_spring
│ │ │ helloSpringApplication.java
│ │ │
│ │ └─Controller
│ │ HelloController.java
│ │
│ └─resources
│ │ application.properties
│ │
│ ├─static
│ │ hello-static.html
│ │ index.html
│ │
│ └─templates
│ hello-template.html
│ hello.html
│
└─test
└─java
└─com
└─example
└─hello_spring
helloSpringApplicationTests.java
스프링 공식 문서에서는 static을 static 디렉토리
에서 제공한다고 적혀있다. 📌 스프링 공식문서 링크
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>
static 폴더
에 hello-static.html
파일을 생성한다.
정적 컨텐츠는 localhost:8080/hello-static.html
이라는 파일경로를 적어줘야 웹브라우저에서 확인이 가능하다.
정적 컨텐츠는 넣어준 정적 파일 그대로 웹브라우저에서 반환이 된다.
그래서 동적 프로그래밍을 할 수는 없다.
(강의 교안의 참고자료를 직접 따라 그렸습니다.)
localhost:8080/hello-static.html
을 입력하면 내장 톰켓 서버
에서 요청을 받고 스프링 컨테이너
에게 넘긴다.Controller
를 우선 살펴본다. hello-static
와 관련(Mapping) 된 Controller가 없다면 다음 단계로 넘어간다.resources 폴더
내부에 있는 static/hello-static.html
을 찾는다. 있다면 웹브라우저에 반환한다.hello-static.html
웹브라우저에서의 hello-static.html
두 코드가 동일한 것을 확인 가능.
예전 Model과 View가 분리되어 있지 않던 개발 방식(Model1 방식)과 달리
요즘에는 MVC 패턴을 이용한 개발이 일반적이다.
Model
Controller
View
HelloController.java
@Controller
public class HelloController {
@GetMapping
public String hello(Model model) {
model.addAttribute("data", "반가워요?!");
return "hello";
}
@GetMapping("hello-mvc")
public String helloMvc(@RequestParam("name") String name, Model model){
model.addAttribute("name", name);
return "hello-template";
}
}
hello-template.html
<html xmlns:th="http://www.thymeleaf.org">
<body>
<p th:text="'hello ' + ${name}">hello! world</p>
</body>
</html>
뷰
이다.웹브라우저에 Controller에서 정의한
localhost:8080/hello-mvc
을 입력해본다.
에러가 발생한다. 왜지?
에러 로그는 다음과 같다.
Required request parameter 'name' for method parameter type String is not present
반드시 넘겨줘야할 파라미터가 넘어오지 않았다는 뜻이다.
따라서 웹브라우저에 파라미터를 넘겨준다.
http GET방식
에서 파라미터를 넘겨주는 방법은 다음과 같다.
localhost:8080/@GetMapping이름
?@RequestParam키값
=입력값
다음과 같이 파라미터를 넘겨준다.
localhost:8080/hello-mvc
?name
=spring!
웹브라우저에 입력한name
=spring!
식이 넘어가면 Controller에서 name
은 입력값인 spring
으로 바뀐다. 바뀐 값은 model
에 담긴다.
hello-template.html
에서의 ${name}
은 model에서 키 값이 name
인 것을 꺼내 해당 키의 값으로 치환한다는 뜻이다. 따라서 화면에서는 hello 뒤에 입력값
이 붙어서 출력된다.
(강의 교안의 참고자료를 직접 따라 그렸습니다.)
localhost:8080/hello-mvc
을 입력하면 내장 톰켓 서버
에서 요청을 받고 스프링 컨테이너
에게 넘긴다.hello-mvc
메서드가 HelloController
와 Mapping된 것을 발견하고 해당 메서드를 호출한다. 이때, return시 이름은 hello-template
, 모델은 name(키값):spring!(밸류)으로 해서 viewResolver
에게 넘겨준다.viewResolver
가 동작해서 http에게 응답으로 돌려줄 뷰(templates/hello-template.html
)를 찾고, 타임리프 템플릿 엔진
에게 넘긴다. 정적 컨텐츠와 템플릿 엔진의 차이
정적 컨텐츠 : Html을 변환하는 과정이 없음
템플릿 엔진 : Html을 변환한 뒤 웹 브라우저에 반환
변환 전 hello-template.html
변환 후 hello-template.html
변환 전과 후의 코드가 다르다.
intellij에서 [Ctrl + Shift + c] 를 통해 Apsolute path를 복사한 뒤 웹 브라우저에 주소를 붙여넣으면 파일을 그대로 전달할 수 있다. 이 방법을 통해 서버를 통하지 않아도 HTML파일의 출력화면을 확인할 수 있다.
다만 서버를 통할 때와 서버를 통하지 않을 때 결과로 출력되는 내용은 조금 다르다.
서버를 통하지 않을 때는 hello! empty가 출력되지만
서버를 통해 웹브라우저와 연결한다면 'hello ' + ${name}
가 치환되어 출력될 것이다.
API를 쓰는 가장 큰 이유는 데이터 전송 때문이다.
HelloController.java
@Controller
public class HelloController {
@GetMapping
public String hello (Model model) {
model.addAttribute("data", "반가워요?!");
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;
}
}
@ResponseBody란?
- http에는
header 부, body 부
가 존재.@ResponseBody
는 body 부에 내용을 직접 넣는다는 의미.
실제 브라우저에 hello-stirng
에 밸류값을 줘서 호출해보면 화면은 MVC방식과 비슷하게 나온다.
하지만 웹브라우저로 전송된 코드에는 html태그
가 하나도 없다.
return
으로 반환한 문자가 그대로 출력되는 것이다.
HelloController.java
@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;
}
}
}
API 방식을 통해 객체를 반환하면 브라우저에서는 JSON
형식의 코드가 출력된다.
JSON
은 {키:밸류}의 구조를 가지고 있다.
html처럼 열고 닫는 구조가 아니기 때문에 html에 비해 단순하고 간단하다.
스프링에서는 @ResponseBody
로 객체를 반환할 때, 기본적으로JSON
을 반환하도록 세팅되어 있다.
static 클래스 Hello의 name
필드는 private
이기 때문에 외부에서 직접 접근할 수 없고 getter, setter를 이용해 접근해야 한다.
(강의 교안의 참고자료를 직접 따라 그렸습니다.)
웹브라우저에서 localhost:8080/hello-api
를 입력하면 내장 톰켓 서버
에서 요청을 받고 스프링 컨테이너
에게 넘긴다.
스프링 컨테이너는 hello-api
메서드가 HelloController
와 Mapping된 것을 발견하고 해당 메서드를 호출한다. @ResponseBody
가 있으므로 http에 대한 응답(return)에 데이터를 바로 넣는다(body에 직접 반환). 단, 데이터가 문자가 아닌 객체일 때는 return시 JSON
방식으로 만들어서 반환한다.
@ResponseBody
를 확인하면 HttpMessageConverter
가 동작한다.템플릿 엔진과 API의 차이
템플릿 엔진
: 뷰(템플릿)을 조작하는 방식. return 발생 시viewResolver
동작API
: 뷰 없음. 데이터를 그대로 내려준다. return 발생 시HttpMessageConverter
동작
정적 컨텐츠 : 파일을 그대로 내려준다.
MVC와 템플릿 엔진 :뷰리졸버
가뷰
를 찾고,템플릿 엔진
으로뷰
(HTML)를 랜더링해서 반환
API :HttpMessageConverter
를 통해JSON 형식
으로 객체를 반환
색인
viewResolver
view를 찾아주고 template에 연결시켜주는 기능을 한다.
Jackson, Gson
객체를 Json으로 변환시켜주는 라이브러리