参数解析实现(@RequestBody)
RequestResponseBodyMethodProcessor.supportsParamter()
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 ( ) ; 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) ;
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) { 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 ) { 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 ( ) ) ; } if ( 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()
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 {
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 ( ) { @Override public OutputStream getBody ( ) { return outputStream; } @Override public 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 ) ; } } 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 ( ) ) { return ; } if ( mappedHandler != null ) { 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) ; if ( 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) ; View view = this . viewAccessCache. get ( cacheKey) ; if ( view == null ) { synchronized ( this . viewCreationCache) { view = this . viewCreationCache. get ( cacheKey) ; if ( view == null ) { view = 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" ) ; } } return ( view != UNRESOLVED_VIEW ? view : null ) ; } }
UrlBasedViewResolver.createView()
protected View createView ( String viewName, Locale locale) throws Exception { if ( ! canHandle ( viewName, locale) ) { return null ; } 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) ; } 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) ; } return super . createView ( viewName, locale) ; }
UrlBasedViewResolver.loadView()
protected View loadView ( String viewName, Locale locale) throws Exception { AbstractUrlBasedView view = buildView ( viewName) ; View result = applyLifecycleMethods ( viewName, view) ; return ( view. checkResource ( locale) ? result : null ) ; }
UrlBasedViewResolver.buildView()
protected AbstractUrlBasedView buildView ( String viewName) throws Exception { AbstractUrlBasedView view = instantiateView ( ) ; view. setUrl ( getPrefix ( ) + viewName + getSuffix ( ) ) ; view. setAttributesMap ( getAttributesMap ( ) ) ; String contentType = getContentType ( ) ; if ( contentType != null ) { view. setContentType ( contentType) ; }
String requestContextAttribute = getRequestContextAttribute ( ) ; if ( requestContextAttribute != null ) { view. setRequestContextAttribute ( requestContextAttribute) ; }
Boolean exposePathVariables = getExposePathVariables ( ) ; if ( exposePathVariables != null ) { view. setExposePathVariables ( exposePathVariables) ; } Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes ( ) ; if ( exposeContextBeansAsAttributes != null ) { view. setExposeContextBeansAsAttributes ( exposeContextBeansAsAttributes) ; } String [ ] exposedContextBeanNames = getExposedContextBeanNames ( ) ; if ( exposedContextBeanNames != null ) { view. setExposedContextBeanNames ( exposedContextBeanNames) ; } return view; }
protected Class < ? > requiredViewClass ( ) { return FreeMarkerView . class ; }
运行结果处理
DispatcherServlet.applyDefultViewName()
private void applyDefaultViewName ( HttpServletRequest request, @Nullable ModelAndView mv) throws Exception { if ( 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 ) ; }
public String getViewName ( HttpServletRequest request) { 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 { Locale locale = ( this . localeResolver != null ? this . localeResolver. resolveLocale ( request) : request. getLocale ( ) ) ; response. setLocale ( locale) ; View view; String viewName = mv. getViewName ( ) ; if ( viewName != null ) { 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 { 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 ( ) + "'" ) ; } } 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()
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) ; }