Spring MVC 中ViewResolver 的职责是什么? 它是如何将 Controller 返回的视图名解析为具体的视图技术的(如Thymeleaf, JSON)?

在Spring MVC框架中,​ViewResolver(视图解析器)​的核心职责是将控制器(Controller)返回的逻辑视图名称解析为具体的视图对象(View)​。View 对象会使用特定的视图技术(如 JSP、Thymeleaf、JSON 等)来渲染最终的响应。

一、 ViewResolver 的核心职责:

  1. 接收逻辑视图名: 当 Controller 方法执行完并返回一个 String 类型的逻辑视图名(或者 ModelAndView 对象中包含了逻辑视图名)时,DispatcherServlet 会将这个逻辑视图名传递给注册的 ViewResolver
  2. 解析为 View 对象: ViewResolver 的主要任务是根据这个逻辑视图名,结合自身的配置(例如前缀、后缀、视图类等),查找或创建一个具体的 org.springframework.web.servlet.View 接口的实现类实例。这个 View 实例封装了使用特定视图技术进行渲染的逻辑。
  3. 处理无法解析的情况: 如果 ViewResolver 无法根据逻辑视图名解析出对应的 View 对象,它会通知 DispatcherServlet(通常返回 null)。DispatcherServlet 可能会尝试其他的 ViewResolver(如果配置了多个),或者最终抛出异常(例如 ServletException)。
  4. 支持视图缓存 (可选): 一些 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(或其子类,如配置了 viewClassJstlView)的实例,并将这个资源路径设置给它。
    • InternalResourceView 内部会使用 Servlet 的 RequestDispatcher 来转发 (forward) 到这个 JSP 文件进行渲染。

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。

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 头(或其他策略)来决定最终使用哪个 ViewHttpMessageConverter 来生成响应。例如,同一个 Controller 方法可以根据请求是 Accept: application/json 还是 Accept: application/xmlAccept: text/html 返回不同的结构体(JSON、XML 或 HTML 视图)。

多 ViewResolver 配置:

可以配置多个 ViewResolverDispatcherServlet 会按照它们在配置中定义的顺序 (order) 依次尝试。如果第一个能够成功解析逻辑视图名并返回 View 对象的 ViewResolver ,后续的 ViewResolver 不会被调用。ContentNegotiatingViewResolver 通常具有最高的优先级。

总结:

ViewResolver 是连接 Controller 逻辑视图名和具体视图实现技术的桥梁。它通过配置(如前缀、后缀、视图类、模板引擎引用等)将抽象的视图名称映射到具体的视图资源和渲染逻辑,使得 Controller 可以独立于具体的视图技术。不同的 ViewResolver 实现支持不同的视图技术,而对于 RESTful 服务返回的数据,则通常绕过 ViewResolver,由 HttpMessageConverter 直接处理。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰糖心书房

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值