티스토리 뷰
MVC
1. MVC
- Model-View-Controller
- Model: 뷰가 렌더링하는데 필요한 데이터 ex) 사용자가 요청한 상품 목록, 주문 내역
- View: 실제로 보이는 부분으로, 모델을 사용해 렌더링한다. 뷰는 JSP, JSF, PDF, XML 등으로 결과를 표현한다.
- Controller: 사용자의 액션에 응답하는 컴포넌트. 모델을 업데이트하고 다른 액션을 수행한다.
2. MVC Model1
요청을 JSP가 받는다. JSP에서 뷰와 컨트롤러가 구현된다. bean을 이용하여 데이터를 가져온다.
Model1은 클라이언트로부터 요청이 들어오면 JSP가 요청받아 처리하면서 동시에 뷰의 역할도 같이 한다.
구현이 쉽지만 유지보수가 어렵다.
3. MVC Model2
뷰는 JSP, 컨트롤러는 서블릿으로 작성된다. 클라이언트의 요청을 (서블릿으로 구현된) 컨트롤러가 받는다.
서블릿이 bean을 이용하여 데이터를 가져오고, 결과를 JSP를 통해 보여준다.
-서블릿: 요청과 데이터를 처리하는 컨트롤러 역할
-JSP: 모델의 결과를 보여주는 뷰 역할
Model2는 역할 구분이 확실하기 때문에 설계가 Model1보다 어렵지만, 유지보수가 수월하다.
4. MVC Model2 발전형태
모든 요청을 프론트 컨트롤러라고 하는 서블릿 클래스가 받는다. 요청만 받고 실제 일은 컨트롤러 클래스에 위임한다.
컨트롤러 클래스는 핸들러 클래스라고도 한다. 컨트롤러는 bean 등을 이용해 결과를 만들어내고, 결과를 모델에 담아 프론트 컨트롤러에 보낸다.
프론트 컨트롤러는 알맞은 뷰에게 모델을 전달하고 결과를 출력한다.
https://www.edwith.org/boostcourse-web/lecture/16762/
https://opentutorials.org/module/3569/21219
SPRING MVC
1. Spring MVC 설계구조 (Model2)
https://www.edwith.org/boostcourse-web/lecture/16763/
- 1. DispatcherServlet(프론트 컨트롤러): 사용자의 모든 요청을 받는다.
- 2. HandlerMapping: 요청에 가장 적합한 컨트롤러를 검색한다.
- 어떤 요청에 어떤 컨트롤러가 동작할지는 xml파일이나 java config 어노테이션으로 설정한다. (bean을 이용하여)
- 3. HandlerAdapter: 해당 컨트롤러에 가장 적합한 메소드를 검색해 컨트롤러를 실행한다.
- 4. Controller: 요청을 처리한 후 결과를 리턴한다. HandlerAdapter가 ModelAndView 객체로 변환한다. ModelAndView 객체에는 응답에 필요한 데이터정보와 뷰정보(JSP파일)이 담겨있다.
- 5. view name도 함께 전달
- 6. View Resolver: view name으로 처리결과를 출력할 view(jsp)를 찾는다.
- 7. View: 응답을 생성한다.
2. DispatcherServlet을 중심으로 #DispatcherServlet
아래 그림 전부가 Layered Architecture의 Presentation Layer에 해당
Layered Architecture
1. Layered Architecture
레이어드 아키텍처에서 각 레이어는
하나의 레이어는 자신의 고유 역할을 수행하고, 인접한 다른 레이어에 무언가를 요청하거나 응답한다.
그 밖의 다른 레이어는 신경 쓸 필요가 없기 때문에 각 레이어는 자신의 역할에 충실할 수 있다.
레이어드 아키텍처의 장점
시스템을 레이어로 나누면 그 중 하나를 다른 것으로 교체하는 것이 가능해진다. 이는 시스템 전체를 수정하지 않고, 특정한 레이어의 기능이나 성능을 개선하는 것이 가능함을 의미한다. 재사용과 유지보수에 유리하다.
ex) 다른 부분은 그대로 두고 프리젠테이션만 웹에서 윈도우로 변경 가능
하나의 레이어에서 모든 작업을 전담하게 되면 같은 작업을 반복해서 구현해야 하는 경우가 생기는데, 이로 인해 많은 중복코드가 발생한다. 중복 코드를 수정할 때 모든 소스코드를 변경해야 하기 때문에 번거로워진다.
http://blog.naver.com/netrance/110111662341
http://blog.daum.net/question0921/797
2. 레이어드 아키텍처 구조
https://www.edwith.org/boostcourse-web/lecture/16767/
https://sites.google.com/site/telosystutorial/springmvc-jpa-springdatajpa/presentation/architecture
- 프리젠테이션 레이어: Controller, Pages, Display beans
- DispatcherServlet이 담당하는 부분 / UI
- 사용자와의 최종 접점. 사용자로부터 데이터를 입력받거나 데이터를 출력해서 보이는 레이어. 외부로부터 어플리케이션에 대한 요구를 받아들이는 부분이자 처리결과를 사용자에게 보여주는 부분
- 사용자가 선택할 수 있는 기능 표시, 요청에 필요한 부가적인 정보 전달을 위한 입력 양식, 전달된 자료를 효과적으로 보여주기 위한 프리젠테이션 로직 구현
- 서비스 레이어: Services, Mapper between JPA entities and Display beans
- Business Logic
- 핵심 업무 로직 구현, 그에 관련된 데이터의 적합성 검증, 트랜잭션 처리, 다른 레이어들과 통신하기 위한 인터페이스 제공, 해당 레이어의 객체들 사이의 관계 관리 #트랜잭션
- 프리젠테이션 레이어와 퍼시스턴스 레이어 사이의 다리 역할.
- 퍼시스턴스 레이어: JPA DAOs Repositories, JPA entities
- Data Access
- 데이터 처리. 주로 데이터의 생성/수정/삭제/선택(검색)과 같은 CRUD 연산을 수행하고, 가져온 관계형 정보를 저장하고 객체화한다.
- 컨트롤러: 요청을 받고 응답 #Controller / 서비스: 비즈니스 로직 담당 #Service / 레파지토리: 데이터 접근 #DAO
- 컨트롤러에서 중복되는 부분 처리: 비즈니스 메소드(핵심 업무 처리)는 서비스 객체에서 구현하고, 컨트롤러는 서비스 객체를 사용한다.
- 서비스에서 중복으로 호출되는 코드 처리: 데이터 엑세스 메소드는 레파지토리 객체에서 구현하고, 서비스는 레파지토리 객체를 사용한다.
- 로직을 세 레이어 중 어디에 놓는게 좋은지 고민해야 한다.
3. 설정의 분리
Bean 설정 파일은 하나의 파일보다는 presentation layer 설정파일과 service, persistance layer 설정파일(비즈니스 로직층 정의)로 분리하여 작성하는 것이 재사용과 유지보수에 좋다.
DispatcherServlet은 2개 이상 설정할 수 있는데, 각 DispathcerServlet의 ApplicationContext는 독립적이기 때문에 각각의 설정 파일에서 생성한 빈을 서로 사용할 수 없다. 대신에 동시에 필요한 빈은 ContextLoaderListener를 사용하면 공통으로 사용할 수 있다.
일반적으로 공통 빈(persistance+service) 설정은 ContextLoaderListener를 로딩해서 ApplicationContext를 만들고, presentation 빈 설정은 DispatcherServlet를 로딩해서 WebApplicationContext를 만든다.
4. Presentation Layer 설정 - DispatcherServlet을 FrontController로 설정하기 #서블릿매핑
- 1. web.xml에 설정
- 2. org.springframework.web.WebApplicationInitializer 인터페이스를 구현해서 사용
- (3. javax.servlet.ServletContainerInitializer 사용)
- 서블릿 3.0 스펙 이상에서 web.xml파일을 대신해서 사용
1. web.xml 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/dispatcherServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
|
cs |
line 3 servlet-class: 내가 실제로 동작시킬 서블릿
line 4 init-param: 해당 서블릿에서만 사용된다. DispatcherServlet가 init될 때 사용할 수 있는 파라미터.
line 4 contextConfigLocation: dispatcherServlet이 <param-value> 위치에 있는 설정파일을 읽는다.
설정파일(xml, java config 등): 스프링이 제공하는 동작 외에 어떤 일들을 해야 하는지 정리되어 있음
- <param-value>/WEB-INF/spring/dispatcherServlet/servlet-context.xml</param-value>
- <param-value>classpath:WebMvcContextConfig.xml</param-value>
- <param-value>mypackage.WebMvcContextConfiguration</param-value>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> // 3. 서블릿 클래스가 실행된다
<init-param>
<param-name>contextClass</param-name> // 4. 이런 ApplicationContext를 사용한다
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name> // 5. 이 설정파일을 읽는다
<param-value>mypackage.WebMvcContextConfiguration</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name> // 2. 이 이름과 같은 이름으로 매핑되어 있는
<url-pattern>/</url-pattern> // 1. 모든 요청(/)을 받아서
</servlet-mapping>
|
cs |
DispatcherServlet은 전달받은 설정 파일을 이용해서 스프링 컨테이너(application context)를 생성하고, 그 컨테이너로부터 필요한 빈 객체(HandlerMapping, HandlerAdapter, 컨트롤러, ViewResolver)를 구한다. #스프링 컨테이너
따라서 DispatcherServlet이 사용하는 설정 파일에 이 Bean들에 대한 정의가 포함되어 있어야 한다. #WebMvcContextConfiguration
5. 그 외 Layer 설정 - ContextLoaderListener 사용하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>mypackage.config.ApplicationConfig
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
|
cs |
line 1 context-param: 어플리케이션 전체(모든 서블릿, jsp)에서 사용하는 파라미터.
line 13 ContextLoaderListener
- listener: 특정한 이벤트가 일어났을 때 동작한다
- ContextLoaderListener: 웹 어플리케이션 시작 시점 = Run on server 시점에 = 이 리스너가 실행된다 = <context-param> 을 읽는다 =스프링 설정 파일을 로딩한다
- Dispatcher 클래스의 로드보다 먼저 동작하여 비즈니스 로직층을 정의한 스프링 설정 파일을 로드한다.
ApplicationContext의 Bean 정보는 모든 WebApplicationContext들이 참조할 수 있다.
ContextLoaderListener와 DispatcherServlet은 각각 ApplicationContext를 생성하는데, ContextLoaderListener가 생성하는 ApplicationContext가 root 컨텍스트가 되고 DispatcherServlet이 생성한 인스턴스는 root 컨텍스트를 부모로 하는 자식 컨텍스트가 된다. 자식 컨텍스트들은 root 컨텍스트의 설정 빈을 사용할 수 있다. 자식 컨텍스트들 사이의 빈 공유는 불가능하다.
https://devbox.tistory.com/entry/Spring-webxml-기본-설정
6. web.xml 정리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>Archetype Created Web Application</display-name>
<!-- ApplicationContext 빈 설정 파일-->
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>kr.or.connect.reservation.config.ApplicationConfig
</param-value>
</context-param>
<!-- 웹 어플리케이션이 시작되는 시점에 ApplicationContext을 로딩 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- DispatcherServelt 설정, WebApplicationContext 빈 설정 파일 -->
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>kr.or.connect.reservation.config.WebMvcContextConfiguration</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 한글인코딩 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
|
cs |
line 25~42 : presentation layer의 설정은 DispatcherServlet이 읽도록 한다 #DispatcherServlet #WebMvcContextConfiguration
line 8~20: 그 외의 설정은 ContextLoaderListener를 통해서 읽도록 한다
line 44 filter
- 요청이 수행되기 전 = 응답이 나가기 전에 실행된다
- 서블릿과 같은 방식으로 CharacterEncodingFilter 맵핑
- 다른 부분은 정해져 있고, <param-value>만 지정하면 됨
- <url-pattern>: 필터를 어디까지 적용할 것인지 정함. 모든요청(/*)
'JAVA > Spring' 카테고리의 다른 글
[Spring] Connection Pool / Spring JDBC (0) | 2019.10.10 |
---|---|
[Spring] Controller(Handler) (0) | 2019.10.09 |
[Spring] [Config] WebMvcContextConfiguration (0) | 2019.10.08 |
[Spring] [Config] DBConfig (0) | 2019.10.06 |
[Spring] [Config] ApplicationConfig (0) | 2019.10.06 |