Spring MVC 4.2.4 文檔實踐(一)--- 菜鳥從零開始學系列

1 前言

本文後續將開啓一個系列,順着做者學習 Spring MVC 文檔的腳步,從零開始搭建一個基於 Spring MVC 的 web 應用,而且根據 Spring MVC 的文檔內容,選擇現有的,用的比較多的,實現性比較好的特性,基於其代碼實現,來說解其源碼和背後的原理,這既是對本身在 Spring 全家桶的學習的檢驗,也可讓我講一講本身對於 Spring MVC 的一些特性的理解。本人也是菜鳥程序員一枚,開始寫這個系列的時候入行也不到半年。所以,儘可能能夠站在初學者的角度,來解決咱們你們在學習的路上一些老師想固然,而咱們卻一直沒有辦法本身解決的問題。但願能夠在不影響工做的狀況下,儘可能作到每週一更甚至每週兩更,但願這個系列能夠幫助到各位。相關代碼能夠移步 個人 github 倉庫,若是有什麼問題,也煩請大佬們在這個系列中,多多指正。php

2 前期準備

初始化 maven 工程

使用 Intellij 新建工程選項,在 maven 選項卡里面選擇 maven-archetype-webapp,輸入對應的工程名,點擊建立,能夠獲得一個已經初始化了 webapp 文件。html

工程目錄初始化設置

在 main 文件夾下,分別建立 java 和 resources 文件夾,點擊 File - Project Structure,將 main 和 resources 設置爲 Source Folders (藍色),和 Resource Folder (紫色)。前端

以後,在 java 的文件夾中設置好 package 的路徑,本例的 package 名字爲 com.test.myappjava

maven 依賴

爲了讓工程支持 Spring 的特性,須要在 pom.xml 中引入 springframework 的依賴git

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-webmvc</artifactId>
	<version>5.1.0.RELEASE</version>
</dependency>
複製代碼

下面,就開始用代碼實例解釋 Spring MVC 的文檔。程序員

3 Spring MVC 用 DispatcherServlet 處理請求

這一部分主要告訴咱們:DispatcherServlet 是 Spring MVC 的中央處理器,它負責把請求分發到控制器中,這被稱爲「前端控制器」的設計模式,模式框架以下圖所示:github

Front-end controller

所以,DispatcherServlet 前端的 Incoming Request 發到(Delegate)對應的 Controller 下面,在 Controller 處理了 Request,而且建立 model 以後,將響應和 model 封裝到對應的 view template 中,以後 view template 將控制權交還到 DispatcherServlet,並由其返回響應。web

3.1 DispatcherServlet 建立

