SpringMVC流程及源码分析

二、源码分析

以下源码来源jar包:spring-webmvc-5.25.RELEASE.jar

1、初始化

1.1、ApplicationContext

ApplicationContext初始化入口类:ApplicationObjectSupport的setApplicationContext方法,setApplicationContext方法中核心部分就是初始化容器initApplicationContext(context),子类AbstractDetectingUrlHandlerMapping实现了该方法。

类图:

2021022601-06-RequestMappingHandlerMapping类层次图

UML图:

2021022601-07-RequestMappingHandlerMapping-uml

RequestMappingHandlerMapping ,用于注解@Controller,@RequestMapping来定义controller.

初始化时,3个类的大致分工如下:

AbstractHandlerMethodMapping定义整个算法流程;

RequestMappingInfoHandlerMapping提供匹配条件RequestMappingInfo的解析处理;

RequestMappingHandlerMapping根据@RequestMapping注解生成 RequestMappingInfo,同时提供isHandler实现

2、前端控制器(中央处理器)DistepcherServlet

从上面的流程图可以看到前端控制器(中央处理器)DistepcherServlet是SpringMVC核心,查看DistepcherServlet类的继承情况。

UML图:

![2021022601-08-DispatcherServlet UML图](https://gitee.com/chuchq/blogs-gallery/raw/master/images / 2021/2021022601-08-DispatcherServlet UML图.png)

从继承关系看出:

DistepcherServlet ---> FrameworkServlet ---> HttpServletBean---> HttpServlet

那就说明DistepcherServlet 类也是一个Servlet类,那最终核心的方法就是service()方法,即Servlet的核心方法。

那就找service()方法,在DistepcherServlet中没有servic()方法,在父类FrameworkServlet有service()方法,源码如下:

来源:

org.springframework.web.servlet.FrameworkServlet.service(HttpServletRequest request, HttpServletResponse response)

/**

* Override the parent class implementation in order to intercept PATCH requests.

*/

@Override

protected void service(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());

if (httpMethod == HttpMethod.PATCH || httpMethod == null) {

processRequest(request, response);

}

else {

super.service(request, response);

}

}

可以看到:

FrameworkServlet.service(HttpServletRequest request, HttpServletResponse response)拿到request请求,判断当前请求是否是PATCH请求,不是的就调用父类的servic()方法,掉用父类中的service方法就是去调用该类中doPost(),doGet()方法,根据不同的请求方式然后走doPost()或者doGet(),调用中以doGet()为例,

FrameworkServlet类的doGet()源码:

/**

* Delegate GET requests to processRequest/doService.

* <p>Will also be invoked by HttpServlet's default implementation of {@code doHead},

* with a {@code NoBodyResponse} that just captures the content length.

* @see #doService

* @see #doHead

*/

@Override

protected final void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

processRequest(request, response);

}

doGet()又调用FrameworkServlet类中的processRequest(request, response);

/**

* Process this request, publishing an event regardless of the outcome.

* <p>The actual event handling is performed by the abstract

* {@link #doService} template method.

*/

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

long startTime = System.currentTimeMillis();

Throwable failureCause = null;

LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();

LocaleContext localeContext = buildLocaleContext(request);

RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();

ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

initContextHolders(request, localeContext, requestAttributes);

try {

doService(request, response);

}

catch (ServletException | IOException ex) {

failureCause = ex;

throw ex;

}

catch (Throwable ex) {

failureCause = ex;

throw new NestedServletException("Request processing failed", ex);

}

finally {

resetContextHolders(request, previousLocaleContext, previousAttributes);

if (requestAttributes != null) {

requestAttributes.requestCompleted();

}

logResult(request, response, failureCause, asyncManager);

publishRequestHandledEvent(request, response, startTime, failureCause);

}

}

processRequest(request, response)方法中最关键的又调用了doService(request, response);查看FrameworkServlet类中的doService(request, response),或者是调试跟踪可知,doService(request, response)由子类DispatcherServlet实现。

源码来源:

org.springframework.web.servlet.FrameworkServlet.doService(HttpServletRequest request, HttpServletResponse response)

/**

* Subclasses must implement this method to do the work of request handling,

* receiving a centralized callback for GET, POST, PUT and DELETE.

* <p>The contract is essentially the same as that for the commonly overridden

* {@code doGet} or {@code doPost} methods of HttpServlet.

* <p>This class intercepts calls to ensure that exception handling and

* event publication takes place.

* @param request current HTTP request

* @param response current HTTP response

* @throws Exception in case of any kind of processing failure

* @see javax.servlet.http.HttpServlet#doGet

* @see javax.servlet.http.HttpServlet#doPost

*/

