13.请求处理-【源码分析】-Model、Map原理
复杂参数:
Map
Model(map、model里面的数据会被放在request的请求域 request.setAttribute)
Errors/BindingResult
RedirectAttributes( 重定向携带数据)
ServletResponse(response)
SessionStatus
UriComponentsBuilder
ServletUriComponentsBuilder
@GetMapping(value = "/params")public String goToPage(Model model,Map map,HttpServletRequest request){map.put("map","map");model.addAttribute("model","model");request.setAttribute("msg","springboot2");request.setAttribute("code","200");return "forward:/success";}@ResponseBody@GetMapping(value = "/success")public Map success(@RequestAttribute(value = "msg",required = false)String msg,@RequestAttribute(value = "code",required = false)Integer code,HttpServletRequest request//与goToPage方法中的参数同样一个request){Map map = new HashMap<>();Object code1 = request.getAttribute("code");Object map1 = request.getAttribute("map");Object model = request.getAttribute("model");map.put("msg",msg);map.put("code1",code1);//利用requerst域获得的codemap.put("code",code);//利用注解@RequestAttribute获得的codemap.put("map1",map1);map.put("model",model);return map;}
Map
Model model
HttpServletRequest request
上面三位都是可以给request域中放数据,用request.getAttribute()获取
接下来我们看看,Map
@Nullablepublic Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);if (logger.isTraceEnabled()) {logger.trace("Arguments: " + Arrays.toString(args));}return this.doInvoke(args);}protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {MethodParameter[] parameters = this.getMethodParameters();if (ObjectUtils.isEmpty(parameters)) {return EMPTY_ARGS;} else {Object[] args = new Object[parameters.length];for(int i = 0; i < parameters.length; ++i) {MethodParameter parameter = parameters[i];parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);args[i] = findProvidedArgument(parameter, providedArgs);if (args[i] == null) {if (!this.resolvers.supportsParameter(parameter)) {throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));}try {args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);} catch (Exception var10) {if (logger.isDebugEnabled()) {String exMsg = var10.getMessage();if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {logger.debug(formatArgumentError(parameter, exMsg));}}throw var10;}}}return args;}}
Map参数用MapMethodProcessor处理:
public class MapMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {@Overridepublic boolean supportsParameter(MethodParameter parameter) {return (Map.class.isAssignableFrom(parameter.getParameterType()) &¶meter.getParameterAnnotations().length == 0);}@Override@Nullablepublic Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {Assert.state(mavContainer != null, "ModelAndViewContainer is required for model exposure");return mavContainer.getModel();}...}
public ModelMap getModel() {if (this.useDefaultModel()) {return this.defaultModel;} else {if (this.redirectModel == null) {this.redirectModel = new ModelMap();}return this.redirectModel;}}
agrs:Model也是另一种意义的Map。

