当前位置: 首页 > news >正文

SpringMVC执行流程源码分析之二

参数解析实现(@RequestBody)

RequestResponseBodyMethodProcessor.supportsParamter()

//能够解析方法上带有@RequestBody注解handler
public boolean supportsParameter(MethodParameter parameter) {return parameter.hasParameterAnnotation(RequestBody.class);}

RequestResponseBodyMethodProcessor.resolveArgument()

public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {parameter = parameter.nestedIfOptional();//读取HTTP报文Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());String name = Conventions.getVariableNameForParameter(parameter);if (binderFactory != null) {WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);if (arg != null) {validateIfApplicable(binder, parameter);if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());}}if (mavContainer != null) {mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());}}return adaptArgumentIfNecessary(arg, parameter);}

equestResponseBodyMethodProcessor.readWithMessageConverters()

protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);Assert.state(servletRequest != null, "No HttpServletRequest");ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
//调用父级的readWithMessageConverters解析参数Object arg = readWithMessageConverters(inputMessage, parameter, paramType);if (arg == null && checkRequired(parameter)) {throw new HttpMessageNotReadableException("Required request body is missing: " +parameter.getExecutable().toGenericString(), inputMessage);}return arg;}

bstractMessageConvertMethodArgumentResolver.adapterArgumentIfNecessary()

protected Object adaptArgumentIfNecessary(@Nullable Object arg, MethodParameter parameter) {//判断参数是否为Optional类型 进行适配处理if (parameter.getParameterType() == Optional.class) {if (arg == null || (arg instanceof Collection && ((Collection<?>) arg).isEmpty()) ||(arg instanceof Object[] && ((Object[]) arg).length == 0)) {return Optional.empty();}else {return Optional.of(arg);}}return arg;}

AbstractMessageConvertMethodArgumentResolver.readWithMessageConverters()

protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {MediaType contentType;boolean noContentType = false;try {contentType = inputMessage.getHeaders().getContentType();}catch (InvalidMediaTypeException ex) {throw new HttpMediaTypeNotSupportedException(ex.getMessage());}if (contentType == null) {noContentType = true;contentType = MediaType.APPLICATION_OCTET_STREAM;}Class<?> contextClass = parameter.getContainingClass();Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);if (targetClass == null) {ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);targetClass = (Class<T>) resolvableType.resolve();}HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);Object body = NO_VALUE;EmptyBodyCheckingHttpInputMessage message;try {message = new EmptyBodyCheckingHttpInputMessage(inputMessage);for (HttpMessageConverter<?> converter : this.messageConverters) {Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();GenericHttpMessageConverter<?> genericConverter =(converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :(targetClass != null && converter.canRead(targetClass, contentType))) {if (message.hasBody()) {HttpInputMessage msgToUse =getAdvice().beforeBodyRead(message, parameter, targetType, converterType);body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);}else {body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);}break;}}}catch (IOException ex) {throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);}if (body == NO_VALUE) {if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||(noContentType && !message.hasBody())) {return null;}throw new HttpMediaTypeNotSupportedException(contentType,getSupportedMediaTypes(targetClass != null ? targetClass : Object.class));}MediaType selectedContentType = contentType;Object theBody = body;LogFormatUtils.traceDebug(logger, traceOn -> {String formatted = LogFormatUtils.formatValue(theBody, !traceOn);return "Read \"" + selectedContentType + "\" to [" + formatted + "]";});return body;}

参数解析实现(@RequestParam)

bstractNamedValueMethodArgumentResolver.resolveArgument()

public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);MethodParameter nestedParameter = parameter.nestedIfOptional();
//获取参数名Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name);if (resolvedName == null) {throw new IllegalArgumentException("Specified name must not resolve to null: [" + namedValueInfo.name + "]");}
//获取参数值Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);if (arg == null) {//参数值为null 默认值不为null 则取默认值if (namedValueInfo.defaultValue != null) {arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);}else if (namedValueInfo.required && !nestedParameter.isOptional()) {handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);}arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());}else if ("".equals(arg) && namedValueInfo.defaultValue != null) {arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);}if (binderFactory != null) {WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);try {arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);}catch (ConversionNotSupportedException ex) {throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),namedValueInfo.name, parameter, ex.getCause());}catch (TypeMismatchException ex) {throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),namedValueInfo.name, parameter, ex.getCause());}// Check for null value after conversion of incoming argument valueif (arg == null && namedValueInfo.defaultValue == null &&namedValueInfo.required && !nestedParameter.isOptional()) {handleMissingValueAfterConversion(namedValueInfo.name, nestedParameter, webRequest);}}handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);return arg;}

