SpringBoot整合模板引擎
整合Freemarker
Freemarker简介
这是一个相当老牌的开源的免费的模版引擎。通过 Freemarker 模版,我们可以将数据渲染成 HTML 网页、电子邮件、配置文件以及源代码等。Freemarker 不是面向最终用户的,而是一个 Java 类库,我们可以将之作为一个普通的组件嵌入到我们的产品中。
来看一张来自 Freemarker 官网的图片:
可以看到,Freemarker 可以将模版和数据渲染成 HTML 。
Freemarker 模版后缀为 .ftl
(FreeMarker Template Language)。FTL 是一种简单的、专用的语言,它不是像 Java 那样成熟的编程语言。在模板中,你可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据。
POM文件增加依赖
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency>
|
创建类
创建实体类
1 2 3 4 5 6
| public class User { private Long id; private String username; private String address; }
|
创建Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Controller public class IndexController { @RequestMapping("/index") public String index(Model model) { List<User> users = new ArrayList<>(); for (int i = 0; i < 10; i++) { User user = new User(); user.setId((long) i); user.setUsername("baiyp>>>>" + i); user.setAddress("www.baiyp.ren>>>>" + i); users.add(user); } model.addAttribute("users", users); return "index"; } }
|
创建ftlh文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table border="1"> <tr> <td>用户编号</td> <td>用户名称</td> <td>用户地址</td> </tr> <#list users as user> <tr> <td>${user.id}</td> <td>${user.username}</td> <td>${user.address}</td> </tr> </#list> </table> </body> </html>
|
目录结构
运行效果
显示配置freemarker
在springboot2.0+ 之后版本freemarker的默认后缀改成了ftlh,用原来的ftl直接访问会报错
可以显示配置为
配置application.properties
1 2 3 4 5
| spring.freemarker.charset=UTF-8 spring.freemarker.suffix=.ftl spring.freemarker.content-type=text/html; charset=utf-8 spring.freemarker.template-loader-path=classpath:/templates spring.mvc.static-path-pattern=/static/**
|
其他配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| spring.freemarker.allow-request-override=false
spring.freemarker.allow-session-override=false
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.check-template-location=true
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes=false
spring.freemarker.suffix=.ftl
spring.freemarker.template-loader-path=classpath:/templates/
|
原理分析
FreeMarkerAutoConfiguration
工程创建完成后,在 org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration
类中,可以看到关于 Freemarker 的自动化配置:
1 2 3 4 5 6 7 8
| @Configuration( proxyBeanMethods = false ) @ConditionalOnClass({freemarker.template.Configuration.class, FreeMarkerConfigurationFactory.class}) @EnableConfigurationProperties({FreeMarkerProperties.class}) @Import({FreeMarkerServletWebConfiguration.class, FreeMarkerReactiveWebConfiguration.class, FreeMarkerNonWebConfiguration.class}) public class FreeMarkerAutoConfiguration { }
|
从这里可以看出,当 classpath 下存在 freemarker.template.Configuration 以及 FreeMarkerConfigurationFactory 时,配置才会生效,也就是说当我们引入了 Freemarker 之后,配置就会生效。但是这里的自动化配置只做了模板位置检查,其他配置则是在导入的 FreeMarkerServletWebConfiguration 配置中完成的。
FreeMarkerServletWebConfiguration
那么我们再来看看 FreeMarkerServletWebConfiguration 类,部分源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| @Configuration( proxyBeanMethods = false ) @ConditionalOnWebApplication( type = Type.SERVLET ) @ConditionalOnClass({Servlet.class, FreeMarkerConfigurer.class}) @AutoConfigureAfter({WebMvcAutoConfiguration.class}) class FreeMarkerServletWebConfiguration extends AbstractFreeMarkerConfiguration { protected FreeMarkerServletWebConfiguration(FreeMarkerProperties properties) { super(properties); }
@Bean @ConditionalOnMissingBean({FreeMarkerConfig.class}) FreeMarkerConfigurer freeMarkerConfigurer() { FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); this.applyProperties(configurer); return configurer; }
@Bean @ConditionalOnMissingBean( name = {"freeMarkerViewResolver"} ) @ConditionalOnProperty( name = {"spring.freemarker.enabled"}, matchIfMissing = true ) FreeMarkerViewResolver freeMarkerViewResolver() { FreeMarkerViewResolver resolver = new FreeMarkerViewResolver(); this.getProperties().applyToMvcViewResolver(resolver); return resolver; }
@Bean @ConditionalOnEnabledResourceChain @ConditionalOnMissingFilterBean({ResourceUrlEncodingFilter.class}) FilterRegistrationBean<ResourceUrlEncodingFilter> resourceUrlEncodingFilter() { FilterRegistrationBean<ResourceUrlEncodingFilter> registration = new FilterRegistrationBean(new ResourceUrlEncodingFilter(), new ServletRegistrationBean[0]); registration.setDispatcherTypes(DispatcherType.REQUEST, new DispatcherType[]{DispatcherType.ERROR}); return registration; } }
|
我们来简单看下这段源码:
- @ConditionalOnWebApplication 表示当前配置在 web 环境下才会生效。
- ConditionalOnClass 表示当前配置在存在 Servlet 和 FreeMarkerConfigurer 时才会生效。
- @AutoConfigureAfter 表示当前自动化配置在 WebMvcAutoConfiguration 之后完成。
- 代码中,主要提供了 FreeMarkerConfigurer 和 FreeMarkerViewResolver
- FreeMarkerConfigurer 是 Freemarker 的一些基本配置,例如 templateLoaderPath、defaultEncoding 等
- FreeMarkerViewResolver 则是视图解析器的基本配置,包含了viewClass、suffix、allowRequestOverride、allowSessionOverride 等属性。
FreeMarkerProperties
另外还有一点,在这个类的构造方法中,注入了 FreeMarkerProperties:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| @ConfigurationProperties( prefix = "spring.freemarker" ) public class FreeMarkerProperties extends AbstractTemplateViewResolverProperties { public static final String DEFAULT_TEMPLATE_LOADER_PATH = "classpath:/templates/"; public static final String DEFAULT_PREFIX = ""; public static final String DEFAULT_SUFFIX = ".ftlh"; private Map<String, String> settings = new HashMap(); private String[] templateLoaderPath = new String[]{"classpath:/templates/"}; private boolean preferFileSystemAccess = true;
public FreeMarkerProperties() { super("", ".ftlh"); }
public Map<String, String> getSettings() { return this.settings; }
public void setSettings(Map<String, String> settings) { this.settings = settings; }
public String[] getTemplateLoaderPath() { return this.templateLoaderPath; }
public boolean isPreferFileSystemAccess() { return this.preferFileSystemAccess; }
public void setPreferFileSystemAccess(boolean preferFileSystemAccess) { this.preferFileSystemAccess = preferFileSystemAccess; }
public void setTemplateLoaderPath(String... templateLoaderPaths) { this.templateLoaderPath = templateLoaderPaths; } }
|
FreeMarkerProperties 中则配置了 Freemarker 的基本信息,例如模板位置在 classpath:/templates/
,再例如模板后缀为 .ftlh
,那么这些配置我们以后都可以在 application.properties 中进行修改。
主要:在springboot 2.0+之后Freemarker 后缀改成了ftlh,如果还是使用的ftl后缀需要显示配置。
如果我们在 SSM 的 XML 文件中自己配置 Freemarker ,也不过就是配置这些东西。现在,这些配置由 FreeMarkerServletWebConfiguration 帮我们完成了。
整合 Thymeleaf
Thymeleaf 简介
Thymeleaf 是新一代 Java 模板引擎,它类似于 Velocity、FreeMarker 等传统 Java 模板引擎,但是与传统 Java 模板引擎不同的是,Thymeleaf 支持 HTML 原型。
它既可以让前端工程师在浏览器中直接打开查看样式,也可以让后端工程师结合真实数据查看显示效果,同时,SpringBoot 提供了 Thymeleaf 自动化配置解决方案,因此在 SpringBoot 中使用 Thymeleaf 非常方便。
事实上, Thymeleaf 除了展示基本的 HTML ,进行页面渲染之外,也可以作为一个 HTML 片段进行渲染,例如我们在做邮件发送时,可以使用 Thymeleaf 作为邮件发送模板。
另外,由于 Thymeleaf 模板后缀为 .html
,可以直接被浏览器打开,因此,预览时非常方便。
POM文件增加依赖
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
|
创建类
实体类
参考下Freemarker 里面的User对象
创建Controller
参考下Freemarker 的controller
在 IndexController
中返回逻辑视图名+数据,逻辑视图名为 index
,意思我们需要在 resources/templates
目录下提供一个名为 index.html
的 Thymeleaf
模板文件。
创建 Thymeleaf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table border="1"> <tr> <td>编号</td> <td>用户名</td> <td>地址</td> </tr> <tr th:each="user : ${users}"> <td th:text="${user.id}"></td> <td th:text="${user.username}"></td> <td th:text="${user.address}"></td> </tr> </table> </body> </html>
|
在 Thymeleaf
中,通过 th:each
指令来遍历一个集合,数据的展示通过 th:text
指令来实现,
注意 index.html
最上面要引入 thymeleaf
名称空间。
目录结构
运行效果
配置完成后,就可以启动项目了,访问 /index 接口,就能看到集合中的数据了:
原理分析
ConfigurationProperties
Thymeleaf 不仅仅能在 Spring Boot 中使用,也可以使用在其他地方,只不过 Spring Boot 针对 Thymeleaf 提供了一整套的自动化配置方案,这一套配置类的属性在 org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties 中,部分源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| @ConfigurationProperties( prefix = "spring.thymeleaf" ) public class ThymeleafProperties { private static final Charset DEFAULT_ENCODING; public static final String DEFAULT_PREFIX = "classpath:/templates/"; public static final String DEFAULT_SUFFIX = ".html"; private boolean checkTemplate = true; private boolean checkTemplateLocation = true; private String prefix = "classpath:/templates/"; private String suffix = ".html"; private String mode = "HTML"; private Charset encoding; private boolean cache; private Integer templateResolverOrder; private String[] viewNames; private String[] excludedViewNames; private boolean enableSpringElCompiler; private boolean renderHiddenMarkersBeforeCheckboxes; private boolean enabled; private final ThymeleafProperties.Servlet servlet; private final ThymeleafProperties.Reactive reactive;
public ThymeleafProperties() { this.encoding = DEFAULT_ENCODING; this.cache = true; this.renderHiddenMarkersBeforeCheckboxes = false; this.enabled = true; this.servlet = new ThymeleafProperties.Servlet(); this.reactive = new ThymeleafProperties.Reactive(); } ... }
|
- 首先通过 @ConfigurationProperties 注解,将 application.properties 前缀为 spring.thymeleaf 的配置和这个类中的属性绑定。
- 前三个 static 变量定义了默认的编码格式、视图解析器的前缀、后缀等。
- 从前三行配置中,可以看出来,Thymeleaf 模板的默认位置在 resources/templates 目录下,默认的后缀是 html 。
- 这些配置,如果开发者不自己提供,则使用 默认的,如果自己提供,则在 application.properties 中以 spring.thymeleaf 开始相关的配置。
ThymeleafAutoConfiguration
而我们刚刚提到的,Spring Boot 为 Thymeleaf 提供的自动化配置类,则是 org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration
,部分源码如下:
1 2 3 4 5 6 7 8 9
| @Configuration( proxyBeanMethods = false ) @EnableConfigurationProperties({ThymeleafProperties.class}) @ConditionalOnClass({TemplateMode.class, SpringTemplateEngine.class}) @AutoConfigureAfter({WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class}) public class ThymeleafAutoConfiguration { ... }
|
可以看到,在这个自动化配置类中,首先导入 ThymeleafProperties ,然后 @ConditionalOnClass 注解表示当当前系统中存在 TemplateMode 和 SpringTemplateEngine 类时,当前的自动化配置类才会生效,即只要项目中引入了 Thymeleaf 相关的依赖,这个配置就会生效。
这些默认的配置我们几乎不需要做任何更改就可以直接使用了。如果开发者有特殊需求,则可以在 application.properties 中配置以 spring.thymeleaf 开头的属性即可。