spring MVC這個環境中,Spring MVC會依據controller(或者你叫它handler)中處理方法的傳回值,進行解析,解析之後提供一個視圖,作為響應。
标注了@Controller的處理器,實際上本質是一個POJO,你标注了@Controller,我就高看你一眼。但你的形态就是一個java代碼檔案。
你作為一個java的土土的檔案,你裡面處理方法的傳回值,也就是return語句,傳回了一個東西。這個東西可以是String 也可以是 ModelAndView對象。這就是标注了@Controller的方法的全部工作。
接下來,Spring容器(或者說Spring MVC容器)需要接着你抛來的傳回值,不管你的傳回值是String還是ModelAndView,我,作為一個容器,我全都封裝成ModelAndView對象。然後,我,Spring容器的一部分,視圖解析器,開始工作。
視圖解析器的英文名字叫做 ViewResolver,這個東西首先是Spring定義得人一個接口,具體你的Spring容器中的視圖解析器有怎樣的功能,取決于你為你自己的Spring容器配置了哪種具體的Spring視圖解析器的實作類。
看看之前我們看過的一個圖:
這個是spring mvc 的jar中的預設配置

當然你的spring項目也可以在配置檔案中覆寫上述配置(我并沒有用别的視圖解析器取代預設的InternalResourceViewResolver):
@Controller中的方法傳回值最終都是ModelAndView,我們需要搞清楚兩件事:
1.ModelAndView是什麼?
2.視圖解析器究竟做了哪些工作,才能傳回我們需要的視圖?
我們應該先看看ModelAndView是怎麼回事:
ModelAndView是Spring中标準的類,完全是Spring自己封裝的對象。Spring API中如此描述這個對象:
public class ModelAndView extends java.lang.Object
Holder for both Model and View in the web MVC framework. Note that these are entirely distinct. This class merely holds both to make it possible for a controller to return both model and view in a single return value.
Represents a model and view returned by a handler, to be resolved by a DispatcherServlet. The view can take the form of a String view name which will need to be resolved by a ViewResolver object; alternatively a View object can be specified directly. The model is a Map, allowing the use of multiple objects keyed by name.
用人話解釋一下ModelAndView是幹什麼用的,ModelAndView包含兩部分:一個View和一個Model
View由setViewName()方法來決定,決定讓ViewResolver去哪裡找View檔案,并找到是哪個jsp檔案;
Model由addObject()方法來決定,它的本質是java的HashMap,鍵值對;
用人話來解釋ModelAndView的功能就是,View負責渲染Model,讓你找到代表View的jsp,用這個jsp去渲染Model中的資料。
看看Spring源碼:
Spring官網提供的API
去這個路徑找一下:
也就是說ModelAndView對象中的核心成員就是Object和ModelMap
其中ModelMap也是Spring自己定義的對象。
ModelMap的本質是Java的标準容器:LinkedHashMap
屬性成員我們已經搞清楚了,下面是方法成員:
setViewName()方法和addObject()方法
也就是說,ModelAndView對象沒有什麼神秘之處,解構一下核心就是ObjectLinkedHashMap,完全是Java的标準容器(對象)。
也就是說,關鍵不在于ModelAndView對象,而在于“視圖解析器”這個Spring容器的核心部件。
那麼視圖解析器怎樣工作呢?
你明明知道你用的ViewResolver的實作類就是InternalResourceViewResolver,那麼你應該仔細看看Spring API中這一部分的詳細内容:
<a href="https://docs.spring.io/spring/docs/5.0.1.RELEASE/javadoc-api/">https://docs.spring.io/spring/docs/5.0.1.RELEASE/javadoc-api/</a>
首先InternalResourceViewResolver extends(繼承)了 UrlBasedViewResolver;
然後順便說,把用于顯示(view)的jsp檔案放在WEB-INF檔案夾下是一種安全的做法,這樣不能通過url直接access這些jsp,隻能通過Controller java類來通路它們。
于是我們繼續去看UrlBasedViewResolver
我想這樣一個Spring官方的API中的說明性文字已經足以解開所有疑惑:那就是ModelAndView對象的方法setViewName()中的參數,看上去像是一個普通字元串的參數,究竟應該采用哪種格式?應該怎麼寫?已經有了定論。
As a special feature, redirect URLs can be specified via the "redirect:" prefix. E.g.: "redirect:myAction.do" will trigger a redirect to the given URL, rather than resolution as standard view name. This is typically used for redirecting to a controller URL after finishing a form workflow. Furthermore, forward URLs can be specified via the "forward:" prefix. E.g.: "forward:myAction.do" will trigger a forward to the given URL, rather than resolution as standard view name. This is typically used for controller URLs; it is not supposed to be used for JSP URLs - use logical view names there.
上述兩段文字就是forward和redirect兩個關鍵詞的用法。