RequestParamMethodArgumentResolver.supportsParameter()

public boolean supportsParameter(MethodParameter parameter) {if (parameter.hasParameterAnnotation(RequestParam.class)) {if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);return (requestParam != null && StringUtils.hasText(requestParam.name()));}else {return true;}}else {if (parameter.hasParameterAnnotation(RequestPart.class)) {return false;}parameter = parameter.nestedIfOptional();if (MultipartResolutionDelegate.isMultipartArgument(parameter)) {return true;}else if (this.useDefaultResolution) {return BeanUtils.isSimpleProperty(parameter.getNestedParameterType());}else {return false;}}}protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);if (servletRequest != null) {Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {return mpArg;}}Object arg = null;MultipartRequest multipartRequest = request.getNativeRequest(MultipartRequest.class);if (multipartRequest != null) {List<MultipartFile> files = multipartRequest.getFiles(name);if (!files.isEmpty()) {arg = (files.size() == 1 ? files.get(0) : files);}}if (arg == null) {String[] paramValues = request.getParameterValues(name);if (paramValues != null) {arg = (paramValues.length == 1 ? paramValues[0] : paramValues);}}return arg;}protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {RequestParam ann = parameter.getParameterAnnotation(RequestParam.class);return (ann != null ? new RequestParamNamedValueInfo(ann) : new RequestParamNamedValueInfo());}

返回值解析实现

HandlerMethodReturnValueHandlerComposite.handleReturnValue()

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//获取能解析当前返回值的解析器HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);if (handler == null) {throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());}//执行handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);}private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {boolean isAsyncValue = isAsyncReturnValue(value, returnType);for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {continue;}if (handler.supportsReturnType(returnType)) {return handler;}}return null;}

RequestResponseBodyMethodProcessor.handleReturnValue()

//支持有@ResponseBody注解的方法
public boolean supportsReturnType(MethodParameter returnType) {return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||returnType.hasMethodAnnotation(ResponseBody.class));}
//处理返回值
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
//设置requestHandled为true 说明当前返回的是json,不是页面名称mavContainer.setRequestHandled(true);ServletServerHttpRequest inputMessage = createInputMessage(webRequest);ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);}

AbstractMessageConverterMethodProcessor.writeWithMessageConverters()

protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {Object body;Class<?> valueType;Type targetType;if (value instanceof CharSequence) {body = value.toString();valueType = String.class;targetType = String.class;}else {body = value;valueType = getReturnValueType(body, returnType);targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass());}if (isResourceType(value, returnType)) {outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.RANGE) != null &&outputMessage.getServletResponse().getStatus() == 200) {Resource resource = (Resource) value;try {List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value());body = HttpRange.toResourceRegions(httpRanges, resource);valueType = body.getClass();targetType = RESOURCE_REGION_LIST_TYPE;}catch (IllegalArgumentException ex) {outputMessage.getHeaders().set(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength());outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value());}}}MediaType selectedMediaType = null;MediaType contentType = outputMessage.getHeaders().getContentType();boolean isContentTypePreset = contentType != null && contentType.isConcrete();if (isContentTypePreset) {if (logger.isDebugEnabled()) {logger.debug("Found 'Content-Type:" + contentType + "' in response");}selectedMediaType = contentType;}else {HttpServletRequest request = inputMessage.getServletRequest();List<MediaType> acceptableTypes;try {acceptableTypes = getAcceptableMediaTypes(request);}catch (HttpMediaTypeNotAcceptableException ex) {int series = outputMessage.getServletResponse().getStatus() / 100;if (body == null || series == 4 || series == 5) {if (logger.isDebugEnabled()) {logger.debug("Ignoring error response content (if any). " + ex);}return;}throw ex;}List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType);if (body != null && producibleTypes.isEmpty()) {throw new HttpMessageNotWritableException("No converter found for return value of type: " + valueType);}List<MediaType> mediaTypesToUse = new ArrayList<>();for (MediaType requestedType : acceptableTypes) {for (MediaType producibleType : producibleTypes) {if (requestedType.isCompatibleWith(producibleType)) {mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));}}}if (mediaTypesToUse.isEmpty()) {if (body != null) {throw new HttpMediaTypeNotAcceptableException(producibleTypes);}if (logger.isDebugEnabled()) {logger.debug("No match for " + acceptableTypes + ", supported: " + producibleTypes);}return;}MediaType.sortBySpecificityAndQuality(mediaTypesToUse);for (MediaType mediaType : mediaTypesToUse) {if (mediaType.isConcrete()) {selectedMediaType = mediaType;break;}else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;break;}}if (logger.isDebugEnabled()) {logger.debug("Using '" + selectedMediaType + "', given " +acceptableTypes + " and supported " + producibleTypes);}}if (selectedMediaType != null) {selectedMediaType = selectedMediaType.removeQualityValue();for (HttpMessageConverter<?> converter : this.messageConverters) {GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?(GenericHttpMessageConverter<?>) converter : null);if (genericConverter != null ?((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :converter.canWrite(valueType, selectedMediaType)) {body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,(Class<? extends HttpMessageConverter<?>>) converter.getClass(),inputMessage, outputMessage);if (body != null) {Object theBody = body;LogFormatUtils.traceDebug(logger, traceOn ->"Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");addContentDispositionHeader(inputMessage, outputMessage);if (genericConverter != null) {genericConverter.write(body, targetType, selectedMediaType, outputMessage);}else {((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);}}else {if (logger.isDebugEnabled()) {logger.debug("Nothing to write: null body");}}return;}}}if (body != null) {Set<MediaType> producibleMediaTypes =(Set<MediaType>) inputMessage.getServletRequest().getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);if (isContentTypePreset || !CollectionUtils.isEmpty(producibleMediaTypes)) {throw new HttpMessageNotWritableException("No converter for [" + valueType + "] with preset Content-Type '" + contentType + "'");}throw new HttpMediaTypeNotAcceptableException(getSupportedMediaTypes(body.getClass()));}}

