It is just my opinion, so don't you attack me. please!
But if this posting has some incorrect informations, you comment about that
Please!!
What is MVC pattern in JSP?
- MVC pattern이란?
MVC 패턴은 Business 로직을 Presentation(User Interface) 로직으로부터 분리시키는 것이다.
· M(Model) - 웹 어플리케이션과 DB간의 상호작용을 핸들링 한다.(beans)
· V(View) - 웹 어플리케이션의 front-end에 user-data, image, text, form(양식)을 표시 한다.(.jsp)
· C(Controller) - 어플리케이션의 다양한 메소드를 활용하여 Model과 View로 부터 받은 data를 조작하고, DB나 front-end에 전달한다.(servlet & controller) - How implement the MVC pattern in JAVA?
· Model의 경우는 java.util.Observable Interface를 상속받아서 만들 수 있다.
import java.util.Observable;
public class Model extends Observable {
public Model() {
super();
}
@Override
public void addObserver() {
// 이곳에서 알림을 보낼 view들을 추가한다.
}
@Override
protected void clearChanged() {}
@Override
public int countObservers() {}
@Override
public void deleteObserver(Observer o) {}
@Override
public boolean hasChanged() {}
@Override
public void notifyObservers() {
// 전체 view들에게 변화를 알린다.
}
@Override
public void notifyObservers(Object arg) {}
@Override
protected void setChanged() {
// 이 메소드를 통해 변화를 세팅한다.
}
}
- View의 경우는 Observer Interface를 상속하여 구현할 수 있다.
import java.util.Observer;
public class View implements Observer {
public View() {
super();
}
@Override
public void update(Observerable o, Object arg) {
// 이 메소드는 반드시 구현되어야 하며, 두 번째 파라미터는 추가적인 정보를 받는다.
}
}
Observerable Class와 Observer Interface는 JDK1.8 까지에서만 사용 가능하다. 현재 (2018.04)는 JDK1.9까지 배포된 상태이며, JDK1.9에는 Observerable과 Observer 대신에 java.util.current.Flow를 사용하길 권장한다. 사라진 이유는 다음과 같다.
· Not Serializable - Observerable은 Serializable을 구현하지 않기 때문에, SubClass와의 Serialization 할 수 없다.
· No thread safety - Observerable Class를 상속한 SubClass들이 event 알림을 순서 없이 보낼 수 있으므로, thread safety가 보장되지 않는다.Flow of MVC pattern
Spring-MVC에서는 위와 같은 형식으로 흐름이 진행된다.
- Web-browser에서 URI를 입력하면 URI에 대한 요청을 Web.xml가 잡는다.
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/*-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/url-pattern>
</servlet-mapping>
org.springframework.web.servlet.DispatcherServlet
라는 클래스를 reference하고 있다.
https://github.com/spring-projects/spring-framework/blob/master/spring-webmvc/src/main/java/org/springframework/web/servlet/DispatcherServlet.java
에서 DispatcherServlet 클래스를 확인 할 수 있다. 그래서 DispatcherServlet을 순수 자바코드로 작성되었다고 이야기한다. 그리고 <param-value> 태그는 현재 프로젝트에 ClassPath:spring폴더 안의 post-fix가 -servlet.xml인 xml파일을 참조하여 사용하겠다는 의미를 갖는다.
<servlet-mapping>아래 <url-pattern>이라는 태그가 보일 것이다. 이 것은 browser url창에 입력된 문자열을 뜻한다. "/"이 입력되어 있는데 이것은 "/"으로 시작하는 모든 url을 뜻한다.
<servlet>
, <servlet-mapping>
두 태그 밑에 모두 <servlet-name>이라는 태그가 있다. 이것을 매개로 하여 "/"으로 시작하는 모든 url을 DispatcherServlet Class로 보낼 수 있게 된다.
- DispatcherServlet
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns="http://www.springframework.org/schema/mvc"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="package-name" />
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<beans:bean id="loggerInterceptor" class="common.first.logger.LoggerInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<beans:bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<beans:bean class="org.springframework.web.servlet.view.BeanNameViewResolver" p:order="0" />
<beans:bean name="cgr/egovCategoryList" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
<mvc:annotation-driven>
<mvc:path-matching suffix-pattern="false" />
</mvc:annotation-driven>
<beans:bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/jsp/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<mvc:resources mapping="/resources/**" location="/resources/" />
</beans:beans>
Servlet에서 요청에 대한 처리를 하는 과정을 알기 전에 알아야할 것이 있다.
· Beans
· Annotation
<beans:bean> 태그의 bean은 무엇인가?
Application의 back-bone을 구성하고, Spring IOC(Inverse Of Control) 컨테이너에 의해 관리되는 객체들을 beans라고 부른다.
위 코드에서는 beans 태그를 이용하여 beans를 reference하고 있다.
· 장점은 Component를 재사용할 수 있고, 비지니스 로직과 표현을 위한 코드를 분리할 수 있다. 또한 JSP 페이지 내에 복잡한 JAVA 코드를 사용하지 않고, 쉽고 간단한 코드만을 사용할 수 있도록 해준다.
Annotation이란 무엇인가?
사전적인 의미로는 주석을 뜻하며 컴파일 타임 또는 런타임에 해석될 수 있다. 또한 메타데이터(실제데이터가 아닌 Data를 위한 데이터) 라고도 불리며 JDK1.5부터 등장하였다
Annotation이 붙은 코드는 Annotation이 구현된 정보에 따라 연결되는 방향이 결정된다. (왜 Annotation이 필요한지는 따로 정리하도록 하겠다.)
url에 대한 처리를 dispatcher-servlet이 받는다. <context:component-scan base-package="package-name" />라는 태그가 있다. 의미는 "package-name이라는 package에서 @Component라는 Annotation을 스캔해라" 인데 @Service, @Controller는 이미 @Component를 상속하고 있기 때문에 문제 없이 dispatcher-servlet에 구현되어있는 handlerMapping을 통해 url에 맞는 Controller를 찾을 수 있다. 이 후 handlerMapping이 url에 해당하는 Controller를 찾으면 해당 Controller로 요청을 보낸다.
@Controller
public class MainController {
...
}
Controller에서는 사용자가 작성한 코드를 실행하고, Request에 맞는 View를 반환한다. 이 때, dispatcherServlet에 있는 viewResolver가 해당 view가 있는지 없는지 검색하고 있다면 Controller에서의 정보를 View로 보낸다. 그리고 이 View를 다시 dispatcherServlet으로 보낸다. 최종적으로는 dispatcherServlet이 Web.xml로 정보를 보낸 후 클라이언트로 응답을 보낸다.