1. 程式人生 > >SpringMVC的學習(八)——SpringMVC的工作流程及相關配置

SpringMVC的學習(八)——SpringMVC的工作流程及相關配置

一、SpringMVC詳細介紹

Spring Web MVC是一種基於Java的實現了Web MVC設計模式的請求驅動型別的輕量級Web框架,即使用了MVC架構模式的思想,將web層進行職責解耦,基於請求驅動指的就是使用請求-響應模型,框架的目的就是幫助我們簡化開發,Spring Web MVC也是要簡化日常Web開發的。

Spring Web MVC前端控制器是DispatcherServlet;應用控制器其實拆為處理器對映器( Handler Mapping)進行處理器管理和檢視解析器(View Resolver)進行檢視管理;頁面控制器/動作/處理器為Controller介面(僅包含ModelAndView handleRequest(request, response) 方法)的實現(也可以是任何的POJO類);支援本地化(Locale)解析、主題(Theme)解析及檔案上傳等;提供了非常靈活的資料驗證、格式化和資料繫結機制;提供了強大的約定大於配置(慣例優先原則  約定大於配置!)的契約式程式設計支援。

二、SpringMVC處理請求流程:(圖是網上隨便找的)

第一步:使用者傳送請求到前端控制器(DispatcherServlet)。

第二步:前端控制器請求 HandlerMapping 查詢 Handler(Controller),可以根據 xml 配置或者註解進行查詢。

第三步:處理器對映器 HandlerMapping 向前端控制器返回 Handler(Controller)

第四步:前端控制器呼叫處理器介面卡(HandlerAdapter)去執行 Handler(Controller)

第五步:處理器介面卡執行 Handler

第六步:Handler 執行完成後給介面卡返回 ModelAndView

第七步:處理器介面卡向前端控制器返回 ModelAndView

    ModelAndView 是SpringMVC 框架的一個底層物件,包括 Model(模型資料) 和 View(檢視)

第八步:前端控制器請求試圖解析器去進行檢視解析

    根據邏輯檢視名來解析真正的檢視。

第九步:試圖解析器向前端控制器返回 view

第十步:前端控制器進行檢視渲染

    就是將模型資料(在 ModelAndView 物件中)填充到 request 域

第十一步:前端控制器向用戶響應結果

用我自己的理解,結合servlet來說的話,就是:

首先頁面傳送一個請求,被SpringMVC的DispatcherServlet(前端控制器,即中央處理器)截獲,就相當於傳統servlet中配置的web.xml中配置的各種servlet,然後DispatcherServlet會根據URL傳送給處理器對映器(Handler Mapping),就相當於servlet中的servlet-mapping中的作用,然後找到對應的Handler,即找到servlet中對應的類的地址,然後再給DispatcherServlet,DispatcherServlet根據Handler去找到對應的處理器介面卡,就是找到SpringMVC的控制層,也就是Controller,相當於servlet中的控制層,一般就是命名為servlet,也就是相當於Strtus2中的Action動作,然後處理器介面卡經過service層,dao層獲得資料等,返回一個ModelAndView給DispatcherServlet,DispatcherServlet再去請求檢視解析器去進行檢視的解析,解析完返回view給DispatcherServlet,然後渲染頁面,然後DispatcherServlet響應給頁面。

下面我們對上面出現的一些元件進行解釋:

1、前端控制器DispatcherServlet不需要程式設計師開發,需要WEB.xml配置)。

作用:接收請求,響應結果,相當於轉發器,中央處理器。有了DispatcherServlet減少了其它元件之間的耦合度。

2、處理器對映器HandlerMapping(不需要程式設計師開發)。

作用:根據請求的url查詢Handler。

3、處理器介面卡HandlerAdapter(不需要程式設計師開發)。介面卡模式

作用:按照特定規則(HandlerAdapter要求的規則)去執行Handler(Controller)。

4、處理器Handler(Controller)(需要程式設計師開發)。

注意:編寫Handler時按照HandlerAdapter的要求去做,這樣介面卡才可以去正確執行Handler

