SpringMVC 전체 구조
DispatcherServlet
- SpringMVC 의 프런트 컨트롤러
- HttpServlet
을 상속받아 사용하고, 서블릿으로 동작
- 스프링 부트가 DispatcherServlet
을 서블릿으로 자동 등록하며 모든 경로 (urlParrerns
) 에 대하여 매핑
SpringMVC 구조
핸들러 매핑 | ||||||
↑ ① 핸들러 조회 ↑ |
핸들러 어댑터 목록 ↗ ② 핸들러 어댑터 조회 ↗ |
|||||
클라이언트 | HTTP 요청 → → → → |
Dispatcher Servlet |
③ handle(handler) → → → → → → ← ← ← ← ← ← ⑤ModelAndView 반환 |
핸들러 어댑터 |
④ 핸들러 호출 → → → → |
핸들러 (컨트롤러) |
↓ ⑧ render(model) 호출 ↓ |
↖ ↘ ⑥ ViewResolver 호출 ↖ ↘ ↖ ⑦ View 반환 ViewResolver |
|||||
HTML 응답 ← ← ← ← |
View |
1. 핸들러 조회 : 핸들러 매핑을 통해 요청 URL 에 매핑된 핸들러를 조회
2. 핸들러 어댑터 조회 : 핸들러를 실행할 수 있는 핸들러 어댑터를 조회
3. 핸들러 어댑터 실행 : 핸들러 어댑터를 실행
4. 핸들러 실행 : 핸들러 어댑터가 실제 핸들러를 실행
5. ModelAndView 반환 : 핸들러 어댑터는 핸들러가 반환하는 정보를 ModelAndView 로 변환하여 반환
6. ViewResolver 호출 : 뷰 리졸버를 찾고 실행
( JSP 의 경우, InternalResourceViewResolver
자동 등록 )
7. View 반환 : 뷰 리졸버가 뷰 논리 이름을 물리 이름으로 바꾸고, 렌더링 역할을 담당하는 View 객체 반환
( JSP 의 경우, InternalResourceView(JstlView) 반환, 내부에
forward()` 로직 )
8. 뷰 렌더링 : 뷰를 통해 뷰를 렌더링
핸들러 매핑 / 핸들러 어댑터
HandlerMapping
0 = RequestMappingHandlerMapping
: 애노테이션 기반의 컨트롤러인 @RequestMapping 에서 사용
1 = BeanNameUrlHandlerMapping
: 스프링 빈 이름으로 핸들러 찾음
( 생략 )
HandlerAdapter
0 = RequestMappingHandlerAdapter
: 애노테이션 기반의 컨트롤러인 @RequestMapping 에서 사용
1 = HttpRequestHandlerAdapter
: HttpRequestHandler 처리
2 = SimpleControllerHandlerAdapter
: Controller 인터페이스 (애노테이션 X, 과거에 사용) 처리
( 생략 )
HandlerAdapter 의 supports()
를 순서대로 호출하여 핸들러 어댑터를 조회한다.
Controller 인터페이스 (과거에 사용)
@Component("/springmvc/old-controller")
public class OldController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
return null;
}
}
/springmvc/old-controller
이름으로 스프링 빈이 등록되었다.
빈 이름으로 URL 을 매핑한다.
1. HandlerMapping 을 순서대로 실행하여 핸들러를 찾는다.
2. 빈 이름으로 핸들러를 찾는 BeanNameUrlHandlerMapping
이 실행에 성공하고 핸들러를 반환한다.
3. HandlerAdapter 의 supports()
를 호출하여 핸들러 어댑터를 찾는다.
4. 찾은 SimpleControllerHandlerAdapter
로 핸들러를 실행하고, 결과를 반환한다.
HttpRequestHandler 인터페이스 (과거에 사용)
@Component("/springmvc/request-handler")
public class MyHttpRequestHandler implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
/springmvc/request-handler
이름으로 스프링 빈이 등록되었다.
빈 이름으로 URL 을 매핑한다.
1. HandlerMapping 을 순서대로 실행하여 핸들러를 찾는다.
2. 빈 이름으로 핸들러를 찾는 BeanNameUrlHandlerMapping
이 실행에 성공하고 핸들러를 반환한다.
3. HandlerAdapter 의 supports()
를 호출하여 핸들러 어댑터를 찾는다.
4. 찾은 HttpRequestHandlerAdapter
로 핸들러를 실행하고, 결과를 반환한다.
@RequestMapping (실무)
실무에서 사용하는 애노테이션 기반의 컨트롤러를 지원하는 매핑과 어댑터인
RequestMappngHandlerMapping
과 RequestMappingHandlerAdapter
를 가장 많이 사용한다.
- @Controller
: 내부의 @Component 애노테이션으로 인해 컴포넌트 스캔의 대상이 되어 스프링 빈으로 등록
: 스프링 MVC 에서 애노테이션 기반 컨트롤러로 인식
- @RequestMapping
: 요청 정보를 매핑하여 해당 URL 이 호출되면 메서드가 호출된다.
(애노테이션 기반이기 때문에 메서드 이름 임의로 지정 가능)
@Controller
public class SpringMemberFormControllerV1 {
@RequestMapping("/springmvc/v1/members/new-form")
public ModelAndView process() {
return new ModelAndView("new-form");
}
}
1. HandlerMapping 을 순서대로 실행하여 핸들러를 찾는다.
2. RequestMappingHandlerMapping
이 실행에 성공하여 @RequestMapping("url")
이 설정된 컨트롤러를 찾아 반환한다.
4. HandlerAdapter 의 supprots()
를 호출하여 핸들러 어댑터를 찾는다.
5. 찾은 RequestMappingHandlerAdpater
로 컨트롤러의 @RequestMapping
메서드를 실행하고, 결과를 반환한다.
애노테이션 기반 컨트롤러
특징
- 컨트롤러 통합
: @RequestMapping 는 클래스 단위가 아닌 메서드 단위에 적용되었기 때문에, 유연하게 하나로 통합할 수 있다.
- Model 을 사용한 데이터 관리
: Model 객체를 이용하여 데이터를 저장/조회 기능을 제공한다.
- ViewName 직접 반환
: ModelAndView 객체를 반환하는 것이 아니라, String 형식의 뷰의 논리 이름을 반환해도 된다.
RequestMappingHandlerAdater
애노테이션 기반의 컨트롤러의 @RequestMapping
을 처리하는 핸들러 어댑터 구조를 자세히 살펴보자
↗ |
① ArgumentResolver |
|||
DispatcherServlet | → → → | RequestMapping HandlerAdapter |
→ → → ② → → → | 핸들러 (컨트롤러) |
↖ |
ReturnValueHandler ③ |
↙ |
① 컨트롤러의 파라미터, 애노테이션 정보를 기반으로 전달 데이터 생성
ex. HttpServletRequest
, Model
, @RequestParam
, @ModelAttribute
, @ReuqestBody
, HttpEntity
등
② 호출
③ 컨트롤러의 반환값을 변환
ex. ModelAndView
, @ResponseBody
, HttpEntity
등
ArgumentResolver (HandlerMethodArgumentResolver)
- 다양한 방식의 컨트롤러의 파라미터를 생성하는 역할
- 인터페이스로 제공하여 확장 가능
ReturnValueHandler (HandlerMethodReturnValueHandler)
- 컨트롤러가 반환한 데이터를 적절한 HTTP 응답 형태로 변환하는 역할
- 인터페이스로 제공하여 확장 가능
HTTP 메시지 컨버터 (HttpMessageConverter)
- ArgumentResolver
와 ReturnValueHandler
가 데이터를 변환할 때 핵심적인 변환 기능을 제공
- 인터페이스로 제공하여 확장 가능
HTTP 메시지 컨버터
HTTP 요청 : @RequestBody
, HttpEntity
, RequestEntity
HTTP 응답 : @ResponseBody
, HttpEntity
, ResponseEntity
사용 시에 HTTP 메시지 컨버터가
요청/응답 데이터의 타입
과 미디어 타입(Content-Type, Accept)
을 확인하여 변환한다.
기본 메시지 컨버터
0 = ByteArrayHttpMessageConverter
: byte 처리
1 = StringHttpMessageConverter
: 기본 문자 처리
2 = MappingJackson2HttpMessageConverter
: 기본 객체 처리
( 생략 )
대상 클래스 타입, 미디어 타입을 체크해서 사용여부를 결정한다.
ByteArrayHttpMessageConverter
- byte[ ] 데이터를 처리
- 클래스 타입 : byte[ ]
- 미디어 타입 : */*
ex. 요청 @RequestBody byte[] data
ex. 응답 @ResponseBody return byte[]
쓰기 미디어타입 application/octet-stream
로 자동 설정
StringHttpMessageConverter
- String 문자로 데이터를 처리
- 클래스 타입 : String
- 미디어 타입 : */*
ex. 요청 @RequestBody String data
ex. 응답 @ResponseBody return "ok"
쓰기 미디어타입 text/plain
로 자동 설정
MappingJackson2HttpMessageConverter
- application/json 처리
- 클래스 타입 : 객체
or HashMap
- 미디어 타입 : application/json
관련
ex. 요청 @RequestBody HelloData data
ex. 응답 @ResponseBody return helloData
쓰기 미디어타입 application/json
관련으로 자동 설정
HTTP 요청 데이터 읽기
1. HTTP 요청이 오고, 컨트롤러에서 @RequestBody
, HttpEntity
, RequestEntity
파라미터를 사용한다.
2. 메시지 컨버터가 메시지를 읽을 수 있는지 확인하기 위해 canRead()
를 호출한다.
> 대상 클래스 타입을 지원하는가 ?
ex. @RequestBody
의 대상 클래스 (byte[]
, String
, HelloData
)
> HTTP 요청의 Content-Type 미디어 타입을 지원하는가 ?
ex. text/plain
, application/json
, */*
3. 위 조건으로 canRead()
를 만족하면, read()
를 호출하여 객체를 생성하고, 반환한다.
HTTP 응답 데이터 생성
1. 컨트롤러에서 @ResponseBody
, HttpEntity
, ResponseEntity
로 값이 반환된다.
2. 메시지 컨버터가 메시지를 쓸 수 있는지 확인하기 위해 canWrite()
를 호출한다.
> 대상 클래스 타입을 지원하는가 ?
ex. return 의 대상 클래스 (byte[]
, String
, HelloData
)
> HTTP 요청의 Accept 미디어 타입을 지원하는가 ?
ex. text/plain
, application/json
, */*
3. 위 조건으로 canWrite()
를 만족하면, write()
를 호출하여 HTTP 응답 메시지 바디에 데이터를 생성한다.
출처 | 스프링 MVC 1(김영한) - 인프런
'💠프로그래밍 언어 > Java' 카테고리의 다른 글
[Spring] SpringMVC 의 요청 매핑과 요청/응답 메시지 기능 ! (0) | 2025.03.20 |
---|---|
[심화] 로깅은 무엇일까 ?? (0) | 2025.03.19 |
[Spring] 리팩토링하며 점진적으로 Spring MVC 프레임워크 만들기 !! (0) | 2025.03.14 |
[Spring] MVC 패턴이 등장하게 된 이유 !! (feat. 서블릿, JSP) (1) | 2025.03.14 |
[Spring] 서블릿의 HttpServletRequest 와 HttpServletResponse 란?? (1) | 2025.03.13 |