freemarker作为SpringMVC一种视图格式,用于将数据模型在文本模板中显示并输出文件(html,也可其它格式)。其中,文本模板可以包括如下四部分内容:
1、注释,即<#--...-->,其中的内容会被freemarker忽略;
2、插值,即${...}部分,freemarker会用真实的值代替${...};
3、FTL指令,和HTML标记类似,名字前加#予以区分,Freemarker会解析标签中的表达式或逻辑;
4、文本,即文本信息,直接原样输出的内容;
数据模型在java中可以是基本类型、Map、List、Pojo等复杂类型。在java代码中,可利用freemarker将文本模型解析(形参替换为实参)为最终文本,代码如下:
1、依赖项
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
2、工具类
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.TemplateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
public class FreeMarkerUtil {
static final Logger logger = LoggerFactory.getLogger(FreeMarkerUtil.class);
/**
* 通过Freemarker解析/编译文本
* @param strTemp
* @param paraMap
* @return
* @throws TemplateException
* @throws IOException
*/
public static String parseTemplate(String strTemp, Map paraMap) throws Exception{
if(Objects.isNull(paraMap) || paraMap.isEmpty()){
return strTemp;
}
try{
StringTemplateLoader strTempLoader = new StringTemplateLoader();
strTempLoader.putTemplate("template", strTemp);
Configuration conf = new Configuration();
conf.setTemplateLoader(strTempLoader);
Map<String,Object> rootMap = new HashMap<>();
/// 思考:去掉影响什么 ?
rootMap.put("p", paraMap);
Iterator iterator = paraMap.keySet().iterator();
while(iterator.hasNext()){
String key = (String)iterator.next();
rootMap.put(key, paraMap.get(key));
}
StringWriter writer = new StringWriter();
conf.getTemplate("template").process(rootMap, writer);
return writer.toString();
}catch(Exception e){
logger.error(e.getMessage(), e);
throw e;
}
}
}
3、模型解析
import com.smy.freemarker.entity.Student;
import com.smy.freemarker.util.FreeMarkerUtil;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;
@RestController
public class FreeMarkerController {
@RequestMapping("/getDataModel")
public static Map getDataModel(Map<String, Object> dataMap) {
Student stu1 = new Student();
stu1.setName("任飘渺");
stu1.setAge(48);
stu1.setBirthday(new Date());
Student stu2 = new Student();
stu2.setName("藏镜人");
stu2.setAge(49);
stu2.setBirthday(new Date());
List<Student> friends = new ArrayList<>();
friends.add(stu1);
stu2.setFriends(friends);
stu2.setBestFriend(stu1);
List<Student> stuList = new ArrayList<>();
stuList.add(stu1);
stuList.add(stu2);
HashMap<String,Student> stuMap = new HashMap<>();
stuMap.put("stu1",stu1);
stuMap.put("stu2",stu2);
//向数据模型放数据
dataMap.put("name","数据名称");
dataMap.put("stu1",stu1);
dataMap.put("stuList",stuList);
dataMap.put("stuMap",stuMap);
return dataMap;
}
/**
* 文本模型解析
*/
public static void main(String[] args) throws Throwable {
/// 使用<#list>指令遍历数据模型list中的数据
String strTemplate1 =
"<#list stuList as stu>" +
"${stu_index + 1} ${stu.name} ${stu.age} ${stu.birthday?string('yyyy-dd-MM HH:mm:ss')}\n" +
"</#list>";
/// 使用<#list>指令遍历数据模型map中的数据
String strTemplate2 =
"<#list stuMap?keys as key>" +
"${key_index + 1} ${stuMap[key].name} ${stuMap[key].age} ${stuMap[key].birthday?string('yyyy-dd-MM HH:mm:ss')}\n" +
"</#list>";
/// 使用<#if>指令进行非空校验和是非判断(引用了不存在的数据模型会报错)
String strTemplate3 =
"<#if stuList??>" +
"<#list stuList as stu>\n" +
"<#if stu.name =='藏镜人'>老藏意志强大:${stu.name}</#if>\n" +
"<#if stu.name =='任飘渺'>老任心思缜密:${stu.name}</#if>\n" +
"</#list>" +
"</#if>" +
"<#if stuList000??>" +
"stuList000 非空,正常" +
"<#else> " +
"stuList000 为空,小心 !" +
"</#if>";
/// 缺失变量的默认值使用 “!”指定,例: ${name!'名称未知'}
/// 运算符
//1、算数运算符
// FreeMarker表达式完全支持算术运算,包括: +, - , * , / , %
//2、逻辑运算符
// 逻辑与:&& 逻辑或:|| 逻辑非:! 只能作用于布尔值,否则将报错
//3、比较运算符
// 1 =或==: 判断两个值是否相等.
// 2 !=: 判断两个值是否不等.
// 3 >或gt:判断左边值是否大于右边值
// 4 >=或gte:判断左边值是否大于等于右边值
// 5 <或者lt:判断左边值是否小于右边值
// 6 <=或者lte:判断左边值是否小于等于右边值
//
// 注意: =和!=可以用于字符串、数值、日期的比较,但=和!=两边必须是相同类型的值,否则报错;FreeMarker是精确比较,"x","x ","X"是不等的。
// 其它的运算符可以作用于数字、日期,但不能作用于字符串,大多时候使用gt等字母运算符代替>会有更好的效果,因为 FreeMarker会把>解释成
// FTL标签的结束字符。当然,也可以使用括号来避免这种情况,如:<#if (x>y)>
String script1 = FreeMarkerUtil.parseString(strTemplate1, FreeMarkerController.getDataModel(new HashMap<>()));
String script2 = FreeMarkerUtil.parseString(strTemplate2, FreeMarkerController.getDataModel(new HashMap<>()));
String script3 = FreeMarkerUtil.parseString(strTemplate3, FreeMarkerController.getDataModel(new HashMap<>()));
System.out.println(script1);
System.out.println(script2);
System.out.println(script3);
}
}