AbstractHttpMessageConverter.write()

public final void write(final T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)throws IOException, HttpMessageNotWritableException {final HttpHeaders headers = outputMessage.getHeaders();addDefaultHeaders(headers, t, contentType);if (outputMessage instanceof StreamingHttpOutputMessage) {StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) outputMessage;streamingOutputMessage.setBody(outputStream -> writeInternal(t, new HttpOutputMessage() {@Overridepublic OutputStream getBody() {return outputStream;}@Overridepublic HttpHeaders getHeaders() {return headers;}}));}else {writeInternal(t, outputMessage);outputMessage.getBody().flush();}}

AbstractGenericHttpMessageConverter.writeInternal()

protected void writeInternal(T t, HttpOutputMessage outputMessage)throws IOException, HttpMessageNotWritableException {writeInternal(t, null, outputMessage);}

AbstractJackjson2HttpMessageConverter.writeInternal()

protected void writeInternal(Object object, @Nullable Type type, HttpOutputMessage outputMessage)throws IOException, HttpMessageNotWritableException {MediaType contentType = outputMessage.getHeaders().getContentType();JsonEncoding encoding = getJsonEncoding(contentType);Class<?> clazz = (object instanceof MappingJacksonValue ?((MappingJacksonValue) object).getValue().getClass() : object.getClass());ObjectMapper objectMapper = selectObjectMapper(clazz, contentType);Assert.state(objectMapper != null, "No ObjectMapper for " + clazz.getName());OutputStream outputStream = StreamUtils.nonClosing(outputMessage.getBody());try (JsonGenerator generator = objectMapper.getFactory().createGenerator(outputStream, encoding)) {writePrefix(generator, object);Object value = object;Class<?> serializationView = null;FilterProvider filters = null;JavaType javaType = null;if (object instanceof MappingJacksonValue) {MappingJacksonValue container = (MappingJacksonValue) object;value = container.getValue();serializationView = container.getSerializationView();filters = container.getFilters();}if (type != null && TypeUtils.isAssignable(type, value.getClass())) {javaType = getJavaType(type, null);}ObjectWriter objectWriter = (serializationView != null ?objectMapper.writerWithView(serializationView) : objectMapper.writer());if (filters != null) {objectWriter = objectWriter.with(filters);}if (javaType != null && javaType.isContainerType()) {objectWriter = objectWriter.forType(javaType);}SerializationConfig config = objectWriter.getConfig();if (contentType != null && contentType.isCompatibleWith(MediaType.TEXT_EVENT_STREAM) &&config.isEnabled(SerializationFeature.INDENT_OUTPUT)) {objectWriter = objectWriter.with(this.ssePrettyPrinter);}objectWriter.writeValue(generator, value);writeSuffix(generator, object);generator.flush();}catch (InvalidDefinitionException ex) {throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);}catch (JsonProcessingException ex) {throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getOriginalMessage(), ex);}}

视图解析实现

