第6章 渲染Web视图
我们所编写的控制器方法都没有直接产生浏览器中渲染所需的 HTML 。这些方法只是将一些数据填充到模型中,然后将模型传递给一个用来渲染的视图。这些方法会返回一个 String 类型的值,这个值是视图的逻辑名称,不会直接引用具体的视图实现。尽管我们也编写了几个简单的 JavaServer Page ( JSP )视图,但是控制器并不关心这些。
将控制器中请求处理的逻辑和视图中的渲染实现解耦是 Spring MVC 的一个重要特性。如果控制器中的方法直接负责产生 HTML 的话,就很难在不影响请求处理逻辑的前提下,维护和更新视图。控制器方法和视图的实现会在模型内容上达成一致,这是两者的最大关联,除此之外,两者应该保持足够的距离。
但是,如果控制器只通过逻辑视图名来了解视图的话,那 Spring 该如何确定使用哪一个视图实现来渲染模型呢?这就是 Spring 视图解析器的任务了。
6.2 解析jsp视图
//配置视图解析器
解析 JSTL 视图
如果想让 InternalResourceViewResolver 将视图解析为 JstlView ,而不是 InternalResourceView 的话,那么我们只需设置它的 viewClass 属性即可:
6.3 解析thymeleaf视图
需要导入除了spring包之外的包
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.9.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf-spring4 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>3.0.9.RELEASE</version>
</dependency>
注意:thymeleaf-spring4,如果用的spring版本不是4需要更换,请参考官网https://www.thymeleaf.org。
ThymeleafViewResolver 是 Spring MVC 中 ViewResolver 的一个实现类。像其他的视图解析器一样,它会接受一个逻辑视图名称,并将其解析为视图。不过在该场景下,视图会是一个 Thymeleaf 模板。
需要注意的是 ThymeleafViewResolver bean 中注入了一个对 SpringTemplate Engine bean 的引用。 SpringTemplateEngine 会在 Spring 中启用 Thymeleaf 引擎,用来解析模板,并基于这些模板渲染结果。可以看到,我们为其注入了一个 TemplateResolver bean 的引用。
TemplateResolver 会最终定位和查找模板。与之前配置 InternalResource-ViewResolver 类似,它使用了 prefix 和 suffix 属性。前缀和后缀将会与逻辑视图名组合使用,进而定位 Thymeleaf 引擎。它的 templateMode 属性被设置成了 HTML 5 ,这表明我们预期要解析的模板会渲染成 HTML 5 输出。
6.4 解析freemarker视图
需要导入额外包
<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
<!-- FreeMarker configuration -->
<bean id="freemarkerConfig"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/freemarker/" />
<property name="defaultEncoding" value="UTF-8" />
<!-- user-defined directives -->
<property name="freemarkerVariables">
<map>
<entry key="schoolDirective" value-ref="schoolDirectiveModel" />
<entry key="headerNavigationDirective" value-ref="headerNavigationDirectiveModel" />
<entry key="footerNavigationDirective" value-ref="footerNavigationDirectiveModel" />
<entry key="headerImageDirective" value-ref="headerImageDirectiveModel" />
<entry key="categoryDirective" value-ref="categoryDirectiveModel" />
<entry key="announcementDirective" value-ref="announcementDirectiveModel" />
<entry key="courseDirective" value-ref="courseDirectiveModel" />
<entry key="latestOrdersDirective" value-ref="latestOrdersDirectiveModel" />
<entry key="liveCourseDirective" value-ref="liveCourseDirectiveModel" />
<entry key="newsDirective" value-ref="newsDirectiveModel" />
<entry key="questionDirective" value-ref="questionDirectiveModel" />
<entry key="latestReviewDirective" value-ref="latestReviewDirectiveModel" />
<entry key="latestUserDirective" value-ref="latestUserDirectiveModel" />
<entry key="columnCourseDirective" value-ref="columnCourseDirectiveModel" />
<entry key="youLikeDirective" value-ref="youLikeDirectiveModel" />
<entry key="vipCourseDirective" value-ref="vipCourseDirectiveModel" />
<entry key="prettyTime" value-ref="prettyTimeMethodModel" />
<entry key="prettyFileSize" value-ref="prettyFileSizeMethodModel" />
<entry key="progress" value-ref="progressMethodModel" />
<entry key="cleanHtml" value-ref="cleanHtmlMethodModel" />
<entry key="completeLecturesDirective" value-ref="completeLecturesDirectiveModel" />
<entry key="userRoleDirective" value-ref="userRoleDirectiveModel" />
</map>
</property>
<!-- FreeMarker setting -->
<property name="freemarkerSettings">
<props>
<prop key=