[#0x002F] Spring-MVC example anatomy

  例子來自spring-framework-2.5.6.SEC01\docs\MVC-step-by-step\pdf\spring-mvc-step-by-step.pdf

  先上圖,再慢慢解釋。

1. DispatchServlet接過瀏覽器的/hello.htm請求

  在springapp/war/WEB-INF/web.xml中,定義了homepage:

<welcome-file-list>
	<welcome-file>index.jsp</welcome-file>
</welcome-file-list>

所以瀏覽器端輸入http://localhost:8080/springapp即相當於http://localhost:8080/springapp/index.jsp。

 

  而springapp/war/index.jsp是直接sendRedirect:

<%-- Redirected because we can't set the welcome page to a virtual URL. --%>
<c:redirect url="/hello.htm"/>

所以又轉爲http://localhost:8080/springapp/hello.htm

 

   在springapp/war/WEB-INF/web.xml中有:

<servlet>
	<servlet-name>springapp</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>

<servlet-mapping>
	<servlet-name>springapp</servlet-name>
	<url-pattern>*.htm</url-pattern>
</servlet-mapping>

所以這個http://localhost:8080/springapp/hello.htm請求由DispatcherServlet來處理。

 

2.  DispatchServlet確定mapping of <Request, Controller>

  DispatchServlet默認使用的是BeanNameUrlHandlerMapping,即通過controller的bean name來與request對應。

  Controller在WebApplicationContext文件中定義,而WebApplicationContext文件的命名規則是<servlet-name>-servlet.xml,所以本案例的WebApplicationContext文件即是springapp-servlet.xml

  bean name必須是slash開頭,然後只能寫request中最後一個slash後面的部分。

<!-- spingapp/war/WEB-INF/springapp-servlet.xml -->

<bean name="/hello.htm" class="springapp.web.InventoryController">
	<property ......></property>
</bean>

 

  另外還有SimpleUrlHandlerMapping、ControllerClassNameHandlerMapping和CommonsPathMapHandlerMapping三種mapping形式,具體參見Spring in Action 2nd Edition 13.2

 

3. Controller返回ModelAndView給DispatchServlet

  Controller的類型有很多,最簡單的形式就是自己實現一個Controller接口(spring自帶了很多Controller及其子接口的實現),只需實現一個handleRequest(HttpServletRequest, HttpServletResponse)方法,返回一個ModelAndView即可。

  ModelAndView(ViewName, ModelName, ModelObject),其中的ModelName和ModelObject相當於給ViewName setAttribute(ModelName, ModelObject);ViewName可以寫一個長路徑,如“WEB-INF/jsp/hello.jsp”,更常見的方法是返回一個短字符串交給ViewResolver去解析。

 

4. DispatchServlet通過ViewResolver來解析ViewName

  DispatchServlet默認使用的ViewResolver是InternalResourceViewResolver(更多關於DispatchServlet的默認配置請參見spring-framework-2.5.6.SEC01\src\org\springframework\web\servlet\DispatcherServlet.properties),但與BeanNameUrlHandlerMapping不同的是,雖然InternalResourceViewResolver是默認的,但需要進一步對InternalResourceViewResolver進行配置。

<!-- spingapp/war/WEB-INF/springapp-servlet.xml -->

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
	<property name="prefix" value="/WEB-INF/jsp/"></property>
	<property name="suffix" value=".jsp"></property>
</bean>

prefix + “hello” + suffix == "/WEB-INF/jsp/hello.jsp"(這裏的“解析”更像是“拼接”)

 

  注意這裏的bean id,雖然在spring-framework-2.5.6.SEC01\src\org\springframework\web\servlet\DispatcherServlet.java裏有:

public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";

但這裏的bean id可以隨便寫。

  However, MessageSource類的bean id必須是"messageSource",不能隨便寫。我們在spring-framework-2.5.6.SEC01\src\org\springframework\context\support\AbstractApplicationContext.java裏面可以看到有:

public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";

 

  另外,bean name和bean id的區別:

  Either one would work. It depends on your needs:
  If your bean identifier contains special character(s) for example (/viewSummary.html), it (the slash) won't be allowed as the bean id, because it's not a valid XML ID. In such cases you could skip defining the bean id and supply the bean name instead.
  The name attribute also helps in defining aliases for your bean, since it allows specifying multiple identifiers for a given bean.

 

5. JSP dispatched to browser by DispatchServlet

  hello.jsp被dispatch給瀏覽器顯示,注意是dispatch,所以瀏覽器的地址欄仍然是hello.htm。

  JSP可以使用ModelAndView中的Model,形式如"${ModelName.ModelObject}",類似於getAttribute。

<%-- springapp/war/WEB-INF/jsp/hello.jsp --%>

<body>
	<h1><fmt:message key="heading"/></h1>
	<p><fmt:message key="greeting"/> <c:out value="${model.now}"></c:out></p>
	<h3>Product</h3>
	<c:forEach items="${model.products}" var="prod">
		<c:out value="${prod.description}"/> 
		<i><c:out value="${prod.price}"/></i><br><br>
	</c:forEach>
	<br>
	<a href="<c:url value="priceincrease.htm"/>">Increase Price</a>
	<br>
</body>
發佈了49 篇原創文章 · 獲贊 2 · 訪問量 1584
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章