而實際操做中,DispatcherServlet 因爲繼承了 HttpServlet 類,也須要在 web.xml 文件下進行聲明。所以,能夠照着文檔中的例子進行 DispatchServlet 的配置:spring

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Dispatched Servlet Demo</display-name>

    <servlet>
        <servlet-name>example</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        <!--load on startup 大於 0 表明這個容器在應用啓動時就加載,而等於 0 則表示在這個容器被選擇時加載-->
        <!--load-on-startup 的值越小,表明加載的優先級越大-->
    </servlet>

    <servlet-mapping>
        <servlet-name>example</servlet-name>
        <url-pattern>/example/*</url-pattern>
    </servlet-mapping>

</web-app>
複製代碼

如上述代碼所示,咱們配置了一個名爲 example 的 dispatcherServlet,而當 url 的後綴爲 example 時,默認將使用該 DispatcherServlet 進行請求(request)的轉發和視圖(view )的返回。express

值得一提的是,咱們在 web.xml 中定義了名爲 example 的 DispatcherServlet,Spring 將爲在 WEB-INF 中尋找名爲 example-servlet.xml 的文件以獲取對應的 bean 配置信息。所以,咱們還須要建立 example-servlet.xml 的文件以設置對應的 bean 信息。

3.2 example-servlet 的配置

example-servlet 中須要咱們指定 bean 的位置,即 Spring MVC 系統須要去哪一個地方尋找 bean 的配置並自動裝配。另外一方面,須要配置 viewResolver 以便返回視圖。所以,咱們在 example-servlet.xml 中首先須要包含這些信息,下述代碼配置了 example-servlet 中的 bean 的掃描路徑,以及視圖解析器 viewResolver。

<beans xmlns="http://www.springframework.org/schema/beans" 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.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">

    <context:component-scan base-package="com.test.myapp.example">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/views/" p:suffix=".jsp" p:order="1">
    </bean>

</beans>
複製代碼

首先解釋一下頭文件

  • beans:文件的根節點
  • Xmlns:xmlns 是 xml name space 的縮寫,用於區分這個 xml 文件下的定義和其餘 xml 文件下的定義。
  • Xmlns:<組件>:表示一個組件配置的 namespace,好比上文用到了 context 的組件來掃描 component 註解,則須要配置 xmlns:context
  • xmlns:xsi:是指xml文件遵照xml規範,xsi 全名 xml schema instance,表示具體用到的 schema 資源文件裏定義的元素所準守的規範。
  • xsi:schemaLocation:表示 xml 的某個組件須要遵循的規範,好比 xmls:context 須要遵循的規範就是

頭文件的配置更多的是理解一個相似於 package 的概念,在定義了 namespace(xmlns) 以後,你須要哪些元素或者組件,則定義他的規則以及 instance 的規則,以便後續的 xml 配置使用這些配置。

context 部分表示了這個工程要去哪裏去尋找這個應用的 component,並實現實例的自動裝配,這裏制定了一個針對 component 的過濾器(filter),使它只會在遇到 controller 的類時候進行自動裝配。

3.3 配置 Controller 和 jsp

在配置好 servlet 的轉發後,咱們須要配置其掃描路徑下的 Controller 和對應的 jsp 視圖。在整理完成對應用途的文件和文件夾以後,工程結構以下圖所示:

![工程文件結構](/Users/shenruofan/Desktop/屏幕快照 2018-10-22 下午5.51.03.png)

首先在 com.test.my.example.controller 下建立對應的 controller 類:

package com.test.myapp.example.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping
public class ExampleController {
    @RequestMapping(value="/hello", method = RequestMethod.GET)
    public String helloWorld() {
        return "hello";
    }
}
複製代碼

值得注意的是,因爲在 example-servlet.xml 中已經配置了 url 的格式,它表示這個 servlet 只在 /example/* 的 url 格式下面纔會生效。所以當咱們在 helloWorld 這個方法上指定 RequestMapping 爲 "hello" 時,則令其實際生效的 url 應當爲 /example/hello。因爲 helloWorld() 方法返回了 "hello",則 viewResolver 在 views 下面去尋找名爲 hello.jsp 的文件。所以,咱們還須要一個 hello.jsp 的視圖文件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>hello world</title>
</head>
<body>
    <h1>example::::::hello world!</h1>
</body>
</html>
複製代碼

以後就是運行 tomcat 時所用到的相關配置,而且 maven 打包這個工程,本機使用了 localhost:8080 端口,則輸入了 http://localhost:8080/example/hello 以後,網頁出現了

![效果圖](/Users/shenruofan/Desktop/屏幕快照 2018-10-23 下午3.09.32.png)

的樣子,則說明這個 controller 成功返回了 view 視圖。類比上述「前端控制器」的設計模式,咱們能夠看到:

當前端有請求進來時,好比 /example/hello,Spring MVC 將會識別這個 url 下生效的 servlet,而後該 servlet 會把它分發到 url 映射到的方法上,而該方法會返回一個視圖的名稱到 servlet;以後,servlet 會去找對應名字的 template,組裝完成後,再返回到用戶的前端。所以,咱們才能夠看到 hello.jsp 的前端樣式展示在咱們眼前。

4 配置根 context 對象代替 Servlet.xml

這篇文檔的最後提到了這樣一句話:

當你的應用中只須要一個DispatcherServlet時,只配置一個根 context 對象也是可行的。

所以,咱們能夠試一下只配置一個 ContextConfig 的條件下,能不能導航到這個 hello.jsp 文件。

4.1 配置 Root Context

首先,更新 web.xml 的配置,使其只使用一個 ContextConfig 來管理 servlet 下面的 beans,配置內容以下:

<?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>Dispatched Servlet Demo</display-name>

    <!--使用根 context 來管理 servlet 的配置-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>WEB-INF/root-context.xml</param-value>
    </context-param>

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

</web-app>
複製代碼

這裏注意一下 servlet-mapping 的 url 攔截問題,其實源文檔的這種配置會有問題,若是不加 .do 的話,會把 jsp 解析的請求也攔截下來,形成 *noHandlerFound for .jsp 的問題,所以須要一個特殊的 url 後綴進行區分,防止 servlet 攔截不應攔截的請求。其次,咱們須要配置 WEB-INF 路徑下的 root-context.xml 文件,配置方法與上面的 example-servlet.xml 的相同。controller 亦然,須要主要的是,如今是當你輸入 /hello.do 時,能夠返回 hello.jsp 的視圖。

以後也是運行 tomcat 時所用到的相關配置,而且 maven 打包這個工程,本機使用了 localhost:8080 端口,則輸入了 http://localhost:8080/hello.do 以後,網頁出現了

![效果圖](/Users/shenruofan/Desktop/屏幕快照 2018-10-23 下午3.09.32.png)

證實咱們的 root context 的配置是有效的。

4.2 RootContext.xml 和 Servlet.xml 的差異

經過上面的配置,看起來 RootContext 和 servlet 的配置文件對 Spring MVC 工程的做用是同樣的,其實否則,根據官方文檔:

Spring lets you define multiple contexts in a parent-child hierarchy.

The applicationContext.xml defines the beans for the "root webapp context", i.e. the context associated with the webapp.

The spring-servlet.xml (or whatever else you call it) defines the beans for one servlet's app context. There can be many of these in a webapp, one per Spring servlet (e.g. spring1-servlet.xml for servlet spring1, spring2-servlet.xml for servlet spring2).

Beans in spring-servlet.xml can reference beans in applicationContext.xml, but not vice versa.

All Spring MVC controllers must go in the spring-servlet.xml context.

In most simple cases, the applicationContext.xml context is unnecessary. It is generally used to contain beans that are shared between all servlets in a webapp. If you only have one servlet, then there's not really much point, unless you have a specific use for it.

大概的意思是,ApplicationContext.xml 和 Servlet.xml 是父子之間的關係,其中一個 Spring mvc 工程裏應當只有一個 ApplicationContext,然而能夠有多個 Servlet 的配置;而且,Servlet.xml 能夠去引用 ApplicationContext 中的 bean,可是反過來卻不行。

5 總結

本章討論了 Spring MVC 中 web.xml,以及下面的 servlet.xml 或者 contextConfig.xml 的配置方法及注意事項,並用實際代碼的方式,理解 Spring MVC 的前端控制器設計思想。

相關文章
相關標籤/搜索