5、檢視解析器ViewResolver(不需要程式設計師開發,只需要配置)。

作用:進行檢視解析,根據邏輯檢視名解析成真正的檢視(view)

6、檢視View(需要程式設計師開發jsp)。標籤顯示頁面資料

  注意:View是一個介面,實現類支援不同的View型別(jsp、freemarker、pdf…)

ps:不需要程式設計師開發的,需要程式設計師自己做一下配置即可。

可以總結出:需要我們開發的工作只有處理器 Handler 的編寫以及檢視比如JSP頁面的編寫。可能你還對諸如前端控制器、處理器對映器等等名詞不太理解,那麼接下來我們對其進行詳細的介紹。

三、配置

①配置前端控制器(DispatcherServlet)

在 web.xml 檔案中進行如下配置:

<!-- 配置前端控制器DispatcherServlet -->
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--
     springmvc.xml 是自己建立的SpringMVC全域性配置檔案,用contextConfigLocation作為引數名來載入
           如果不配置 contextConfigLocation,那麼預設載入的是/WEB-INF/servlet名稱-servlet.xml,在這裡也就是 springmvc-servlet.xml
      -->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
  </servlet>
 
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <!--
            第一種配置:*.do,還可以寫*.action等等,表示以.do結尾的或者以.action結尾的URL都由前端控制器DispatcherServlet來解析
           第二種配置:/,所有訪問的 URL 都由DispatcherServlet來解析,但是這裡最好配置靜態檔案不由DispatcherServlet來解析
      -->
    <url-pattern>/</url-pattern>
  </servlet-mapping>

②配置處理器介面卡(不需要程式設計師配置)

在 springmvc.xml 檔案中配置。用來約束我們所需要編碼的 Handler類。

第一種配置:編寫 Handler 時必須要實現 Controller

我們可以檢視原始碼:

第二種配置:編寫 Handler 時必須要實現 HttpRequestHandler

③編寫Handler(Controller)

在 springmvc.xml 檔案中配置。通俗來講,就是請求的 URL 到我們這裡所編寫的 Handler 類的某個方法進行一些業務邏輯處理。

  我們在上面講解了兩個處理器介面卡來約束 Handler,那麼我們就通過上面兩種配置分別編寫兩個 Handler

  1.第一種:實現Controller 介面

public class HelloController implements Controller {

	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
		ModelAndView modelView = new ModelAndView();
		// 類似於 request.setAttribute()
		modelView.addObject("name", "張三");
		modelView.setViewName("/WEB-INF/view/index.jsp");
		return modelView;
	}
}

  2.第二種:實現 HttpRequestHandler 介面

public class HelloController2 implements HttpRequestHandler {

	@Override
	public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setAttribute("name", "張三");
		request.getRequestDispatcher("/WEB-INF/view/index.jsp").forward(request, response);
	}
}

總結:通常我們使用第一種方式來編寫 Handler ,但是第二種沒有返回值,我們可以通過 response 修改相應內容,比如返回 json 資料。

response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json字串");

實際開發,我們加註解即可

④配置處理器對映HandlerMapping

在 springmvc.xml 檔案中配置。通俗來講就是請求的 URL 怎麼能被 SpringMVC 識別,從而去執行我們上一步所編寫好的 Handler

第一種:

<!-- 配置Handler -->
<bean name="/hello" class="com.bruceliu.controller.HelloController" />

<!-- 配置處理器對映器 將bean的name作為url進行查詢,需要在配置Handler時指定bean name(就是url) -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />

這樣配置的話,那麼請求的 URL,必須為 http://localhost:8080/專案名/hello

第二種方法:

<!-- 配置Handler -->
	<bean id="hello1" class="com.bruceliu.controller.HelloController" />
	<bean id="hello2" class="com.bruceliu.controller.HelloController2" />
	
	<!-- 第二種方法:簡單URL配置處理器對映器 -->
	<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<props>
				<prop key="/hello1">hello1</prop>
				<prop key="/hello2">hello2</prop>
			</props>
		</property>
	</bean>

這種配置請求的 URL可以為 http://localhost:8080/專案名/hello1,或者http://localhost:8080/專案名/hello2

