ModelAndView的作用非常簡單,就是兩個作用。
第一個作用,往作用域中放值。
第二個作用,實現頁面跳轉。
15 - ModelAndView簡單使用
往request作用域中放值,有三種方式。
springmvc中提供了一個類,就是modelandview。model是模型。項目中的實體類,裝載傳輸數據。view是視圖,幫助我們設置視圖,操作視圖。

modelandview的構造器很多,如上圖所示。
有參構造器當中的參數,說明modelandview的類當中,肯定是有對應的屬性,肯定是有這些屬性的set和get方法的。

model-and-view的add-object方法

我們看上圖中的,第二個方法。
我們說過model-and-view當中的model是用來裝載和傳輸數據的。
那么里面addObject方法,就是裝載和傳輸數據的過程。

我們前面通過return "success"這種方式,返回的就是視圖名稱。
現在我們通過modelAndView類的setViewName的方法,也可以設置視圖名稱。

所以,我們必須將ModelAndView對象,返回:

我們在request作用域中放了一個值,然后跳轉到了success.jsp,然后我們就可以在success.jsp當中獲取到request作用域中的值。
jsp當中jstl是c標簽
el表達式是為了從作用域中取值,pagecontext,request,session,Application四個作用域。從小到大逐個作用域尋找。


我們可以加上作用域。

測試效果如下:

所以:modelandview的作用是裝載數據,是往作用域中放置,view是設置視圖名稱,實現頁面跳轉。
16 - ModelAndView源碼調試
加載spring-webmvc的源碼,查看ModelAndView里面的東西。

我們看一下:



- getModelInternal
- getModelMap
- getModel
- 這三個方法是一樣的,都是獲取model對象,model就是一個map,就是多個鍵值對數據。
debug - 斷點




點擊yes之后,進入到下面的視圖:

調整視圖布局,變成下面的樣子:

- 雙擊打斷點,debug模式啟動項目,進入debug視圖,在debug框框中,顯示的是,執行到斷點位置,已經調用的方法。

1、DispatcherServlet.doDispatch(HttpServletRequest, HttpServletResponse)

- 上面的代碼中有一個mv,這個mv就是ModelAndView。
- 我們的代碼中,打斷點的位置,是要返回一個ModelAndView對象。
- 這里的代碼,意思就是通過ha.handle()方法,對請求進行了處理,獲得了一個mv對象。

為什么是空的,因為這一行,還沒有開始執行。斷點所在的位置,是還沒有執行的。

我們怎么從mv的代碼的地方,走到processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);的地方呢?

我們想要從mv的地方跑到processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);的地方
- 第一,我們可以通過step over一步一步執行。
- 第二,我們可以在
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);位置,打一個斷點,然后點擊resume,就可以直接跳到我們需要的位置。

在這個位置,mv的值是,如下圖所示:

2、進入processDispatchResult方法內部
進入方法內部,兩種方式:
- 第一,按住ctrl鍵,鼠標點進去。
- 第二,step into。如果當前位置,有多個方法被調用,會按照方法執行的順序,一個一個地進入。

我們在render(mv, request, response);位置打一個斷點,然后resume到render的位置,然后step into進去。
3、進入render方法內部
在這個render方法內部,已經把mv當中的view和model分開處理了。

在view.render(mv.getModelInternal(), request, response);的位置,我們打一個斷點,然后step into進入看看。
4、進入view.render()方法內部
view.render(mv.getModelInternal(), request, response);
這一行中有兩個方法,render()是一個方法,mv.getModelInternal()也是一個方法。
我們點擊step into之后,是mv.getModelInternal()這個方法先執行。
第一次,step into,進入mv.getModelInternal()方法內部。

第二次,step into,回到render方法的位置。

第三次,step into,這次是真正進入到render方法內部:

5、進入renderMergedOutputModel()方法內部

6、進入exposeModelAsRequestAttributes()方法內部

然后不斷step over,從這個exposeModelAsRequestAttributes()方法中出來。
7、回到renderMergedOutputModel()方法內部
ModelAndView的作用就是兩個:第一往作用域中放值,第二實現頁面跳轉。
原來我們在servlet當中,往作用域中放值,和實現頁面跳轉,分別是這么寫的。
request.setAttribute(key, value),往作用域中放值。
request.getRequestDispatcher.forward(),實現頁面跳轉

ModelAndView源碼調試總結

17 - 三種方式實現作用域放值
前面說過,往作用域中放值,是三種方式。
第一種方式

@RequestMapping(value="/param",method=RequestMethod.POST)
public ModelAndView param() {
ModelAndView mav = new ModelAndView();
mav.addObject("username", "root");
mav.setViewName("success");
return mav;
}
第二種方式

@RequestMapping(value="/param",method=RequestMethod.POST)
public String param(Map<String, Object> map) {
map.put("username", "admin");
return "success";
}
這種寫法,默認也會將上面的map和return “success”包裝成為ModelAndView對象的。
第三種方式

@RequestMapping(value="/param",method=RequestMethod.POST)
public String param(Model model) {
model.addAttribute("username", "zhangsan");
return "success";
}
通過model往作用域中放值,也會將model和"success"封裝成為ModelAndView對象的
總結
springmvc處理請求過程中,往作用域中放值,有以下三種方式:
- map.put("username","admin")
- Model.addAttribute("username","admin")
- ModelAndView.addObject("username","admin")
上面三種寫法,都會和view一起封裝到ModelAndView中。
當前亂碼問題
- 頁面發送請求,傳值
張三

- 我們在控制層的方法當中,接收了頁面傳值,看到控制台輸出是亂碼的:

- 作用域中放的值,頁面顯示是正常的。

為什么頁面傳值,控制層接收打印會亂碼呢?
這是因為第一,頁面傳值的時候,默認會以頁面的編碼為編碼格式。我們頁面傳過去的username默認是以utf-8編碼的。
但是tomcat接收數據的時候,默認是用iso-8859-1來接收的。
springmvc為我們提供了一個編碼過濾器,只要配置一下,就可以了。這個以后再說。
