当今的页面展示技术主要分为两种:基于JSP和EL表达式、采用模板引擎(FreeMarker、Velocity等)。 FreeMarker是一个用java语言编写的模板引擎,它基于模板生成文本输出。它强制将展示层和业务逻辑层分开,使开发人员不能像JSP页面那样在页面中添加业务逻辑。
FreeMarker采用${…}的语法形式在模块中充当占位符,运行时,由模板引擎解析模板,并用动态数据替换${…}部分的内容。FreeMarker不仅可以用作表现层的实现技术,还可以生成XML、Jsp和Java文件等。
FreeMarker模板主要由四部分组成 :
◆普通文本
◆注释 <#--注释内容-->
◆插值:${..}和#{..}。
◆FTL标签。FTL标签的名字以#开始,如:<#if user=“admin”>…</#if>;自定义标签使用@代替#。
一、使用FreeMarker作为Struts2表现层的示例
- package com.action.convention;
-
- import java.util.ArrayList;
- import java.util.List;
- import org.apache.struts2.convention.annotation.Action;
- import org.apache.struts2.convention.annotation.Result;
- import com.opensymphony.xwork2.ActionSupport;
-
- @Result(name = "success", location = "/freemarker.ftl")
- public class HelloAction extends ActionSupport {
-
- public String execute() {
- System.out.println("execute");
- return SUCCESS;
- }
-
- public List<String> getList() {
- List<String> list = new ArrayList<String>();
- list.add("aaa");
- list.add("bbb");
- list.add("ccc");
- list.add("ddd");
- return list;
- }
- }
freemarker.ftl
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <title>Insert title here</title>
- </head>
- <body>
- This is my first freemarker page!
- <br/>
- <#--循环list里的内容-->
- <#list list as item>
- ${item}
- </#list>
- </body>
- </html>
生成的页面如下:
二、使用FreeMarker模板生成Action示例
为了使用FreeMarker来将数据模型中的值合并到模板文件中,可按如下步骤进行:
1,创建Configuration实例,该实例负责管理FreeMarker的模板加载路径,负责生成模板实例
2,使用Configuration实例来生成Template实例,同进需要指定使用的模板文件
3,填充数据模型,数据模型就是一个Map对象
4,调用Template实例的process方法完成合并
- private static void createAction() throws Exception {
- // 第一步:创建freemarker.template.Configuration实例
- Configuration cfg = new Configuration();
- File directory = new File("src/resources/template");
- // 指定.ftl模板路径
- cfg.setDirectoryForTemplateLoading(directory);
-
- // 第二步:使用Configuration实例来生成Template实例,同进需要指定使用的模板文件
- String tempFile = "action.ftl";
- Template template = cfg.getTemplate(tempFile);
-
- // 第三步:填充数据模型,数据模型就是一个Map对象
- LoginUser user1 = new LoginUser();
- user1.setUsername("Cui");
- user1.setPassword("1212");
- Map<String, Object> map = new HashMap<String, Object>();
- map.put("user", user1);
-
- // 第四步:调用Template实例的process方法完成合并
- Writer writer = new FileWriter("./bin/createAction.java");
- template.process(map, writer);
- }
action.ftl模板内容如下:
- import com.opensymphony.xwork2.ActionSupport;
-
- public class ${user.username}Action extents ActionSupport{
- public String execute() {
- System.out.println("${user.password}");
- return SUCCESS;
- }
- }
运行测试方法createAction()在指定路径下生成createAction.java文件,文件内容如下:
import com.opensymphony.xwork2.ActionSupport;
public class CuiAction extents ActionSupport{
public String execute() {
System.out.println("1212");
return SUCCESS;
}
}
可见,用user对象的值填充了freemarker文件中的占位符。
PS:在上面的示例完成后又在工程下做了一些其他的示例,这两天学习FreeMarker重新运行第一个示例时FreeMarker却报错了,提示无法获取list变量,错误信息如下:
把list放入Session中可以正常显示,但是手动把变量放入Session中不仅麻烦session也会越来越大,这样肯定不能解决问题。重新创建了一个strut2工程,取消了struts-convention插件支持,测试成功,这让我怀疑是struts-convention插件对FreeMarker的支持有问题,但写这篇博客时做的示例就好好的。后来换到LoginAction下进行测试,但是又发现一个问题:登录form中的username和password无法通过属性驱动传递到LoginAction的username和password属性中,提取参数并将参数传递给Action属性的工作是由param拦截器实现的,难不成param拦截器出问题了?应该也不会,上网搜了一下发现http://topic.csdn.net/u/20110213/14/59b09329-b292-4164-a0fa-e2e6d7fa20d8.html?65640中遇到的问题和我的一样,他提到去掉AOP支持就可以正常传值,这才想到自己前几天做了一个Spring AOP的示例,把applicationContext.xml中关于AOP的配置去掉,页面到Action的传值成功,Action中的属性传值给FreeMarker模板也成功了。关于Spring AOP造成传值失败需要再查找一下。