protected abstract void doService(HttpServletRequest request, HttpServletResponse response)

throws Exception;

查看DispatcherServlet中的doService(HttpServletRequest request, HttpServletResponse response)方法

/**

* Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}

* for the actual dispatching.

*/

@Override

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {

logRequest(request);

// Keep a snapshot of the request attributes in case of an include,

// to be able to restore the original attributes after the include.

Map<String, Object> attributesSnapshot = null;

if (WebUtils.isIncludeRequest(request)) {

attributesSnapshot = new HashMap<>();

Enumeration<?> attrNames = request.getAttributeNames();

while (attrNames.hasMoreElements()) {

String attrName = (String) attrNames.nextElement();

if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {

attributesSnapshot.put(attrName, request.getAttribute(attrName));

}

}

}

// Make framework objects available to handlers and view objects.

request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());

request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);

request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);

request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

if (this.flashMapManager != null) {

FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);

if (inputFlashMap != null) {

request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));

}

request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());

request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

}

try {

doDispatch(request, response);

}

finally {

if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {

// Restore the original attribute snapshot, in case of an include.

if (attributesSnapshot != null) {

restoreAttributesAfterInclude(request, attributesSnapshot);

}

}

}

}

DispatcherServlet的doService()方法中最终调用doDispatch(request, response),查看源码如下:

org.springframework.web.servlet.DispatcherServlet.doDispatch()

/**

* Process the actual dispatching to the handler.

* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.

* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters

* to find the first that supports the handler class.

* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers

* themselves to decide which methods are acceptable.

* @param request current HTTP request

* @param response current HTTP response

* @throws Exception in case of any kind of processing failure

*/

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

HttpServletRequest processedRequest = request;

HandlerExecutionChain mappedHandler = null;

boolean multipartRequestParsed = false;

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

try {

ModelAndView mv = null;

Exception dispatchException = null;

try {

// 文件上传相关,判断是不是二进制请求

processedRequest = checkMultipart(request);

multipartRequestParsed = (processedRequest != request);

// 取得处理当前请求的controller,这里也称为hanlder处理器,第一个步骤的意义就在这里体现了.这里并不是直接返回controller,而是返回的HandlerExecutionChain请求处理器链对象,该对象封装了handler和拦截器interceptors.

// Determine handler for the current request.

mappedHandler = getHandler(processedRequest);

// 如果handler为空,则返回404

if (mappedHandler == null) {

noHandlerFound(processedRequest, response);

return;

}

//3. 获取处理request的处理器适配器HandlerAdapter

// Determine handler adapter for the current request.

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// Process last-modified header, if supported by the handler.

String method = request.getMethod();

boolean isGet = "GET".equals(method);

if (isGet || "HEAD".equals(method)) {

long lastModified = ha.getLastModified(request, mappedHandler.getHandler());

if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {

return;

}

}

//处理器适配器执行之前,检查拦截器的方法

if (!mappedHandler.applyPreHandle(processedRequest, response)) {

return;

}

//处理器适配器根据找到,执行handler,返回ModelAndView

// Actually invoke the handler.

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {

return;

}

applyDefaultViewName(processedRequest, mv);

mappedHandler.applyPostHandle(processedRequest, response, mv);

}

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);

}

catch (Exception ex) {

triggerAfterCompletion(processedRequest, response, mappedHandler, ex);

}

catch (Throwable err) {

triggerAfterCompletion(processedRequest, response, mappedHandler,

new NestedServletException("Handler processing failed", err));

}

finally {

if (asyncManager.isConcurrentHandlingStarted()) {

// Instead of postHandle and afterCompletion

if (mappedHandler != null) {

mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);

}

}

else {

// Clean up any resources used by a multipart request.

if (multipartRequestParsed) {

cleanupMultipart(processedRequest);

}

}

}

}

可以看出doDispatch()就是SpringMVC的核心代码了,分析doDispatch():

2.1、查找处理器映射器HandlerMapping

首先看下处理器映射器HandlerMapping类图:

2021022601-09-HandlerMapping类图

doDispatch()关键代码:

HandlerExecutionChain mappedHandler = null;

mappedHandler = getHandler(processedRequest);

mappedHandler是一个执行链HandlerExecutionChain 对象,这里封装了handler和拦截器interceptors,getHandler(processedRequest)方法就是从处理器映射器HandlerMapping中找到url和controller的对应关系,并返回给前端控制器DispatchServlet。

