springMVC是一個MVC的開源框架,springMVC就至關因而Struts2加上sring的整合,那麼springMVC和spring是什麼樣的關係呢?在百度百科上有一個很好的解釋:springMVC是spring的一個後續產品,其實就是spring在原有基礎上,又提供了web應用的MVC模塊,能夠簡單的把springMVC理解爲是spring的一個模塊(相似AOP,IOC這樣的模塊),網絡上常常會說springMVC和spring無縫集成,其實springMVC就是spring的一個子模塊,因此根本不須要同spring進行整合。html
工做原理圖:前端
能夠看到這裏分爲大體11個步驟,這11個步驟的任務是這樣的:java
一、用戶發送請求至前端控制器DispatcherServlet。web
二、 DispatcherServlet收到請求調用HandlerMapping處理器映射器。spring
三、 處理器映射器找到具體的處理器(能夠根據xml配置、註解進行查找),生成處理器對象及處理器攔截器(若是有則生成)一併返回給DispatcherServlet。apache
四、DispatcherServlet調用HandlerAdapter處理器適配器。後端
五、 HandlerAdapter通過適配調用具體的處理器(Controller,也叫後端控制器)。api
六、Controller執行完成返回ModelAndView。網絡
七、 HandlerAdapter將controller執行結果ModelAndView返回給DispatcherServlet。架構
八、 DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器。
九、 ViewReslover解析後返回具體View,這個view不是完整的,僅僅是一個頁面(視圖)名字,且沒有後綴名。
十、DispatcherServlet根據View進行渲染視圖(即將模型數據填充至視圖中)。
十一、 DispatcherServlet響應用戶。
圖中能夠看到,DispatcherServlet(前端控制器)佔據了很大的一部分,事實也是這樣,springMVC中,DispatcherServlet是他的核心。
接下來再看一下springMVC組件及其核心步驟的說明:
黃色字體和綠色字體是對組件做用的說明,其中黃色字體說明的組件是框架提供,綠色字體說明的部分是要由工程師實現,紅色字體是核心架構的具體流程步驟
看完了原理,再來經過註釋的方式,寫一個Hello World,熟悉一下過程。
maven須要的相關依賴,springMVC須要的spring-webmvc,日誌相關的slf4j-log4j12,JSP相關的jstl、servlet-api、jsp-api。
由於DispatcherServlet自己就是一個Servlet,因此要在web.xml配置:
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
複製代碼
前端控制器要協調各個組件幹活,因此就要依賴於配置文件,SpringMVC要讀取的配置文件是要是本身手動建立,怎麼建立?配置文件應該怎麼命名?先來到DispatcherServlet的源代碼中:
能夠看到DispatcherServlet繼承了FrameworkServlet,FrameworkServlet是Spring web框架的基本servlet。爲集成提供了基於javabean的總體解決方案中的Spring應用程序上下文。FrameworkServlet註釋中有這樣一段描述:
大體意思就是,默認的SpringMVC配置文件名字是「servlet-name」-servlet.xml, 而這個「servlet-name」就是在web.xml中配置的的名字,這裏就是springmvc,固然你也能夠起其餘名字。而後讀取的默認位置是在/WEB-INF/「servlet-name」-servlet.xml,因此這裏要在WEB-INF下面建立的是名叫springmvc-servlet.xml的配置文件,由於他和Spring都是一個體系內的,因此能夠直接建立spring的配置文件模板:
如今有了配置文件,那麼改在配置文件中配置什麼東西?能夠回到SpringMVC工做流程圖看到,在springMVC配置文件中起碼要配置,映射器HandlerMapping、適配器HandelAdapter、處理器Handel(Controller)、視圖解析器ViewResolver。View的渲染不是SpringMVC來完成,因此這裏不須要配置。
先來配置HandlerMapping,找到HandlerMapping,他是一個接口,因此要配置的是HandlerMapping的實現類,找到HandlerMapping源碼,查看他的繼承樹:
不看已通過時的(這裏Spring基於4.3的一個版本),咱們要經過請求中的url和HandlerMapping找處處理器,因此使用BeanNameUrlHandlerMapping,類名中的BeanName也就是要找的處理器,在註釋中也有說明,若是url是/foo ,對應的處理器名字也是/foo,假設咱們等等要訪問的url是localhost:8080/hello.do,那麼後面咱們再寫 處理器中的代碼的名字也是hello.do.
而後再springmvc-servler.xml中配置映射器:
<!--HandelMapping-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
複製代碼
映射器處理完後,返回執行鏈,DispatcherServlet去調用處理器,處理器實現自己就就是多元化的,要根據處理器的具體實現,經過適配器(處理器包裝後)調用處理器,咱們先找到HandlerAdapter,看看這個接口的繼承樹:
有一個適配器SimpleControllerHandlerAdapter,可以幫咱們調用處理器(也能夠叫Controller)中的方法,
那麼他是怎麼調用處理器方法?
他是經過判斷你的處理器是否屬於Controller的類型,是則返回true。那麼Controller又是什麼呢?查看源代碼發現Controller是一個接口,也就意味着,咱們寫處理器部分的代碼要實現這一個接口。
這個接口中就一個方法,也就是處理器方法,這個方法等同與Servlet中的doGet/doPost方法。
咱們調用處理器方法的前提是實現Controller接口,在交給適配器,適配器判斷完以後,處理器(handler)在調用Controller接口中的處理器方法,因此最終調用處理器方法返回ModelAndView的是適配器的handler方法:
接下來咱們要作的事就是在springmvc-servlet.xml配置這個SimpleControllerHandlerAdapter:
<!--SimpleControllerHandlerAdapter-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
複製代碼
配置好適配器,按照流程圖接下來搞配置處理器,前面說提處處理器部分是咱們本身來實現的。
咱們在項目中建立一個一個包com.ljm.springmvc.controller,而後在包中建立處理器HelloController。這裏不叫包名類名不叫Handler而叫controller,至於爲何,多是由於他要實現一個接口,這接口叫Controller。而後重寫Controller中的方法:
package com.ljm.springmvc.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
return null;
}
}
複製代碼
由於咱們本身建立了處理器和Spring沒啥關係,要想有有點什麼關係,就要把它配置到springmvc-servlet.xml中,處理器有不少個,那麼就要給他配上id或者name,這裏給他配置name,前面在配置映射器時提到,這個名字是咱們要訪問的url因此,不能隨便配:
<!--處理器,注意/不能丟-->
<bean name="/hello.do" class="com.ljm.springmvc.controller.HelloController" />
複製代碼
建立配置好處理器後,就要開始實現處理器中的業務,該調用哪一個service層就調用哪一個service,而後把結果響應到客戶端,這裏響應回去的是一個ModelAndView,這裏不實現service和dao層,寫一個死數據,無論三七二十一,先建立一個ModelAndView對象用於返回,
這裏能夠看到modelAndView有一些add方法:addObject(),根據參數能夠聯想到request的get/set Attribute方法,先設置一對key/value;但這時候只設置了數據,沒有告訴他往哪一個頁面返回,因此這裏還有一個操做,叫設置視圖名稱,使用的是modelAndView的setViewName方法,但這裏參數僅僅是設置要返回到的視圖名稱(邏輯視圖),且不帶後綴名,這裏咱們要返回到index.jsp,因此參數是index;因此處理器的代碼實現已經完成了:
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg","spring MVC : Hello World!");
modelAndView.setViewName("index");
return modelAndView;
}
}
複製代碼
視圖解析器:ViewResolver是框架提供的,因此直接配置到springmvc-servlet.xml就行。
ViewResolver也是個接口,查看繼承樹,
其中有一個InternalResourceViewResolver,根據註釋咱們能夠看到咱們要用的就是他InternalResourceViewResolver繼承了UrlBasedViewResolver,根據UrlBasedViewResolver註釋的提示,咱們能夠看到視圖解析器正確的配置姿式:
咱們這裏的配置就應該是:
<!--視圖解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
<!--配置路徑:返回頁面在webapp下,因此配置/-->
<property name="prefix" value="/" />
<!--配置後綴名-->
<property name="suffix" value=".jsp" />
<!--viewname已經在處理器配置過了-->
</bean>
複製代碼
<html>
<body>
<h2>${msg}</h2>
</body>
</html>
複製代碼
添加log4j.properties 到resources
log4j.rootLogger=DEBUG,A1
log4j.logger.org.apache=DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
複製代碼