在完整web開發中。springMVC主要充當了控制層的角色。它接受視圖層的請求。獲取視圖層請求數據,再對數據進行業務邏輯處理。而後封裝成視圖層需要的模型數據,再將數據導向到jsp等視圖界面。
在前面,咱們經過對@RequestMapping和方法入參綁定的分析,完畢了視圖層->控制層的數據交接,而後業務邏輯處理主要由Service層進行。那麼接下來很是關鍵的就是,怎樣將視圖數據導向到特定的視圖中。html
普遍意義上,視圖,並非是單指前端界面如jsp\html等。咱們可能需要給安卓、IOS等寫後臺接口、因先後端分離而放棄視圖界面導向如對前端ajax請求的純數據流輸出等。前端
這時,咱們的視圖可以爲json視圖、xml視圖、乃至PDF視圖、Excel視圖等java
springMVC爲咱們提供了多種途徑輸出模型數據:web
輸出途徑 | 功能說明 |
---|---|
ModelAndView | 將處理方法返回類型設爲ModelAndView。裏面封裝了咱們的模型數據,同一時候指明瞭視圖導向。 |
@modelAttribute | 方法入參標註改註解後,入參的對象就會放到數據模型中。 |
Map及Model | 入參爲org.springframework.ui.Model或org.springframework.ui.ModelMap或java.util.Map時,方法返回時會將Map中的數據本身主動加入到模型中 |
@SessionAttributes | 將模型中的某個屬性暫存到HttpSession中,以便多個請求之間完畢屬性共享 |
如下咱們主要介紹ModelAndView
ModelAndView(如下簡稱MAV)就像它的名字同樣。既包括了模型數據又包括視圖信息。咱們返回一個MAV。springMVC就會將模型數據轉發給相應的視圖界面。
在學習ModelAndView的用法前。咱們先用肢解的方法學習其兩個重要組成部分ajax
model是一個接口,咱們可以簡單地將model的實現類理解成一個Map,將模型數據以鍵值對的形式返回給視圖層使用。在springMVC中,每個方法被前端請求觸發調用前,都會建立一個隱含的模型對象,做爲模型數據的存儲容器。spring
這是一個Request級別的模型數據。咱們可以在前端頁面如jsp中經過HttpServletRequest等相關API讀取到這些模型數據。
在model中。定義有例如如下常常使用接口方法:json
/** * 加入鍵值屬性對 */
Model addAttribute(String attributeName, Object attributeValue);
/** * 以屬性的類型爲鍵加入屬 */
Model addAttribute(Object attributeValue);
/** * 以屬性和集合的類型構造鍵名加入集合屬性,假設有同類型會存在覆蓋現象 */
Model addAllAttributes(Collection<?> attributeValues);
/** * 將attributes中的內容拷貝到當前的model中 * 假設當前model存在一樣內容。會被覆蓋 */
Model addAllAttributes(Map<String, ?> attributes);
/** * 將attributes中的內容拷貝到當前的model中 * 假設當前model存在一樣內容,不會被覆蓋 */
Model mergeAttributes(Map<String, ?> attributes);
/** * 推斷是否有相應的屬性值 */
boolean containsAttribute(String attributeName);
/** * 將當前的model轉換成Map */
Map<String, Object> asMap();
假設咱們加入的屬性沒有指定鍵名。咱們稱之爲匿名數據綁定,它們遵循例如如下規則:
1. 對於普通數據類型,咱們直接以類型(第一字母小寫)做爲鍵值
2. 對於集合類型(Collection接口的實現者們,包括數組),生成的模型對象屬性名爲「簡單類名(首字母小寫)」+「List」,如List生成的模型對象屬性名爲「stringList」,List生成的模型對象屬性名爲「userModelList」。後端
在ModelAndView中,咱們不少其它的是直接操做modelMap和Map來完畢咱們的模型參數準備就能夠。modelMap繼承自java.util.LinkedHashMap。數組
它在LinkedHashMap的基礎上,新增了很是多便利的構造方法如:markdown
public ModelMap(String attributeName, Object attributeValue) {
addAttribute(attributeName, attributeValue);
}
public ModelMap addAllAttributes(Map<String, ?> attributes) { if (attributes != null) { putAll(attributes); } return this; }
使用這些構造方法能進一步簡化咱們的模型數據封裝。
view也是一個接口,它表示一個響應給用戶的視圖如jsp文件,pdf文件,html文件。
它有兩個接口方法:
1. String getContentType():返回視圖的內容類型
2. void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception
:依據給定模型和web資源定義視圖的渲染形式。
view接口有衆多的實現類,例如如下圖所看到的:
在spring中。經過ViewResolver來解析相應View實例的行爲。 它的定義至關簡單:
public interface ViewResolver {
//經過view name 解析View
View resolveViewName(String viewName, Locale locale) throws Exception;
}
spring爲咱們提供ViewResolver實現類用來解析不一樣的view:
在咱們最開始配置springMVC核心文件時,就用到了InternalResourceViewResolver,它是一個內部資源視圖解析器。
會把返回的視圖名稱都解析爲 InternalResourceView 對象。 InternalResourceView 會把 Controller 處理器方法返回的模型屬性都存放到相應的 request 屬性中。而後經過 RequestDispatcher 在server端把請求 forword 重定向到目標 URL。
如下咱們來看配置實例:
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property><!-- 前綴,在springMVC控制層處理好的請求後,轉發配置文件夾下的視圖文件 -->
<property name="suffix" value=".jsp"></property><!-- 文件後綴,表示轉發到的視圖文件後綴爲.jsp -->
</bean>
解析完Model and(和) View後,再來看咱們的ModelAndView:
public class ModelAndView {
//視圖成員
private Object view;
//模型成員
private ModelMap model;
//是否調用clear()方法清空視圖和模型
private boolean cleared = false;
/** * 空構造方法 */
public ModelAndView() {
}
/** * 簡便地使用視圖名生成視圖,詳細解析由DispatcherServlet的視圖解析器進行 */
public ModelAndView(String viewName) {
this.view = viewName;
}
/** * 指定一個視圖對象生成視圖 */
public ModelAndView(View view) {
this.view = view;
}
/** * 指定視圖名同一時候綁定模型數據。這裏模型數據以追加的形式加入在原來的視圖數據中 */
public ModelAndView(String viewName, Map<String, ?> model) { this.view = viewName; if (model != null) { getModelMap().addAllAttributes(model); } } /** * 指定一個視圖對象同一時候綁定模型數據。這裏模型數據以追加的形式加入在原來的視圖數據中 */ public ModelAndView(View view, Map<String, ?> model) { this.view = view; if (model != null) { getModelMap().addAllAttributes(model); } } /** * 簡便配置:指定視圖名,同一時候加入單個屬性 */ public ModelAndView(String viewName, String modelName, Object modelObject) { this.view = viewName; addObject(modelName, modelObject); } /** * 簡便配置:指定一個視圖對象,同一時候加入單個屬性 */ public ModelAndView(View view, String modelName, Object modelObject) { this.view = view; addObject(modelName, modelObject); } /** * 設置當前視圖名 */ public void setViewName(String viewName) { this.view = viewName; } /** * 獲取視圖名。假設當前視圖屬性爲view而非名字(String)則返回null */ public String getViewName() { return (this.view instanceof String ? (String) this.view : null); } /** * 設置當前視圖對象 */ public void setView(View view) { this.view = view; } /** * 獲取視圖,假設非view實例,則返回null */ public View getView() { return (this.view instanceof View ? (View) this.view : null); } /** * 推斷當前視圖是否存在 */ public boolean hasView() { return (this.view != null); } /** * 獲取模型Map。假設爲空,則新建一個 */ public ModelMap getModelMap() { if (this.model == null) { this.model = new ModelMap(); } return this.model; } /** * 同getModelMap */ public Map<String, Object> getModel() { return getModelMap(); } /** * 加入單個鍵值對屬性 */ public ModelAndView addObject(String attributeName, Object attributeValue) { getModelMap().addAttribute(attributeName, attributeValue); return this; } /** * 以屬性類型爲鍵加入屬性 */ public ModelAndView addObject(Object attributeValue) { getModelMap().addAttribute(attributeValue); return this; } /** * 將Map中的所有屬性加入到成員屬性ModelMap中 */ public ModelAndView addAllObjects(Map<String, ?> modelMap) { getModelMap().addAllAttributes(modelMap); return this; } /** * 清空視圖模型。並設爲清空狀態 */ public void clear() { this.view = null; this.model = null; this.cleared = true; } /** * 推斷是否爲不含視圖和模型 */ public boolean isEmpty() { return (this.view == null && CollectionUtils.isEmpty(this.model)); } }