查看getHandler(processedRequest);源码:

/**

* Return the HandlerExecutionChain for this request.

* <p>Tries all handler mappings in order.

* @param request current HTTP request

* @return the HandlerExecutionChain, or {@code null} if no handler could be found

*/

@Nullable

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

if (this.handlerMappings != null) {

for (HandlerMapping mapping : this.handlerMappings) {

HandlerExecutionChain handler = mapping.getHandler(request);

if (handler != null) {

return handler;

}

}

}

return null;

}

调试代码如下:

2021022601-10-DispatchServlet-doDispatch-getHandler执行截图

从代码调试中可以看到handlerMapping中有三个对象:

this.handlerMappings = {ArrayList@4662}  size = 3

0 = {BeanNameUrlHandlerMapping@4791}

1 = {RequestMappingHandlerMapping@4792}

2 = {RouterFunctionMapping@4793}

BeanNameUrlHandlerMapping:初始化时会将urlpath做映射存储(xml);

RequestMappingHandlerMapping:初始化时会将Controller中配置@RequestMapping注解的方法做映射存储(注解);

RouterFunctionMapping:

(这个对象不是太理解)

这也就是为什么要去HandlerMapping找一个Handler了,因为处理器映射器HandlerMapping有不同的实现:

1、xml方式

2、注解方式

接着看getHandler(HttpServletRequest request)方法,先遍历HandlerMappers,查找控制器找到之后就返回执行链HandlerExecutionChain类型的Handler。

2021022601-11-DispatchServlet-doDispatch-getHandler-执行截图

可以看到返回的Handler中,拿到的就是我们自己编码的Controller类,以及拦截器(演示项目中未编写,所以调试汇总返回的Handler最后是0 interceptors)

