Apache FreeMarker 是一个模板引擎,用于生成从 HTML 到电子邮件和其他任何类型的文本输出。Spring 框架有内置的集成,可以使用 Spring MVC 和 FreeMarker 模板。
视图配置
首先需要先添加依赖
// org.springframework.ui.freemarker.FreeMarkerConfigurationFactory 在 spring-context-support 中被支持
implementation group: 'org.springframework', name: 'spring-context-support', version: '5.3.15'
implementation group: 'org.freemarker', name: 'freemarker', version: '2.3.31'
下面的例子显示了如何将 FreeMarker 配置为一种视图技术:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
// 使用空的默认视图名称前缀和默认后缀 .ftl 注册 FreeMarker 视图解析器。
// 请注意,您还必须通过添加 FreeMarkerConfigurer bean 来配置 FreeMarker
registry.freeMarker();
}
// 配置 FreeMarker...
@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath("/WEB-INF/freemarker");
return configurer;
}
}
下面的例子显示了如何在 XML 中进行同样的配置:
<mvc:annotation-driven/>
<mvc:view-resolvers>
<mvc:freemarker/>
</mvc:view-resolvers>
<!-- Configure FreeMarker... -->
<mvc:freemarker-configurer>
<mvc:template-loader-path location="/WEB-INF/freemarker"/>
</mvc:freemarker-configurer>
另外,你也可以声明 FreeMarkerConfigurer bean 来完全控制所有的属性,如下例所示:
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/freemarker/"/>
</bean>
你的模板需要存储在前面的例子中所示的 FreeMarkerConfigurer 指定的目录中。鉴于前面的配置,如果你的控制器返回的视图名称是 welcome,解析器会寻找 /WEB-INF/freemarker/welcome.ftl
模板。
FreeMarker 配置
你可以通过在 FreeMarkerConfigurer Bean 上设置适当的 bean 属性,将 FreeMarker 「Settings」和 「SharedVariables」直接传递给 FreeMarker 配置对象(它由 Spring 管理)。freemarkerSettings 属性需要一个 java.util.Properties
对象,而 freemarkerVariables 属性需要一个java.util.Map
。下面的例子显示了如何使用 FreeMarkerConfigurer:
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/freemarker/"/>
<property name="freemarkerVariables">
<map>
<entry key="xml_escape" value-ref="fmXmlEscape"/>
</map>
</property>
</bean>
<bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape"/>
关于适用于 Configuration 对象的设置和变量的细节,请参见 FreeMarker 文档。
表单处理
Spring 提供了一个标签库供 JSP 使用,其中包含 <spring:bind/>
元素。这个元素主要让表单显示来自表单支持对象的值,并显示来自 Web 或业务层中验证器的失败验证结果。Spring 在 FreeMarker 中也支持同样的功能,还有额外的方便宏用于生成表单输入元素本身。
绑定宏(Macros)
在 FreeMarker 的 spring-webmvc.jar 文件中维护了一套标准的宏,所以它们总是可以被适当配置的应用程序使用。
在 Spring 模板库中定义的一些宏被认为是内部的(私有的),但在宏定义中不存在这样的范围,使所有的宏对调用代码和用户模板是可见的。下面的章节只集中讨论你需要从模板中直接调用的宏。如果你想直接查看宏代码,文件名为 spring.ftl,位于org.springframework.web.servlet.view.freemarker 包中。
简单的绑定
在你基于 FreeMarker 模板的 HTML 表单中,作为 Spring MVC 控制器的表单视图,你可以使用类似于下一个例子的代码来绑定字段的值,并以类似于 JSP 的方式为每个输入字段显示错误信息。下面的例子显示了一个 personForm 视图:
<!-- FreeMarker 宏必须被导入到一个命名空间。
我们强烈建议坚持使用 "spring"。 -->
<#import "/spring.ftl" as spring/>
<html>
...
<form action="" method="POST">
Name:
<@spring.bind "personForm.name"/>
<input type="text"
name="${spring.status.expression}"
value="${spring.status.value?html}"/><br />
<#list spring.status.errorMessages as error> <b>${error}</b> <br /> </#list>
<br />
...
<input type="submit" value="submit"/>
</form>
...
</html>
<@spring.bind>
需要一个 ‘path’ 参数,它由你的命令对象的名字组成(它是 ‘command’,除非你在控制器配置中改变了它),后面是一个 .
和你想绑定的命令对象上的字段名。你也可以使用嵌套字段,如 command.address.street
。绑定宏假定默认的 HTML 转义行为由 web.xml 中的 ServletContext 参数 defaultHtmlEscape 指定。
该宏的另一种形式叫做 <@spring.bindEscaped>
,它需要第二个参数,明确指定是否应该在状态错误信息或值中使用 HTML 转义。你可以根据需要将其设置为真或假。附加的表单处理宏简化了 HTML 转义的使用,你应该尽可能地使用这些宏。它们将在下一节中解释。
输入宏
FreeMarker 的附加便利宏简化了绑定和表单生成(包括验证错误显示)。从来没有必要使用这些宏来生成表单输入字段,你可以将它们与简单的HTML 或直接调用我们之前强调的 Spring 绑定宏进行混合和匹配。
下面的可用宏表显示了 FreeMarker 模板(FTL)的定义和每个宏的参数列表。
:::tips 后面的内容还挺多的,就不记录了,暂时没有打算使用这个视图,请参考 官方文档 :::
一个 Hello Word 例子
这个例子架子在 Spring Web MVC 中 内嵌 Tomcat 笔记中有说明,这里针对配置和写法进行搭建。
package cn.mrcode.study;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
/**
* @author mrcode
*/
@EnableWebMvc
@ComponentScan("cn.mrcode.study.springdocsread")
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.freeMarker();
}
// 配置 FreeMarker...
@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
// 对应的是模板存放地址
configurer.setTemplateLoaderPath("/WEB-INF/freemarker");
return configurer;
}
}
hello-word.ftl
您好:${username}
controller
package cn.mrcode.study.springdocsread.web;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author mrcode
*/
@Controller
@RequestMapping("/demo2")
public class Demo2Controller {
@GetMapping("/freemarker")
public String freemarker(Model model) {
// 添加一个响应参数
model.addAttribute("username", "Hello Word");
return "hello-word";
}
}
然后访问 http://localhost:8080/demo2/freemarker 就能看到渲染的 html 页面了