1. 程式人生 > >springMVC原始碼分析--頁面跳轉RedirectView(三)

springMVC原始碼分析--頁面跳轉RedirectView(三)

跳轉的示例:

@RequestMapping("/index")
	public String index(Model model,RedirectAttributes attr){
		attr.addAttribute("attributeName", "attributeValue");
		model.addAttribute("book", "金剛經");
		model.addAttribute("description","不擦擦擦擦擦擦擦車"+new Random().nextInt(100));
		model.addAttribute("price", new Double("1000.00"));
		model.addAttribute("attributeName1", "attributeValue1");
		//跳轉之前將資料儲存到book、description和price中,因為註解@SessionAttribute中有這幾個引數
		return "redirect:get.action";
	}
返回的值為“redirect:get.action”,這樣在處理之後我們會看到瀏覽器會跳轉到get.action中,首先我們需要了解請求的跳轉會在瀏覽器中修改請求連結,這樣跳轉的請求和原請求就是兩個不相干的請求,跳轉的請求會丟失掉原請求的中的所有資料,一般的解決方法是將原請求中的資料放到跳轉請求的連結中這樣來獲取資料。接下來我們看看springMVC的RediectView所做的處理,讓我們不用關心原請求中的值問題。

首先當返回值為"redirect:get.action"時,會呼叫ViewNameMethodReturnValueHandler的handleReturnValue方法,判斷是否是跳轉頁面,設定跳轉標記

ViewNameMethodReturnValueHandler中的實現如下:

@Override
	public void handleReturnValue(Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

		if (returnValue instanceof CharSequence) {
			String viewName = returnValue.toString();
			mavContainer.setViewName(viewName);
			//用於判斷是否是跳轉頁面 redirect
			if (isRedirectViewName(viewName)) {
				mavContainer.setRedirectModelScenario(true);
			}
		}
		else if (returnValue != null){
			// should not happen
			throw new UnsupportedOperationException("Unexpected return type: " +
					returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
		}
	}
當判斷頁面是跳轉頁面是ViewResolver生成的View物件是RedirectView,這樣就可以實現頁面跳轉工作了。

接下來我們看看在RedirectView中所做的操作,最終的實現是在renderMergedOutputModel中完成實現的,這邊需要實現的機制是在連線重定向時資料會丟失,這樣使用FlashMap將資料儲存起來作為重定向後的資料使用。

@Override
	protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		//建立跳轉連結
		String targetUrl = createTargetUrl(model, request);
		targetUrl = updateTargetUrl(targetUrl, model, request, response);
		//獲取原請求所攜帶的資料
		FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);
		if (!CollectionUtils.isEmpty(flashMap)) {
			UriComponents uriComponents = UriComponentsBuilder.fromUriString(targetUrl).build();
			flashMap.setTargetRequestPath(uriComponents.getPath());
			flashMap.addTargetRequestParams(uriComponents.getQueryParams());
			FlashMapManager flashMapManager = RequestContextUtils.getFlashMapManager(request);
			if (flashMapManager == null) {
				throw new IllegalStateException("FlashMapManager not found despite output FlashMap having been set");
			}
			//將資料儲存起來,作為跳轉之後請求的資料使用
			flashMapManager.saveOutputFlashMap(flashMap, request, response);
		}
		//重定向操作
		sendRedirect(request, response, targetUrl, this.http10Compatible);
	}

簡單來說RedirectView實現了連結的重定向,並且將資料儲存到FlashMap中,這樣在跳轉後的連結中可以獲取一些資料。