1. MVC - 구조 이해
MVC 뜻
MVC (모델-뷰-컨트롤러) 는 사용자 인터페이스, 데이터 및 논리 제어를 구현하는데 널리 사용되는 소프트웨어 디자인 패턴이다. 소프트웨어의 비즈니스 로직과 화면을 구분하는데 중점을 두고 있다. 이러한 "관심사 분리" 는 더나은 업무의 분리와 향상된 관리를 제공한다.
DispatcherServlet 구조 살펴보기

- 핸들러 조회 : 핸들러 매핑을 통해 요청 URL에 매핑된 핸들러를 조회
- 핸들러 어댑터 조회 : 핸들러를 처리할 수 있는 어댑터 : 핸들러를 실행할 수 있는 핸들러 어댑터를 조회
- 핸들러 어댑터 실행
- 핸들러 어댑터를 통해 핸들러 실행
- ModelAndView 반환
- 뷰 리졸버를 통해서 뷰 찾기
- View 반환 : 뷰 리졸버는 뷰의 논리 이름을 물리 이름으로 바꾸고, 렌더링 역할을 담당하는 뷰 객체를 반환
- 뷰 렌더링
핸들러 매핑과 핸들러 어댑터
뷰 리졸버
- 스프링 부트는 InternalResourceViewResolver 라는 뷰 리졸버를 자동으로 등록하는데, 이때 application.properties 에 등록한 spring.mvc.view.prefix , spring.mvc.view.suffix 설정 정보를 사용해서 등록.
@Controller
- 스프링이 자동으로 스프링 빈으로 등록 (내부에 @Component 애노테이션이 있어서 컴포넌트 스캔의 대상이 됨)
- 스프링 MVC에서 애노테이션 기반 컨트롤러로 인식
@RequestMapping
- 요청 정보를 매핑
- 해당 URL이 호출되면 이 메서드가 호출
- 애노테이션을 기반으로 동작하기 때문에, 메서드의 이름은 임의로 지으면 됨
ModelAndView
Model 파라미터
ViewName 직접 반환
@RequestParam 사용
- 스프링은 HTTP 요청 파라미터를 @RequestParam 으로 받을 수 있음
- @RequestParam("username") 은 request.getParameter("username") 와 거의 같은 코드라 생각하면 됨
- GET 쿼리 파라미터, POST Form 방식을 모두 지원
@RequestMapping @GetMapping, @PostMapping
- @RequestMapping 은 URL만 매칭하는 것이 아니라, HTTP Method도 함께 구분할 수 있음.
- 예를 들어서 URL이 /new-form 이고, HTTP Method가 GET인 경우를 모두 만족하는 매핑을 하려면 다음과 같이 처리하면 됨.
@RequestMapping(value = "/new-form", method = RequestMethod.GET)
- 이를 @GetMapping, @PostMapping으로 더욱 편리하게 사용 가능함
@RestController
- @Controller 는 반환 값이 String 이면 뷰 이름으로 인식됨
- @RestController 는 반환 값으로 뷰를 찾는 것이 아니라, HTTP 메시지 바디에 바로 입력
@RequestMapping("hello-basic")
- /hello-basic URL 호출이 오면 이 메서드가 실행되도록 매핑
- 대부분의 속성을 배열[] 로 제공하므로 다중 설정이 가능하다. {"/hello-basic", "/hello-go"}
-> 다른 url이지만 스프링이 같은 것으로 매핑해줌
HTTP 메서드
- @RequestMapping 에 method 속성으로 HTTP 메서드를 지정하지 않으면 HTTP 메서드와 무관하게 호출.
-> 따라서 모두 허용 GET, HEAD, POST, PUT, PATCH, DELETE
PathVariable(경로 변수) 사용
- 변수명이 같으면 생략 가능
- ex) @PathVariable("userId") String userId -> @PathVariable userId
@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable("userId") String data) {
return "ok";
}
- @RequestMapping 은 URL 경로를 템플릿화 할 수 있는데, @PathVariable 을 사용하면 매칭 되는 부분을 편리하게 조회할 수 있음.
PathVariable 사용 - 다중
@GetMapping("/mapping/users/{userId}/orders/{orderId}")
public String mappingPath(@PathVariable String userId, @PathVariable Long
orderId) {
return "ok";
}
클라이언트에서 서버로 요청 데이터를 전달할 때는 주로 다음 3가지 방법을 사용.
1. GET - 쿼리 파라미터
- /url?username=hello&age=20
- 메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달
- ex) 검색, 필터, 페이징등에서 많이 사용하는 방식
GET 쿼리 파리미터 전송 방식이든, POST HTML Form 전송 방식이든 둘다 형식이 같으므로 구분없이 조회할 수 있음.
이것을 간단히 요청 파라미터(request parameter) 조회라 함.
- HTTP 요청 파라미터 - @RequestParam
스프링이 제공하는 @RequestParam 을 사용하면 요청 파라미터를 매우 편리하게 사용할 수 있음.
- View 조회를 무시하고, HTTP message body에 직접 해당 내용 입력
- HTTP 요청 파라미터 - @ModelAttribute
실제 개발을 하면 요청 파라미터를 받아서 필요한 객체를 만들고 그 객체에 값을 넣어주어야 하는데 @ModelAttribute는 이를 자동화해줌
-
- 스프링MVC는 @ModelAttribute 가 있으면 다음을 실행
-
-
- 요청 파라미터의 이름으로 HelloData 객체의 프로퍼티를 찾고 해당 프로퍼티의 setter를 호출해서 파라미터의 값을 입력(바인딩)
-
- ex) 파라미터 이름이 username 이면 setUsername() 메서드를 찾아서 호출하면서 값을 입력
-
@RequestParam과 @ModelAttribute는 생략 가능함
-
String, int 같은 단순 타입 = @RequestParam
-
argument resolver 로 지정해둔 타입 외 = @ModelAttribute
- POST - HTML Form
-
content-type: application/x-www-form-urlencoded
-
메시지 바디에 쿼리 파리미터 형식으로 전달 username=hello&age=20
-
ex) 회원 가입, 상품 주문, HTML Form 사용
-
스프링 MVC는 다음 파라미터를 지원
-
HttpEntity: HTTP header, body 정보를 편리하게 조회
-
-
- 요청 파라미터를 조회하는 기능과 관계 없음 @RequestParam X, @ModelAttribute X
-
HttpEntity는 응답에도 사용 가능
-
-
-
-
HttpEntity 를 상속받은 다음 객체들도 같은 기능을 제공
-
RequestEntity
-
- HttpMethod, url 정보가 추가, 요청에서 사용
-
ResponseEntity
-
- HTTP 상태 코드 설정 가능, 응답에서 사용
-
@RequestBody
- 메시지 바디 정보를 직접 조회(@RequestParam X, @ModelAttribute X)
- HttpMessageConverter 사용 -> StringHttpMessageConverter 적용 *
- @ResponseBody
- 메시지 바디 정보 직접 반환(view 조회X)
- HttpMessageConverter 사용 -> StringHttpMessageConverter 적용
요청 파라미터 vs HTTP 메시지 바디
요청 파라미터를 조회하는 기능: @RequestParam , @ModelAttribute HTTP 메시지 바디를 직접 조회하는 기능: @RequestBody
- HTTP message body에 데이터를 직접 담아서 요청
- HTTP API에서 주로 사용, JSON, XML, TEXT - 데이터 형식은 주로 JSON 사용
- POST, PUT, PATCH
@RequestBody 객체 파라미터
-
@RequestBody HelloData data
-
@RequestBody 에 직접 만든 객체를 지정할 수 있음
-
HttpEntity , @RequestBody 를 사용하면 HTTP 메시지 컨버터가 HTTP 메시지 바디의 내용을 우리가 원하는 문자나 객체 등으로 변환해줌
-
HTTP 메시지 컨버터는 문자 뿐만 아니라 JSON도 객체로 변환해줌
// @RequestBody는 생략 불가능
HTTP 응답 - 정적 리소스, 뷰 템플릿
스프링(서버)에서 응답 데이터를 만드는 방법은 크게 3가지
- 정적 리소스
웹 브라우저에 정적인 HTML, css, js를 제공할 때는, 정적 리소스를 사용
src/main/resources/static
다음 경로에 파일이 들어있으면
src/main/resources/static/basic/hello-form.html
웹 브라우저에서 다음과 같이 실행하면 됨
http://localhost:8080/basic/hello-form.html
정적 리소스는 해당 파일을 변경 없이 그대로 서비스하는 것
-
뷰 템플릿 사용
웹 브라우저에 동적인 HTML을 제공할 때는 뷰 템플릿을 사용
뷰 템플릿을 거쳐서 HTML이 생성되고, 뷰가 응답을 만들어서 전달하는 것
뷰 템플릿 경로
src/main/resources/templates
뷰 템플릿 생성
src/main/resources/templates/response/hello.html
- String을 반환하는 경우 - View or HTTP 메시지
@ResponseBody 가 없으면 response/hello 로 뷰 리졸버가 실행되어서 뷰를 찾고, 렌더링
- @ResponseBody 가 있으면 뷰 리졸버를 실행하지 않고, HTTP 메시지 바디에 직접 response/hello 라는 문자가 입력
- Thymeleaf 스프링 부트 설정
build.gradle에 다음과 같음 라이브러리 추가
`implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'`
- HTTP 메시지 사용
HTTP API를 제공하는 경우에는 HTML이 아니라 데이터를 전달해야 하므로, HTTP 메시지 바디에 JSON 같은 형식으로 데이터를 실어 보냄
- @RestController
@Controller 대신에 @RestController 애노테이션을 사용하면, 해당 컨트롤러에 모두 @ResponseBody 가 적용됨. 따라서 뷰 템플릿을 사용하는 것이 아니라, HTTP 메시지 바디에 직접 데이터를 입력. 이름 그대로 Rest API(HTTP API)를 만들 때 사용하는 컨트롤러임.
HTTP 메시지 컨버터
스프링 MVC는 다음의 경우에 HTTP 메시지 컨버터를 적용함.
- HTTP 요청: @RequestBody , HttpEntity(RequestEntity) ,
- HTTP 응답: @ResponseBody , HttpEntity(ResponseEntity) ,
HTTP 메시지 컨버터는 HTTP 요청, HTTP 응답 둘 다 사용됨
- canRead() , canWrite() : 메시지 컨버터가 해당 클래스, 미디어타입을 지원하는지 체크
- read() , write() : 메시지 컨버터를 통해서 메시지를 읽고 쓰는 기능
스프링 부트 기본 메시지 컨버터
0 = ByteArrayHttpMessageConverter
1 = StringHttpMessageConverter
2 = MappingJackson2HttpMessageConverte
-
ByteArrayHttpMessageConverter : byte[] 데이터를 처리
-
- 클래스 타입: byte[] , 미디어타입: / ,
요청 예) @RequestBody byte[] data
응답 예) @ResponseBody return byte[] 쓰기 미디어타입 application/octet-stream
-
StringHttpMessageConverter : String 문자로 데이터를 처리
-
- 클래스 타입: String , 미디어타입: /
요청 예) @RequestBody String data
응답 예) @ResponseBody return "ok" 쓰기 미디어타입 text/plain
-
MappingJackson2HttpMessageConverter : application/json
-
- 클래스 타입: 객체 또는 HashMap , 미디어타입 application/json 관련
요청 예) @RequestBody HelloData data
응답 예) @ResponseBody return helloData 쓰기 미디어타입 application/json 관련
-
HTTP 요청 데이터 읽기
HTTP 요청이 오고, 컨트롤러에서 @RequestBody , HttpEntity 파라미터를 사용. 메시지 컨버터가 메시지를 읽을 수 있는지 확인하기 위해 canRead() 를 호출.
canRead() 조건을 만족하면 read() 를 호출해서 객체 생성하고, 반환
-
HTTP 응답 데이터 생성
컨트롤러에서 @ResponseBody , HttpEntity 로 값이 반환
메시지 컨버터가 메시지를 쓸 수 있는지 확인하기 위해 canWrite() 를 호출
canWrite() 조건을 만족하면 write() 를 호출해서 HTTP 응답 메시지 바디에 데이터를 생성한다.
요청 매핑 헨들러 어뎁터 구조
HTTP 메시지 컨버터는 핸들러 어댑터 쪽에서 사용됨.

- 요청의 경우 @RequestBody 를 처리하는 ArgumentResolver 가 있고, HttpEntity 를 처리하는 ArgumentResolver 가 있음.
이 ArgumentResolver 들이 HTTP 메시지 컨버터를 사용해서 필요한 객체를 생성하는 것.
- 응답의 경우 @ResponseBody 와 HttpEntity 를 처리하는 ReturnValueHandler 가 있음.
여기에서 HTTP 메시지 컨버터를 호출해서 응답 결과를 만듦.
정리가 잘 된 글이네요. 도움이 됐습니다.