一、springMvc执行流程
注:请求-》DispatcherServlet(前端控制器)-》HandlerMapping(找到处理器映射器)-》返回映射器的映射地址url-》handlerAdapter(找到处理器适配器)-》Hanlder(找到处理器)-》找到Controller-》进入service层-》dao层-》返回数据结果一直到DispatcherServlet-》ViewResolver(将数据绑定在ModelAndView传给视图解析器)-》返回View(页面路径)-》DispatcherServlet(渲染视图)-》响应客户端
1、JSP
- JSP本质上是一个servlet组件
- 原生的Servlet响应网页给客户端,就需要不断地PrintWriter或println()去渲染。
- 将HTML抽离出来,定义在其他文件中,在动态的拼接渲染给客户端。
- JSP可以直接定义网页的代码结构,可以通过El表达式,JSTL标签库在实现页面的动态数据加载。
- Tomcat在编译jsp(xxx.jsp)文件的时候,会将JSP转化为Servlet组件,(xxx_jsp.java源文件)-》
(xxx_jsp.class)
2、springmvc-servlet.xml(配置文件)
默认读取路径 /WEB-INF/springmvc-servlet.xml
主要配置 处理器映射器、处理器、处理器适配器、视图解析器。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 注册处理器映射器
将一个url地址跟spring容易当中的一个bean的name属性进行匹配
说明,没有定义id的时候,spring容器会自动定义一个id的值。
命名规则:包名.类名#自增数字 例如:id=com.xx.jj.controller.xxxController#1
-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- 注册处理器(Controller类)
name属性: 对应的一个前端请求,取值必须使用/开头
class属性: DispatcherServlet发送过来的请求地址所对应的处理器(controller)
-->
<bean class="com.test.controller.DiyController" name="/diy"></bean>
<!-- 配置处理器适配器 HandlerAdapter
根据handlerMapping返回的controller,执行一个匹配规则,找到对应的handler去处理controller
-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- 配置视图解析器 ViewResolver
根据前缀后缀找到对应的视图文件进行渲染
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 资源文件的前缀 -->
<property name="prefix" value="/WEB-INF/"></property> <!-- 给bean对象的属性配置一个初始化值 -->
<!-- 资源文件的后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
二、DispatcherServlet(前端控制器)源码解析
- 继承关系:DispatcherServlet继承-》FramworkServlet继承-》HttpServletBean继承-》HttpServlet继承-》GenericServlet-》Servlet接口
- 主要处理流程 doservice-》doDispatch-》获取处理器执行链-》处理器适配器匹配-》前置过滤器-》执行handler(controller方法)->中置过滤器->渲染视图-》后置过滤器

- 两种加载方式
- 启动即加载
- 懒加载
- 配置方式 (LoadOnStartup 0:懒加载 1:启动即加载)
<!-- 基于xml设置 -->
<load-on-startup>1</load-on-startup>
<!-- 基于类的设置 -->
DispatcherServlet dispatcherServlet = new DispatcherServlet(context);
registration.setLoadOnStartup(1);
- 基于xml配置
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring.xml</param-value>
</init-param>
<!-- load-on-startup 设置成1 启动即加载 ,不设置则 用到时在加载(懒加载) -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- url映射 -->
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
- 基于注解(实现WebApplicationInitializer)
注:【tomcat在启动时候遵守Servlet规范,根据SPI机制去找到ServletContainerInitializer下的SpringServletContainerInitializer,在找到头上注释@HandlesTypes({WebApplicationInitializer.class}) 所有实现类,遍历循环onStartup()方法,则会执行下方的DispatcherServlet的装配流程】