總結:上面兩種處理器對映器配置可以並存,前端控制器會正確的去判斷 url 用哪個 Handler 去處理。

⑤配置檢視解析器

1.第一種配置:

如果這樣配,那麼在 Handler 中返回的必須是  路徑+jsp頁面名稱+".jsp"

2.第二種配置

<!--配置檢視解析器 -->
	<bean
	class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<!-- 返回檢視頁面的字首 -->
		<property name="prefix" value="/WEB-INF/view"></property>
		<!-- 返回頁面的字尾 -->
		<property name="suffix" value=".jsp"></property>
	</bean>

如果這樣配,那麼在 Handler 中只需要返回在 view 資料夾下的jsp 頁面名就可以了

⑥DispatcherServlet.properties

上面我們講解了各種配置,可能有人會問這麼多配置,萬一少配置了一樣,那不就不能運行了,那我們能不能不配置呢?答案是肯定的,SpringMVC 給我們提供了一個 DispatcherServlet.properties 檔案。系統會首先載入這裡面的配置,如果我們沒有配置,那麼就預設使用這個檔案的配置;如果我們配置了,那麼就優先使用我們手動配置的。

在 SpringMVC 執行之前,會首先載入 DispatcherServlet.properties 檔案裡面的內容,那麼我們來看看這裡面都是什麼。 在 SpringMVC 執行之前,會首先載入 DispatcherServlet.properties 檔案裡面的內容,那麼我們來看看這裡面都是什麼

我們可以從上面得出,如果我們不手動進行各種配置,那麼也有會預設的

  1、處理器介面卡預設:org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter

  2、處理器對映器預設:org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping

       3、檢視解析器預設:org.springframework.web.servlet.view.InternalResourceViewResolver

Spring配置 <context:component-scan/> <mvc:annotation-driven />

1.<annotaion-driven/> 標籤

這個標籤對應的實現類是org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser

 

仔細閱讀它的註釋文件可以很明顯的看到這個類的作用。解析這個文件:

這個類主要註冊8個類的例項:

 

  • 1.RequestMappingHandlerMapping   @RequestMapping
  • 2.BeanNameUrlHandlerMapping
  • 3.RequestMappingHandlerAdapter
  • 4.HttpRequestHandlerAdapter   @controller
  • 5.SimpleControllerHandlerAdapter
  • 6.ExceptionHandlerExceptionResolver
  • 7.ResponseStatusExceptionResolver
  • 8.DefaultHandlerExceptionResolver

1是處理@RequestMapping註解的,2.將controller類的名字對映為請求url。1和2都實現了HandlerMapping介面,用來處理請求對映。

3是處理@Controller註解的控制器類,4是處理繼承HttpRequestHandlerAdapter類的控制器類,5.處理繼承SimpleControllerHandlerAdapter類的控制器。所以這三個是用來處理請求的。具體點說就是確定呼叫哪個controller的哪個方法來處理當前請求。

6,7,8全部繼承AbstractHandlerExceptionResolver,這個類實現HandlerExceptionResolver,該介面定義:介面實現的物件可以解決處理器對映、執行期間丟擲的異常,還有錯誤的檢視。

所以<annotaion-driven/>標籤主要是用來幫助我們處理請求對映,決定是哪個controller的哪個方法來處理當前請求,異常處理。

2.<context:component-scan/>標籤

它的實現類是org.springframework.context.annotation.ComponentScanBeanDefinitionParser.

把滑鼠放在context:component-scan上就可以知道有什麼作用的,用來掃描該包內被@Repository @Service @Controller的註解類,然後註冊到工廠中。並且context:component-scan啟用@ required。@ resource,@ autowired、@PostConstruct @PreDestroy @PersistenceContext @PersistenceUnit。使得在適用該bean的時候用@Autowired就行了。

四、Spring和SpringMVC的關係

  • pingMvc是Spring體系中的一個Web模組。負責Web控制層工作!
  • SpringMvc依賴於Spring存在!
  • SpringSpringMvc是一個父子容器關係!