视图解析 (View Resolution)
Spring MVC 定义了 ViewResolver 和 View 接口,允许你在浏览器中渲染模型,而无需绑定到特定的视图技术。ViewResolver 提供视图逻辑名与实际视图之间的映射。View 则负责在移交给特定视图技术之前准备数据。
ViewResolver 实现
以下是常用的 ViewResolver 实现:
| ViewResolver | 说明 |
|---|---|
InternalResourceViewResolver | 最常用。用于解析 JSP 和 Servlet 资源。建议将其放在解析器链的最后。 |
FreeMarkerViewResolver | 支持 FreeMarker 模板引擎。 |
BeanNameViewResolver | 将视图名解释为 Spring 容器中的 Bean 名称。非常灵活。 |
ContentNegotiatingViewResolver | 根据请求的文件扩展名或 Accept 头自动选择最合适的视图(内容协商)。 |
UrlBasedViewResolver | 简单的实现,将逻辑名直接映射到 URL,无需显式映射定义。 |
解析处理 (Handling)
你可以通过声明多个 ViewResolver Bean 来形成解析器链,并设置 order 属性来指定顺序。order 值越大,解析器在链中的位置越靠后。
注意
对于 JSP 和 InternalResourceViewResolver,唯一确定 JSP 是否存在的方法是通过 RequestDispatcher 进行转发。因此,你必须始终将 InternalResourceViewResolver 放在解析器链的最后。
特殊前缀:重定向与转发
在视图逻辑名中使用特殊前缀可以实现特定的跳转行为:
redirect::执行重定向。例如return "redirect:/index"。它会相对于当前的 Servlet 上下文进行重定向。forward::执行内部转发。这会创建一个InternalResourceView并调用RequestDispatcher.forward()。
内容协商 (Content Negotiation)
ContentNegotiatingViewResolver 自己并不解析视图,而是委托给其他解析器,并选择一个与客户端请求的表示形式(通过 Accept 头或查询参数如 ?format=json)最接近的视图。
补充教学
1. 为什么 RESTful 应用中很少看到 ViewResolver?
在现代的 REST 架构中,由于我们通常通过 @ResponseBody 或 @RestController 返回 JSON 数据,Spring MVC 会直接使用 HttpMessageConverter 而不是 ViewResolver。
- ViewResolver 场景:多见于传统的 SSR(服务端渲染)项目,如使用 Thymeleaf、JSP 或 FreeMarker。
2. redirect: vs 外部完整 URL
return "redirect:/home":重定向到当前站点的/home。Spring 会自动帮你处理 Context Path(上下文路径)。return "redirect:https://google.com":重定向到外部站点。Spring 发现是完整协议头,就不会拼接本地路径。
3. 如何解决 404 跳转逻辑?
如果你使用了 InternalResourceViewResolver,由于它总是认为自己能处理视图(即使 JSP 不存在),这会导致容器最后才报 404。 最佳实践:在 Spring Boot 中,推荐使用 @ControllerAdvice 结合 NoHandlerFoundException 捕获异常,或者通过容器的错误页面配置(如我们在“异常处理”章节所讲)来统一处理 404 逻辑。