看一段普通的代码,我们访问controller中的一个方法后,重定向到另外一个controller或者视图。
@RequestMapping(params="method=index") public ModelAndView index() { RedirectView redirectView = new RedirectView("/Demo.do?method=index2", true, true); ModelAndView mav = new ModelAndView(redirectView); mav.addObject("attr1", "attr1Value"); mav.addObject("attr2", "attr2Value"); return mav; }
浏览器的URL会变成http://localhost:8080/FuDeKang/Demo.do?method=index2&attr2=attr2Value&attr1=attr1Value
也就是说Spring会自定把model中的键值放入到URL当中,那么Spring是如何做到的呢,我么还来看ModelAndViewMethodReturnValueHandler这个类。
public class ModelAndViewMethodReturnValueHandler implements HandlerMethodReturnValueHandler { public boolean supportsReturnType(MethodParameter returnType) { return ModelAndView.class.isAssignableFrom(returnType.getParameterType()); } public void handleReturnValue( Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { if (returnValue == null) { mavContainer.setRequestHandled(true); return; } ModelAndView mav = (ModelAndView) returnValue; if (mav.isReference()) { String viewName = mav.getViewName(); mavContainer.setViewName(viewName); if (viewName != null && viewName.startsWith("redirect:")) { mavContainer.setRedirectModelScenario(true); } } else { View view = mav.getView(); mavContainer.setView(view); if (view instanceof SmartView) { if (((SmartView) view).isRedirectView()) { mavContainer.setRedirectModelScenario(true); } } } mavContainer.addAllAttributes(mav.getModel()); } }
其中最后一句是关键,首先modelandview当中的model数据全部放到ModelAndViewContainer 里面。
因为我们是重定向,所以无论如何底层最后产生的视图对象都是RedirectView实例,我们在看一下它的源码。
/** * Convert model to request parameters and redirect to the given URL. * @see #appendQueryProperties * @see #sendRedirect */ @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); flashMapManager.saveOutputFlashMap(flashMap, request, response); sendRedirect(request, response, targetUrl.toString(), this.http10Compatible); }
其中 targetUrl = updateTargetUrl(targetUrl, model, request, response); 是拼接了URL的代码,最后调用sendRedirect做重定向。