HandlerExecutionChain with [com.bjpowernode.controller.MyController#doSome()] and 0 interceptors

2021022601-12-02-DispatchServlet-doDispatch-getHandler-mappedHandler执行截图2

将正在调试的idea打开自己编写的Controller来对照,发现一致:

2021022601-13-DispatchServlet-doDispatch-getHandler-执行返回结果截图

2.2、根据处理器映射器HandlerMapping返回结果调用处理器适配器HandlerAdapter

doDispatch()里面的关键代码:

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

源码如下:

/**

* Return the HandlerAdapter for this handler object.

* @param handler the handler object to find an adapter for

* @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.

*/

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {

if (this.handlerAdapters != null) {

for (HandlerAdapter adapter : this.handlerAdapters) {

if (adapter.supports(handler)) {

return adapter;

}

}

}

throw new ServletException("No adapter for handler [" + handler +

"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");

}

为什么还要获取处理器适配器HandlerAdapter:与获取处理器映射器HandlerMapping一样,Spring提供了不通的处理器适配器。

调试如下:

2021022601-14-01-DispatchServlet-doDispatch-getHandlerAdapter-执行截图-出方法-在用

查看DEBUG调试模式中getHandlerAdapter()方法在中的:

handler、adapter、this.handlerAdapters

2021022601-15-DispatchServlet-doDispatch-getHandlerAdapter-执行结果截图

以下是拷贝的结果:

handler

handler = {HandlerMethod@4792} "com.bjpowernode.controller.MyController#doSome()"

logger = {LogAdapter$JavaUtilLog@4858}

bean = {MyController@4859}

beanFactory = {DefaultListableBeanFactory@4847} "org.springframework.beans.factory.support.DefaultListableBeanFactory@56b5a4c3: defining beans [myController,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,org.springframework.web.servlet.view.InternalResourceViewResolver#0]; root of factory hierarchy"

beanType = {Class@3782} "class com.bjpowernode.controller.MyController"

method = {Method@4860} "public org.springframework.web.servlet.ModelAndView com.bjpowernode.controller.MyController.doSome()"

bridgedMethod = {Method@4860} "public org.springframework.web.servlet.ModelAndView com.bjpowernode.controller.MyController.doSome()"

parameters = {MethodParameter[0]@4861}

responseStatus = null

responseStatusReason = null

resolvedFromHandlerMethod = {HandlerMethod@4863} "com.bjpowernode.controller.MyController#doSome()"

interfaceParameterAnnotations = null

description = "com.bjpowernode.controller.MyController#doSome()"

adapter

adapter = {RequestMappingHandlerAdapter@4827}

customArgumentResolvers = null

argumentResolvers = {HandlerMethodArgumentResolverComposite@4833}

initBinderArgumentResolvers = {HandlerMethodArgumentResolverComposite@4834}

customReturnValueHandlers = null

returnValueHandlers = {HandlerMethodReturnValueHandlerComposite@4835}

modelAndViewResolvers = null

contentNegotiationManager = {ContentNegotiationManager@4836}

messageConverters = {ArrayList@4837}  size = 4

requestResponseBodyAdvice = {ArrayList@4838}  size = 0

webBindingInitializer = null

taskExecutor = {SimpleAsyncTaskExecutor@4839}

asyncRequestTimeout = null

callableInterceptors = {CallableProcessingInterceptor[0]@4840}

deferredResultInterceptors = {DeferredResultProcessingInterceptor[0]@4842}

reactiveAdapterRegistry = {ReactiveAdapterRegistry@4844}

ignoreDefaultModelOnRedirect = false

cacheSecondsForSessionAttributeHandlers = 0

synchronizeOnSession = false

sessionAttributeStore = {DefaultSessionAttributeStore@4845}

parameterNameDiscoverer = {DefaultParameterNameDiscoverer@4846}

beanFactory = {DefaultListableBeanFactory@4847} "org.springframework.beans.factory.support.DefaultListableBeanFactory@56b5a4c3: defining beans [myController,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,org.springframework.web.servlet.view.InternalResourceViewResolver#0]; root of factory hierarchy"

sessionAttributesHandlerCache = {ConcurrentHashMap@4848}  size = 0

initBinderCache = {ConcurrentHashMap@4849}  size = 0

initBinderAdviceCache = {LinkedHashMap@4850}  size = 0

modelAttributeCache = {ConcurrentHashMap@4851}  size = 0

modelAttributeAdviceCache = {LinkedHashMap@4852}  size = 0

order = 2147483647

supportedMethods = null

allowHeader = "GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS"

requireSession = false

cacheControl = null

cacheSeconds = -1

varyByRequestHeaders = null

useExpiresHeader = false

useCacheControlHeader = true

useCacheControlNoStore = true

alwaysMustRevalidate = false

servletContext = {ApplicationContextFacade@4754}

logger = {LogAdapter$JavaUtilLog@4854}

applicationContext = {XmlWebApplicationContext@4665} "WebApplicationContext for namespace 'myweb-servlet', started on Tue Mar 02 23:25:35 CST 2021"

messageSourceAccessor = {MessageSourceAccessor@4855}

this.handlerAdapters

this.handlerAdapters = {ArrayList@4658}  size = 4

0 = {HttpRequestHandlerAdapter@4810}

1 = {SimpleControllerHandlerAdapter@4820} //XML方式

2 = {RequestMappingHandlerAdapter@4827} //注解方式

3 = {HandlerFunctionAdapter@4832}

可以看到找到4个处理器适配器。通过DEBUG模式可以看到,此次取到的处理器适配器HandlerAdapter是:RequestMappingHandlerAdapter

ha = {RequestMappingHandlerAdapter@4827}

2.3、检查拦截器Interceptor

doDispatch()中的关键代码:

if (!mappedHandler.applyPreHandle(processedRequest, response)) {

return;

}

org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle

applyPreHandle(processedRequest, response)源码:

/**

* Apply preHandle methods of registered interceptors.

* @return {@code true} if the execution chain should proceed with the

* next interceptor or the handler itself. Else, DispatcherServlet assumes

* that this interceptor has already dealt with the response itself.

*/

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {

HandlerInterceptor[] interceptors = getInterceptors();

if (!ObjectUtils.isEmpty(interceptors)) {

for (int i = 0; i < interceptors.length; i++) {

HandlerInterceptor interceptor = interceptors[i];

if (!interceptor.preHandle(request, response, this.handler)) {

triggerAfterCompletion(request, response, null);

return false;

}

this.interceptorIndex = i;

}

}

return true;

}

2.3、处理器适配器HandlerAdapter执行Handler(Controller)返回ModelAndView

doDispatch()中的关键代码:

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

DEBUG模式调试,是跳到了:

org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle

源码如下:

/**

* This implementation expects the handler to be an {@link HandlerMethod}.

*/

@Override

@Nullable

public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {

return handleInternal(request, response, (HandlerMethod) handler);

}

再往下看handleInternal(request, response, (HandlerMethod) handler)方法,

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal

@Override

protected ModelAndView handleInternal(HttpServletRequest request,

HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

ModelAndView mav;

checkRequest(request);

// Execute invokeHandlerMethod in synchronized block if required.

if (this.synchronizeOnSession) {

HttpSession session = request.getSession(false);

if (session != null) {

Object mutex = WebUtils.getSessionMutex(session);

synchronized (mutex) {

mav = invokeHandlerMethod(request, response, handlerMethod);

}

}

else {

// No HttpSession available -> no mutex necessary

mav = invokeHandlerMethod(request, response, handlerMethod);

}

}

else {

// No synchronization on session demanded at all...

mav = invokeHandlerMethod(request, response, handlerMethod);

}

if (!response.containsHeader(HEADER_CACHE_CONTROL)) {

if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {

applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);

}

else {

prepareResponse(response);

}

}

return mav;

}