参数处理完之后,开始调用该方法doInvoke
@Nullablepublic Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);if (logger.isTraceEnabled()) {logger.trace("Arguments: " + Arrays.toString(args));}return this.doInvoke(args);}
接下来看看Map
众所周知,所有的数据都放在 ModelAndView包含要去的页面地址View,还包含Model数据。
先看ModelAndView接下来是如何处理的。重点看processDispatchResult
public class DispatcherServlet extends FrameworkServlet {...protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {...try {ModelAndView mv = null;...// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());...}catch (Exception ex) {dispatchException = ex;}catch (Throwable err) {// As of 4.3, we're processing Errors thrown from handler methods as well,// making them available for @ExceptionHandler methods and other scenarios.dispatchException = new NestedServletException("Handler dispatch failed", err);}//处理分发结果processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}...}private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,@Nullable Exception exception) throws Exception {...// Did the handler return a view to render?if (mv != null && !mv.wasCleared()) {render(mv, request, response);...}...}protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {...View view;String viewName = mv.getViewName();//获取要转发的视图名if (viewName != null) {// We need to resolve the view name.view = resolveViewName(viewName, mv.getModelInternal(), locale, request);//解析视图if (view == null) {throw new ServletException("Could not resolve view with name '" + mv.getViewName() +"' in servlet with name '" + getServletName() + "'");}}else {// No need to lookup: the ModelAndView object contains the actual View object.view = mv.getView();if (view == null) {throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +"View object in servlet with name '" + getServletName() + "'");}}view.render(mv.getModelInternal(), request, response);...}}
调用resolveViewName,将 mv.getModelInternal()获得的参数值传入

step into resolveViewName
protected View resolveViewName(String viewName, @Nullable Map model, Locale locale, HttpServletRequest request) throws Exception {if (this.viewResolvers != null) {Iterator var5 = this.viewResolvers.iterator();while(var5.hasNext()) {ViewResolver viewResolver = (ViewResolver)var5.next();View view = viewResolver.resolveViewName(viewName, locale);if (view != null) {return view;}}}return null;}

判断用什么视图解析器进行解析,获得视图名之后开始进行进行页面的跳转
view.render(mv.getModelInternal(), request, response);

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale();response.setLocale(locale);String viewName = mv.getViewName();View view;if (viewName != null) {view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);if (view == null) {throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + this.getServletName() + "'");}} else {view = mv.getView();if (view == null) {throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + this.getServletName() + "'");}}if (this.logger.isTraceEnabled()) {this.logger.trace("Rendering view [" + view + "] ");}try {if (mv.getStatus() != null) {response.setStatus(mv.getStatus().value());}view.render(mv.getModelInternal(), request, response);} catch (Exception var8) {if (this.logger.isDebugEnabled()) {this.logger.debug("Error rendering view [" + view + "]", var8);}throw var8;}}
step int view.render(mv.getModelInternal(), request, response);
public void render(@Nullable Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {if (this.logger.isDebugEnabled()) {this.logger.debug("View " + this.formatViewName() + ", model " + (model != null ? model : Collections.emptyMap()) + (this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));}Map mergedModel = this.createMergedOutputModel(model, request, response);this.prepareResponse(request, response);this.renderMergedOutputModel(mergedModel, this.getRequestToExpose(request), response);}
step into createMergedOutputModel,如果model不为空,则直接放入要传输的数据给mergedModel
protected Map createMergedOutputModel(@Nullable Map model, HttpServletRequest request, HttpServletResponse response) {Map pathVars = this.exposePathVariables ? (Map)request.getAttribute(View.PATH_VARIABLES) : null;int size = this.staticAttributes.size();size += model != null ? model.size() : 0;size += pathVars != null ? pathVars.size() : 0;Map mergedModel = CollectionUtils.newLinkedHashMap(size);mergedModel.putAll(this.staticAttributes);if (pathVars != null) {mergedModel.putAll(pathVars);}if (model != null) {mergedModel.putAll(model);}if (this.requestContextAttribute != null) {mergedModel.put(this.requestContextAttribute, this.createRequestContext(request, response, mergedModel));}return mergedModel;}

返回之后,渲染输出的mergedModel

step into renderMergedOutputModel
protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {this.exposeModelAsRequestAttributes(model, request);this.exposeHelpers(request);String dispatcherPath = this.prepareForRendering(request, response);RequestDispatcher rd = this.getRequestDispatcher(request, dispatcherPath);if (rd == null) {throw new ServletException("Could not get RequestDispatcher for [" + this.getUrl() + "]: Check that the corresponding file exists within your web application archive!");} else {if (this.useInclude(request, response)) {response.setContentType(this.getContentType());if (this.logger.isDebugEnabled()) {this.logger.debug("Including [" + this.getUrl() + "]");}rd.include(request, response);} else {if (this.logger.isDebugEnabled()) {this.logger.debug("Forwarding to [" + this.getUrl() + "]");}rd.forward(request, response);}}
}
将传入过来的mergeModel的数据放入request域中
protected void exposeModelAsRequestAttributes(Map model, HttpServletRequest request) throws Exception {model.forEach((name, value) -> {if (value != null) {request.setAttribute(name, value);} else {request.removeAttribute(name);}});}
exposeModelAsRequestAttributes方法看出,Map,Model model这两种类型数据可以给request域中放数据,用request.getAttribute()获取。over
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
