在Spring MVC框架中,ViewResolver(视图解析器)的核心职责是将控制器(Controller)返回的逻辑视图名称解析为具体的视图对象(View)。View 对象会使用特定的视图技术(如 JSP、Thymeleaf、JSON 等)来渲染最终的响应。
一、 ViewResolver 的核心职责:
- 接收逻辑视图名: 当 Controller 方法执行完并返回一个 String 类型的逻辑视图名(或者
ModelAndView对象中包含了逻辑视图名)时,DispatcherServlet会将这个逻辑视图名传递给注册的ViewResolver。 - 解析为 View 对象:
ViewResolver的主要任务是根据这个逻辑视图名,结合自身的配置(例如前缀、后缀、视图类等),查找或创建一个具体的org.springframework.web.servlet.View接口的实现类实例。这个View实例封装了使用特定视图技术进行渲染的逻辑。 - 处理无法解析的情况: 如果
ViewResolver无法根据逻辑视图名解析出对应的View对象,它会通知DispatcherServlet(通常返回null)。DispatcherServlet可能会尝试其他的ViewResolver(如果配置了多个),或者最终抛出异常(例如ServletException)。 - 支持视图缓存 (可选): 一些
ViewResolver实现支持缓存已解析的View对象,以提高性能,避免对同一个逻辑视图名重复进行解析和创建View实例。
可以把 ViewResolver 想象成一个“视图地址翻译官”。 Controller 说:“我需要展示‘用户详情’这个页面(逻辑视图名是 userDetail)。” ViewResolver 就负责翻译:“好的,‘用户详情’对应的实际视图是 /WEB-INF/views/userDetail.jsp 这个 JSP 文件(或者是一个 Thymeleaf 模板、Freemarker 模板等),并且需要用 JstlView(或 ThymeleafView 等)来渲染它。” 然后它把这个具体的 View 对象交给 DispatcherServlet 去执行渲染。
二、 ViewResolver 如何将逻辑视图名解析为具体视图技术?
ViewResolver 解析逻辑视图名的过程取决于其具体的实现类以及相关的配置。以下是一些常见 ViewResolver 的工作方式:
1. InternalResourceViewResolver (常用于 JSP):
- 配置示例 (Java Config):
@Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { @Bean public ViewResolver internalResourceViewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); // 设置视图文件路径前缀 resolver.setSuffix(".jsp"); // 设置视图文件路径后缀 resolver.setViewClass(JstlView.class); // 指定使用 JSTL 标签库的视图类 (如果需要) return resolver; } } - 解析过程:
- 假设 Controller 返回逻辑视图名
"userDetail"。 InternalResourceViewResolver会将前缀 (prefix)、逻辑视图名 (view name) 和 后缀 (suffix) 拼接起来,形成实际的视图资源路径:/WEB-INF/views/userDetail.jsp。- 它会创建一个
InternalResourceView(或其子类,如配置了viewClass的JstlView)的实例,并将这个资源路径设置给它。 InternalResourceView内部会使用 Servlet 的RequestDispatcher来转发 (forward) 到这个 JSP 文件进行渲染。
- 假设 Controller 返回逻辑视图名
2. ThymeleafViewResolver (用于 Thymeleaf):
- 配置示例 (通常由 Spring Boot 自动配置):
@Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { // 需要配置 TemplateEngine Bean @Bean public ViewResolver thymeleafViewResolver(SpringTemplateEngine templateEngine) { ThymeleafViewResolver resolver = new ThymeleafViewResolver(); resolver.setTemplateEngine(templateEngine); // 注入 Thymeleaf 模板引擎 resolver.setCharacterEncoding("UTF-8"); // Spring Boot 会自动设置默认的前缀 (classpath:/templates/) 和后缀 (.html) // resolver.setPrefix("classpath:/templates/"); // resolver.setSuffix(".html"); return resolver; } } - 解析过程:
- 假设 Controller 返回逻辑视图名
"product/list"。 ThymeleafViewResolver通常会结合默认或配置的前缀和后缀,定位到模板文件,例如classpath:/templates/product/list.html。- 它会创建一个
ThymeleafView实例,并将逻辑视图名和配置好的TemplateEngine传递给它。 ThymeleafView在渲染时会使用TemplateEngine来处理这个模板文件,结合模型数据生成最终的 HTML。
- 假设 Controller 返回逻辑视图名
3. FreeMarkerViewResolver (用于 Freemarker):
- 配置示例 (通常由 Spring Boot 自动配置):
// 需要配置 FreeMarkerConfigurer Bean @Bean public ViewResolver freeMarkerViewResolver() { FreeMarkerViewResolver resolver = new FreeMarkerViewResolver(); resolver.setCache(true); resolver.setPrefix(""); // 通常 Spring Boot 自动设置前缀 classpath:/templates/ resolver.setSuffix(".ftl"); // 设置 Freemarker 模板文件后缀 return resolver; } - 解析过程:
- 与
ThymeleafViewResolver类似,它会根据逻辑视图名和配置的前后缀找到对应的.ftl模板文件。 - 创建一个
FreeMarkerView实例,该实例在渲染时会使用配置的 Freemarker 引擎来处理模板。
- 与
4. 处理 JSON/XML (非传统视图解析,微服务中常用的返回):
- 对于 Controller 方法使用了
@ResponseBody或属于@RestController的情况,Spring MVC 不使用ViewResolver来处理返回的对象。 DispatcherServlet(或HandlerAdapter) 会识别出这种情况,并跳过视图解析步骤。- 它会使用注册的
HttpMessageConverter(如MappingJackson2HttpMessageConverter处理 JSON,MappingJackson2XmlHttpMessageConverter处理 XML)来将 Controller 返回的对象直接序列化成相应的格式,并写入响应体。 ContentNegotiatingViewResolver: 这是一个特殊的ViewResolver,它可以根据请求的Accept头(或其他策略)来决定最终使用哪个View或HttpMessageConverter来生成响应。例如,同一个 Controller 方法可以根据请求是Accept: application/json还是Accept: application/xml或Accept: text/html返回不同的结构体(JSON、XML 或 HTML 视图)。
多 ViewResolver 配置:
可以配置多个 ViewResolver。DispatcherServlet 会按照它们在配置中定义的顺序 (order) 依次尝试。如果第一个能够成功解析逻辑视图名并返回 View 对象的 ViewResolver ,后续的 ViewResolver 不会被调用。ContentNegotiatingViewResolver 通常具有最高的优先级。
总结:
ViewResolver 是连接 Controller 逻辑视图名和具体视图实现技术的桥梁。它通过配置(如前缀、后缀、视图类、模板引擎引用等)将抽象的视图名称映射到具体的视图资源和渲染逻辑,使得 Controller 可以独立于具体的视图技术。不同的 ViewResolver 实现支持不同的视图技术,而对于 RESTful 服务返回的数据,则通常绕过 ViewResolver,由 HttpMessageConverter 直接处理。
580

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