注意,handleInternal(request, response, (HandlerMethod) handler)方法的返回值是ModelAndView ,这里就完成了处理器适配器HandlerAdapter执行Handler(Controller)并将结果ModelAndView返回给前端控制器DistepchServlet

2.4、视图解析器ViewResolver

  接上2.3:前端控制器DistepchServlet接收到处理器适配器HandlerAdapter返回的ModelAndView以后,这里分2种情况:

(1)、如果ModelAndView里面是逻辑视图

前端控制器DistepchServlet调用视图解析器ViewResolver通过逻辑视图查找真正的视图对象View,并返回给前端控制器DistepchServlet。

(2)、如果ModelAndView里面是非逻辑视图:

如:MappingJackson2JsonView(把当前数据转为为JSON数据,并不需要对视图逻辑名称进行转换)

总结一下:

视图解析器ViewResolver接口主要作用是解析前端控制器DispatcherServlet传递的逻辑视图名,并将解析结果的真正的视图对象View传回给前端控制器DispatcherServlet

ViewResolverd的实现类:

2021022601-16-ViewResolver-实现类图-hierarchy

ViewResolver的UML:

2021022601-17-ViewResolver-uml图

2.5、视图View

2.5.1、视图对象的作用

(1)、将控制器返回的数据处理渲染,最终返回客户端展示给用户,主要就是完成转发或者是重定向的操作.。

(2)、为了实现视图模型和具体实现技术的解耦(指的是Spring在org.springframework.web.servlet包中定义的抽象View接口),详见2.5.2View接口图。

(3)、视图对象View由视图解析器负责实例化。由于视图是无状态(每一次请求都会创建一个新的view对象)的,所以不会有线程安全的问题.

2.5.2、View接口图

2021022601-18-View-接口方法

2.5.3、View的实现类图

2021022601-19-View-实现类图-hierarchy

2.5.4、View的UML图

![2021022601-20-01-View-uml(hierarchic group layout)](https://gitee.com/chuchq/blogs-gallery/raw/master/images / 2021/2021022601-20-01-View-uml(hierarchic group layout).png)

2.5.5、常用的View视图类

视图类型 简介

URL视图资源图 InternalResourceView 将JSP或其他资源封装成一个视图。被视图解析器InternalResourceViewResolver默认使用。

JstlView InternalResourceView的子类。如果JSP中使用了JSTL的国际化标签,就需要使用该视图类。

文档视图 AbstractExcelView Excel文档视图的抽象类。

AbstractPdfView PDF文档视图的抽象类

报表视图 ConfigurableJasperReportsView 常用的JasperReports报表视图

JasperReportsHtmlView

JasperReportsPdfView

JasperReportsXlsView

JSON视图 MappingJackson2JsonView 将数据通过Jackson框架的ObjectMapper对象,以JSON方式输出

2.6、其他重要的点

2.6.1、DispatcherServlet.properties

DispatcherServlet.properties文件是在SpringMVC架包中:

2021022601-21-jar-DispatchServlet.properties

DispatcherServlet.properties内容:

# Default implementation classes for DispatcherServlet's strategy interfaces.

# Used as fallback when no matching beans are found in the DispatcherServlet context.

# Not meant to be customized by application developers.

org.springframework.web.servlet.LocaleResolver=

org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=

org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=

org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\

org.springframework.web.servlet.function.support.RouterFunctionMapping

org.springframework.web.servlet.HandlerAdapter=

org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\

org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\

org.springframework.web.servlet.function.support.HandlerFunctionAdapter

org.springframework.web.servlet.HandlerExceptionResolver=

org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\

org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\

org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=

org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=

org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=

org.springframework.web.servlet.support.SessionFlashMapManager

深圳网站建设www.sz886.com

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容