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);
    }
}