- 查看源码
// 部分代码
@HandlesTypes({WebApplicationInitializer.class})
public class SpringServletContainerInitializer implements ServletContainerInitializer {
public SpringServletContainerInitializer() {
}
// webAppInitializerClasses 入参,则是所有WebApplicationInitializer的实现类数组
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList();
Iterator var4;
// 中间省略.....
//执行遍历的实现类的onStartup
while(var4.hasNext()) {
WebApplicationInitializer initializer = (WebApplicationInitializer)var4.next();
initializer.onStartup(servletContext);
}
- 对应的实现类
//实现webApplicationInitializer将dispatcherServlet进行装配
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(javax.servlet.ServletContext servletContext) throws ServletException {
// 创建容器
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(WebConfig.class);
// 前端控制器管理spring容器
DispatcherServlet dispatcherServlet = new DispatcherServlet(context);
// 添加url映射
ServletRegistration.Dynamic registration = servletContext.addServlet("app",dispatcherServlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
- 核心方法 doDispatch()
// servlet提供的一个方法,对不同请求方式进行处理
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
// ..上方代码省略
try {
//调用了doDispatch()方法,传递了请求和响应对象
this.doDispatch(request, response);
} finally {}
// 代码省略
}
- doDispatch() 方法定义
// doDispatch 方法定义
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
// 创建一个处理器执行链(将来执行的请求流程)
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// 通过 getHandler(request)方法,返回一个处理器执行链对象。
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
// 处理器是适配器,这里主要找到对应handler的适配器。如:HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter等。
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
//处理GET请求
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(执行controller里面的方法)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//获取视图名
this.applyDefaultViewName(processedRequest, mv);
//执行中置过滤器
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
//渲染视图
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
- this.getHandler()源码
// handlerMapptings 作用维护url和controller的映射
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
// HandlerMapping是 servlet所支持的处理器映射集合。
while(var2.hasNext()) {
//拿到 url映射的Controller 例:/test - testController 的映射关系
HandlerMapping mapping = (HandlerMapping)var2.next();
//返回一个处理器执行链
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
- mapping.getHandler()的源码
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 获取handler对象,由于类型不统一所以转成 Object
Object handler = this.getHandlerInternal(request);
if (handler == null) {
handler = this.getDefaultHandler();
}
if (handler == null) {
return null;
} else {
if (handler instanceof String) {
String handlerName = (String)handler;
handler = this.obtainApplicationContext().getBean(handlerName);
}
//获取处理器执行链,要根据request和handler对象来获取处理器执行链
HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Mapped to " + handler);
} else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
this.logger.debug("Mapped to " + executionChain.getHandler());
}
//跨域的配置封装到处理器执行链中
if (this.hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null;
CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
config = config != null ? config.combine(handlerConfig) : handlerConfig;
executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
}
- 查看 this.getHandlerInternal(request)
// 获取一个controller
@Nullable
protected abstract Object getHandlerInternal(HttpServletRequest var1) throws Exception;
- 查看this.getHandlerExecutionChain(handler, request)
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 获取处理器执行链的对象
HandlerExecutionChain chain = handler instanceof HandlerExecutionChain ? (HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
//获取过滤器
Iterator var5 = this.adaptedInterceptors.iterator();
while(var5.hasNext()) {
HandlerInterceptor interceptor = (HandlerInterceptor)var5.next();
// 判断过滤器器是否是这个类型
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
//匹配路径
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
//过滤器根据请求做匹配加入到过滤器中
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else {
chain.addInterceptor(interceptor);
}
}
//处理器执行链包含:Interceptor和handler
return chain;
}
- DispatcherServlet前端控制器,经过一系列处理返回一个处理器执行链对象 (HandlerExecutionChain)。在该对象中封装了两部分信息(Interceptor和handler)。之后就都是对请求的处理了。
**
三、XmlWebApplicationContext源码解析
XmlWebApplicationContext维护了springmvc的核心配置
- 基于xml文件
<servlet>
<!-- 不设置contextConfigLocation 默认会去找 app-servlet.xml 的文件 -->
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springmvc-servlet.xml</param-value>
</init-param>
<!-- load-on-startup 设置成1 启动即加载 ,不设置则 用到时在加载 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
- 源码
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {
//默认配置信息,读取路径
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";
public XmlWebApplicationContext() {
}
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
this.initBeanDefinitionReader(beanDefinitionReader);
this.loadBeanDefinitions(beanDefinitionReader);
}
protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
String[] configLocations = this.getConfigLocations();
if (configLocations != null) {
String[] var3 = configLocations;
int var4 = configLocations.length;
for(int var5 = 0; var5 < var4; ++var5) {
String configLocation = var3[var5];
reader.loadBeanDefinitions(configLocation);
}
}
}
protected String[] getDefaultConfigLocations() {
return this.getNamespace() != null ? new String[]{"/WEB-INF/" + this.getNamespace() + ".xml"} : new String[]{"/WEB-INF/applicationContext.xml"};
}
}
- XmlWebApplicationContext 读取机制
优先找/WEB-INF/applicationContext.xml 文件,找不到再去找 如果<servlet-name>app</servlet-name>,则会去找 app-servlet.xml的文件。还找不到,就需要指定配置文件路径,如 contextConfigLocation去指定读取路径。
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springmvc-servlet.xml</param-value>
</init-param>
四、HandleMapping(处理器映射器)源码解析
注:HandleMapping接口,负责将request请求找到handler对象及interceptor对象,封装到处理器执行链中(HandlerExecutionChain)中,返回给前端控制器。
- 提供了两个实现类
- BeanNameUrlHandlerMapping
- 作用:根据请求的url和spring容器中定义的bean(如:controller)对象的name属性进行匹配,匹配成功则返回一个handler(处理器对象Controller)。
- 缺点:多个url映射同个controller,会造成代码冗余,Controller的name不能重复,但bean标签的name值可以重复。
- xml注册处理器映射器
- BeanNameUrlHandlerMapping
<!-- 注册处理器映射器
将一个url地址跟spring容易当中的一个bean的name属性进行匹配
说明,没有定义id的时候,spring容器会自动定义一个id的值。
命名规则:包名.类名#自增数字 例如:id=com.xx.jj.controller.xxxController#1
-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- 注册处理器(Controller类)
name属性: 对应的一个前端请求,取值必须使用/开头
class属性: DispatcherServlet发送过来的请求地址所对应的处理器(controller)
-->
<bean class="com.test.controller.DiyController" name="/diy"></bean>
- 源码
public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {
public BeanNameUrlHandlerMapping() {
}
//根据beanName找到
protected String[] determineUrlsForHandler(String beanName) {
//存储name属性值的集合
List<String> urls = new ArrayList();
// 判断Name取值是否以/开头。
if (beanName.startsWith("/")) {
// 将beaanName添加到集合中
urls.add(beanName);
}
//bean的别名也符合条件也加入到集合当中
String[] aliases = this.obtainApplicationContext().getAliases(beanName);
String[] var4 = aliases;
int var5 = aliases.length;
for(int var6 = 0; var6 < var5; ++var6) {
String alias = var4[var6];
if (alias.startsWith("/")) {
urls.add(alias);
}
}
return StringUtils.toStringArray(urls);
}
}
-
SimpleUrlHandlerMapping
- 配置方式一
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<!-- 通过mappings的属性来配置多个url的请求映射 -->
<property name="mappings">
<!-- 是map集合 -->
<props>
<!-- 声明一组url的映射,prop标签的内容是bean对象的id取值 -->
<prop key="/hello">diyController</prop>
<prop key="/word">diyController</prop>
</props>
</property>
</bean>
<bean class="com.test.controller.DiyController" name="/diy" id="diyController"></bean>
- 配置方式二
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<!-- 方式二:通过urlMap属性来实现映射 -->
<property name="urlMap">
<map>
<!-- entry 表示一组url的 映射 key表示请求的url value表示bean的id值 -->
<entry key="/hello" value="diyController" ></entry>
</map>
</property>
</bean>
<bean class="com.test.controller.DiyController" name="/diy" id="diyController"></bean>
- 源码解析
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
// 遍历handlerMapping对象
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
//获取一个handlerMapping对象
HandlerMapping mapping = (HandlerMapping)var2.next();
// 通过request获取handlerMapping的处理器执行链
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
getHandler在AbstractHandlerMapping实现了该方法
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//根据请求对象获取到handler处理器
Object handler = this.getHandlerInternal(request);
if (handler == null) {
handler = this.getDefaultHandler();
}
if (handler == null) {
return null;
} else {
if (handler instanceof String) {
String handlerName = (String)handler;
handler = this.obtainApplicationContext().getBean(handlerName);
}
//通过Handler和request获取到处理器执行链(包含过滤器和handler)
HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Mapped to " + handler);
} else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
this.logger.debug("Mapped to " + executionChain.getHandler());
}
if (this.hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null;
CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
config = config != null ? config.combine(handlerConfig) : handlerConfig;
executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
}
五、HandlerAdapter(处理器适配器)源码解析
-
HandlerAdapter执行过程
DispatcherServlet会根据HandlerMapping返回的handler(Controller)注册到已配置的HandlerAdapter上,HandlerAdapter会根据handler类型来判断是否满足要求,满足要求就返回一个handlerAdapter给DispatcherServlet去执行handler里面的请求体(如SimpleControlerAdapter,则执行的是 handleRequest方法)。 -
查看doDispatch()中的this.getHandlerAdapter()方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//...省略
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
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;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
//...省略
}
}
- getHandlerAdapter()方法
//通过Handler对象,返回一个handlerAdapter对象
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
//handlerAdapters 适配器集合
if (this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
while(var2.hasNext()) {
//获取集合中的handlerAdapter对象
HandlerAdapter adapter = (HandlerAdapter)var2.next();
//调用handlerAdapter的supports方法
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");
}
- 查看 supports()方法拥有5个实现类

- 查看SimpleControllerHandlerAdapter的实现
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
public SimpleControllerHandlerAdapter() {
}
//判断Handler是否是Controller类
public boolean supports(Object handler) {
return handler instanceof Controller;
}
// 执行handler里的请求体即 Controller里面的方法
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return ((Controller)handler).handleRequest(request, response);
}
//与 HttpServlet的getLastModified()方法的约定时间
public long getLastModified(HttpServletRequest request, Object handler) {
return handler instanceof LastModified ? ((LastModified)handler).getLastModified(request) : -1L;
}
}
- handleRequest()执行的方法
//@Component("/test")
public class BeanNameController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("123",1);
System.out.println("你好");
return null;
}
}
六、ViewResolver(视图解析器)源码解析
- 执行流程
1.将SpringMvc的前端控制返回的结果封装成ModelAndView对象。
2.在通过视图解析器对ModelAndView对象进行解析,解析成一个物理地址映射的视图。
3.将这个物理地址的视图通过view接口来进行渲染。 - xml配置
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 资源文件的前缀 -->
<property name="prefix" value="/WEB-INF/"></property> <!-- 给bean对象的属性配置一个初始化值 -->
<!-- 资源文件的后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
- 源码
public class InternalResourceViewResolver extends UrlBasedViewResolver {
//加载JSTL的标签库来解析目标JSP文件
private static final boolean jstlPresent = ClassUtils.isPresent("javax.servlet.jsp.jstl.core.Config",
// 获取当前类的类加载器
InternalResourceViewResolver.class.getClassLoader());
@Nullable
private Boolean alwaysInclude;
public InternalResourceViewResolver() {
Class<?> viewClass = this.requiredViewClass();
if (InternalResourceView.class == viewClass && jstlPresent) {
viewClass = JstlView.class;
}
this.setViewClass(viewClass);
}
public InternalResourceViewResolver(String prefix, String suffix) {
this();
this.setPrefix(prefix);
this.setSuffix(suffix);
}
protected Class<?> requiredViewClass() {
return InternalResourceView.class;
}
public void setAlwaysInclude(boolean alwaysInclude) {
this.alwaysInclude = alwaysInclude;
}
//构建页面视图
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
InternalResourceView view = (InternalResourceView)super.buildView(viewName);
if (this.alwaysInclude != null) {
view.setAlwaysInclude(this.alwaysInclude);
}
view.setPreventDispatchLoop(true);
return view;
}
}
- UrlBasedViewResolver 类
public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered {
//重定向的标识
public static final String REDIRECT_URL_PREFIX = "redirect:";
//请求转发表示
public static final String FORWARD_URL_PREFIX = "forward:";
@Nullable
private Class<?> viewClass;
private String prefix = ""; //目标视图的前缀
private String suffix = ""; //目标视图的后缀
/...
}
&spm=1001.2101.3001.5002&articleId=148242627&d=1&t=3&u=5eceb7b8205a4bbab997a8babb6ca023)
3610

被折叠的 条评论
为什么被折叠?



