스프링 MVC
1. 스프링 MVC
M(모델)
- 평범한 자바 객체
- 도메인 객체 또는 DTO로 화면에 전달할 또는 화면에서 전달 받은 데이터를 담고 있는 객체
V(뷰)
- HTML, JSP, 타임리프..
- 데이터를 보여주는 역할. 다양한 형태로 보여줄 수 있음 (HTML, JSON, XML)
C(컨트롤러)
- 스프팅 @MVC
- 사용자의 입력을 받아 모델 객체의 데이터를 변경하거나, 모델 객체를 뷰에 전달
- 입력 값 검증, 입력 받은 데이터를 모델 객체로 변경, 변경된 모델 객체를 뷰에 전달
2. MVC 패턴의 장점
동시 다발적 개발
높은 결합도
낮은 의존도
개발 용이성
한 모델에 대한 여러 형태의 뷰를 가질 수 있음
3. MVC 패턴의 단점
코드 네비게이션이 복잡함
코드 일관성 유지에 노력이 필요함
높은 학습 곡선
서블릿
1. 서블릿 애플리케이션
서블릿
- 자바EE는 웹 애플리케이션 개발용 스펙과 API를 제공
- 요청 당 쓰레드를 만들거나, 풀에서 가져다가 사용
- HttpServlet
서블릿 장점
- 빠르다
- 플랫폼 독립적
- 보안
- 이식성
서블릿 컨테이너
- 톰켓, 제티, 언더토
- 서블릿 스펙(웹 애플리케이션 개발 스펙과 API)을 준수하는 것들
- 세션 관리
- 네트워크 서비스
- 서블릿 생명주기 관리 (init, destroy)
2. 서블릿 리스너와 서블릿 필터
서블릿 리스너
- 웹 애플리케이션에서 발생하는 주요 이벤트를 감지하고 각 이벤트에 특별한 작업이 필요한 경우에 사용할 수 있다.
- 서블릿 컨텍스트 수준의 이벤트, 세션 수준의 이벤트
서블릿 필터
- 들어온 요청을 서블릿으로 보내고, 또 서블릿이 작성한 응답을 클라이언트로 보내기 전에 특별한 처리가 필요한 경우에 사용할 수 있음
- 체인 형태의 구조
3. 서블릿에서 스프링에서 제공하는 IoC 컨테이너 연동하기
1) spring-mvc 의존성 추가
2) ContextLoaderListener 추가
- Application Context를 만듬.
- 서블릿 생명주기에 맞추어 Application Context가 실행되도록 함
3) 스프링 설정 파일 생성 및 위치 설정
- Application Context를 만들기 위해서는 스프링 설정 파일 필요
4. 서블릿에 스프링 MVC 적용하기
Servlet에서는 각 url 마다 서블릿을 매핑해줘야 함 -> 설정 코드가 길어지고 불편
따라서, 모든 요청을 FrontController가 받고, 핸들러에게 dispatch하는 방식으로 해결 가능
스프링이 이러한 것을 구현했음 (DispathcherServlet - 스프링MVC에서 가장 핵심적인 클래스)
웹 설정 없는 Application Context와 웹 설정이 들어간 Application Context 를 계층적으로 구현함
Service 와 같은 것은 모든 곳에서 사용 가능하도록 하기 위해
(경우에 따라 설정하는 것으로, 굳이 계층적으로 구현하지 않고 모든 설정이 들어가도록 해도 됨 -> 최근에는 더더욱 계층적으로 구현하지 않음)
(계층적으로 구현하지 않는다면 위의 3번 과정 삭제 후 진행)
1) DispathcherServlet 을 추가
2) 위와 같이 설정 파일 생성 및 위치 설정
3) 서블릿 매핑 설정 (/app/*)
4) Controller 작성
스프링 부트와 다른 점
- 이러한 방식은 서블릿 컨테이너가 먼저 작동하고 서블릿 애플리케이션이 동작
- 스프링 부트는 스프링 부트 어플리케이션이 먼저 작동하고, 내부적으로 서블릿 컨테이너가 동작
5. DispatcherServlet
HandlerMapping : 핸들러를 찾아주는 인터페이스
HandlerAdapter : 핸들러를 실행하는 인터페이스
HandlerExceptionResolver
ViewResolver
동작 순서
1. 요청을 분석한다. (로케일, 테마, 멀티파트 등)
2. (핸들러 매핑에게 위임하여) 요청을 처리할 핸들러를 찾는다.
3. (등록되어 있는 핸들러 어댑터 중에 ) 해당 핸들러를 실행할 수 있는 "핸들러 어댑터"를 찾는다.
4. 찾아낸 "핸들러 어댑터"를 사용해서 핸들러의 응답을 처리한다.
4-1) 핸들러의 리턴 값을 보고 어떻게 처리할 지 판단한다.
- ViewResolver가 뷰 이름에 해당하는 뷰를 찾아서 모델 데이터를 랜더링한다.
- @ResponseEntity가 있다면 Converter를 사용해서 응답 본문을 만든다.
5. (부가적으로) 예외가 발생했다면, 예외 처리 핸들러에 요청 처리를 위임한다.
6. 최종적으로 응답을 보낸다.