DispatcherServlet.processDispatchResult()

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,@Nullable Exception exception) throws Exception {boolean errorView = false;if (exception != null) {if (exception instanceof ModelAndViewDefiningException) {logger.debug("ModelAndViewDefiningException encountered", exception);mv = ((ModelAndViewDefiningException) exception).getModelAndView();}else {Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);mv = processHandlerException(request, response, handler, exception);errorView = (mv != null);}}// Did the handler return a view to render?if (mv != null && !mv.wasCleared()) {render(mv, request, response);if (errorView) {WebUtils.clearErrorRequestAttributes(request);}}else {if (logger.isTraceEnabled()) {logger.trace("No view rendering, null ModelAndView returned.");}}if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {// Concurrent handling started during a forwardreturn;}if (mappedHandler != null) {// Exception (if any) is already handled..mappedHandler.triggerAfterCompletion(request, response, null);}}

DispacherServlet.resolveViewName()

protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,Locale locale, HttpServletRequest request) throws Exception {
//遍历所有的视图解析器if (this.viewResolvers != null) {for (ViewResolver viewResolver : this.viewResolvers) {View view = viewResolver.resolveViewName(viewName, locale);//找到能解析当前视图的解析器,并且解析完成,返回Viewif (view != null) {return view;}}}return null;}

AbstractCachingViewResolver.resolveViewName()

public View resolveViewName(String viewName, Locale locale) throws Exception {//是否从缓存中获取if (!isCache()) {return createView(viewName, locale);}else {//先从缓存中获取Object cacheKey = getCacheKey(viewName, locale);//第一个map是支持并发获取的ConcurrentHashMapView view = this.viewAccessCache.get(cacheKey);if (view == null) {//如果缓存中没有synchronized (this.viewCreationCache) {//第二个map是能提供对于缓存溢出时候的清除工作(LinkedHashMap的removeEldestEntry方法)view = this.viewCreationCache.get(cacheKey);if (view == null) {//则创建Viewview = createView(viewName, locale);if (view == null && this.cacheUnresolved) {view = UNRESOLVED_VIEW;}if (view != null && this.cacheFilter.filter(view, viewName, locale)) {//放到缓存中this.viewAccessCache.put(cacheKey, view);this.viewCreationCache.put(cacheKey, view);}}}}else {if (logger.isTraceEnabled()) {logger.trace(formatKey(cacheKey) + "served from cache");}}//返回Viewreturn (view != UNRESOLVED_VIEW ? view : null);}}

UrlBasedViewResolver.createView()

protected View createView(String viewName, Locale locale) throws Exception {// If this resolver is not supposed to handle the given view,// return null to pass on to the next resolver in the chain.if (!canHandle(viewName, locale)) {return null;}//处理viewName中前缀是redirect:的视图 重定向if (viewName.startsWith(REDIRECT_URL_PREFIX)) {String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());RedirectView view = new RedirectView(redirectUrl,isRedirectContextRelative(), isRedirectHttp10Compatible());String[] hosts = getRedirectHosts();if (hosts != null) {view.setHosts(hosts);}return applyLifecycleMethods(REDIRECT_URL_PREFIX, view);}//处理viewName中前缀是forward:的视图 转发if (viewName.startsWith(FORWARD_URL_PREFIX)) {String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());InternalResourceView view = new InternalResourceView(forwardUrl);return applyLifecycleMethods(FORWARD_URL_PREFIX, view);}//一般返回值,转发不带前缀forward,重定向才携带return super.createView(viewName, locale);}

UrlBasedViewResolver.loadView()

protected View loadView(String viewName, Locale locale) throws Exception {//创建View对象AbstractUrlBasedView view = buildView(viewName);//对view属性进行初始化View result = applyLifecycleMethods(viewName, view);return (view.checkResource(locale) ? result : null);}

UrlBasedViewResolver.buildView()

protected AbstractUrlBasedView buildView(String viewName) throws Exception {//获取View对应的class (UrlBasedViewResolver子类中每一个类型都有只处理一个View对象)//比如FreeMarkerViewResolver 的viewClass 为FreeMarkerView//InternalResourceViewResolver的viewClass为JstlView//获取view class 并进行实例化AbstractUrlBasedView view = instantiateView();////设置view的urlview.setUrl(getPrefix() + viewName + getSuffix());view.setAttributesMap(getAttributesMap());//设置view的contentTypeString contentType = getContentType();if (contentType != null) {view.setContentType(contentType);}
//设置view的requestContextAttribute 用于持有request对象的beanNameString requestContextAttribute = getRequestContextAttribute();if (requestContextAttribute != null) {view.setRequestContextAttribute(requestContextAttribute);}
//是否支持view使用PathVariables(url中的参数)Boolean exposePathVariables = getExposePathVariables();if (exposePathVariables != null) {view.setExposePathVariables(exposePathVariables);}//是否支持view可以使用spring容器中的bean实例Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes();if (exposeContextBeansAsAttributes != null) {view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes);}//是否配置view可以使用spring容器中的那些bean实例String[] exposedContextBeanNames = getExposedContextBeanNames();if (exposedContextBeanNames != null) {view.setExposedContextBeanNames(exposedContextBeanNames);}return view;}// getViewClass()方法获取viewClass,其UrlBasedViewResolver子类遵循每一个实例都对应一个viewClass其通过requiredViewClass来保证必须符合,则子类只需要setView()就可以完成相关功能。
protected Class<?> requiredViewClass() {return FreeMarkerView.class;}

运行结果处理

DispatcherServlet.applyDefultViewName()

private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {//没有没有View  则设置一个默认的viewNameif (mv != null && !mv.hasView()) {String defaultViewName = getDefaultViewName(request);if (defaultViewName != null) {mv.setViewName(defaultViewName);}}}
protected String getDefaultViewName(HttpServletRequest request) throws Exception {return (this.viewNameTranslator != null ? this.viewNameTranslator.getViewName(request) : null);}
//DefaultRequestToViewNameTranslator
public String getViewName(HttpServletRequest request) {//根据配置的一些通用url进行匹配String path = ServletRequestPathUtils.getCachedPathValue(request);return (this.prefix + transformPath(path) + this.suffix);}

HandlerExecutionChain.applyPosHandle()

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)throws Exception {
//拦截器后置处理器 遍历所有的拦截器for (int i = this.interceptorList.size() - 1; i >= 0; i--) {HandlerInterceptor interceptor = this.interceptorList.get(i);interceptor.postHandle(request, response, this.handler, mv);}}

DispatcherServlet.render()

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {// Determine locale for request and apply it to the response.Locale locale =(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());response.setLocale(locale);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() + "'");}}// Delegate to the View object for rendering.if (logger.isTraceEnabled()) {logger.trace("Rendering view [" + view + "] ");}try {if (mv.getStatus() != null) {response.setStatus(mv.getStatus().value());}view.render(mv.getModelInternal(), request, response);}catch (Exception ex) {if (logger.isDebugEnabled()) {logger.debug("Error rendering view [" + view + "]", ex);}throw ex;}}

View.render()

//AbstractView 
//抽象类AbstractView执行对数据进行组装,输出操作交由子类完成
public void render(@Nullable Map<String, ?> model, HttpServletRequest request,HttpServletResponse response) throws Exception {if (logger.isDebugEnabled()) {logger.debug("View " + formatViewName() +", model " + (model != null ? model : Collections.emptyMap()) +(this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));}//组装数据Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);prepareResponse(request, response);//渲染输出数据renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);}
http://www.dtcms.com/a/606741.html

相关文章:

  • 网站查询备案网站群建设调研报告
  • TreeSet的排序方式
  • FILE的本质
  • 5.5、Python-字符串去重
  • (论文速读)基于拉曼光谱深度学习的改进拉曼半定量分析成像去噪方法
  • 自然的算法:从生物进化到智能优化 —— 遗传算法的诗意与硬核“
  • wp企业网站模板网站模块建设方案
  • 使用腾讯云建设网站教程黄页网站建设
  • 基于微信小程序的民宿预定系统
  • 网站建设域名空间网站建设项目签约仪式举行
  • 做网站应该用什么数据库做五金有哪些网站推广
  • 积分法对IMU(陀螺仪加速度计) LSB(Least Significant Bit)验证
  • 爱网站最新发布址做淘宝网站怎么弄
  • 物理信道、信号、映射的介绍
  • 个人站长做网站需要多少钱wordpress转换为html
  • 如何处理自动化测试中的动态元素?
  • soular实战教程系列(1) - 安装与配置
  • JS宏连接数据库:使用Connections创建的对象
  • 如何建立公司网站是什么自己的服务器做网站域名解析
  • 设计一款高效的短链服务系统
  • 算法33.0
  • 建造个网站花多少钱今天福州头条新闻
  • 优秀简历制作网站wordpress主题更换字体教程 hu
  • 如何在沟通不畅导致误解后进行修复
  • c语言编译器哪个好用 | 探讨选择合适C语言编译器的标准与建议
  • 广州十度网络网站开发最好潍坊网站seo
  • 38.附近商户实现
  • 做网站 帮别人卖服务器成都网站设计
  • 园林景观网站源码做网站前应该先出图
  • Zookeeper 基础入门与应用场景解析