FreeMarker语法

概述

最近做公司一个需求,代码生成模板,编写用于生成Java Bean的ftl文件。在此记录下使用Freemarker的常用语法

FreeMarker Java使用

  1. 实例化FreeMarker配置类
Configuration conf = new Configuration();
  1. 设置配置类路径,也就是将会从该路径下读取模板文件
conf.setDirectoryForTemplateLoading(new File(dir));
  1. 读取模板文件
Template template = conf.getTemplate("freemarker.html");
  1. 定义数据模型
    将模型放入一个Map中,可以放入对象、基本类型、List、,Map等
 Map<String,Object> root = new HashMap<String,Object>();
        Person p = new Person();
        p.setId("111");
        p.setName("哈哈哈");
        root.put("person", p);
        root.put("world", "世界你好");
        //遍历List
        List<String> persons = new ArrayList<String>();
        persons.add("阿灵罗");
        persons.add("罗零");
        persons.add("灵罗");
        root.put("persons",persons);
  1. 定义输出文本的文件
Writer out = new FileWriter(new File(dir+"hello.html"));
  1. 调用模板process方法,传入数据模型及目标文件,生成文本
template.process(root, out);
    out.flush();
    out.close();
  1. 在freemarker.html中访问放入map的数据结构,如:
<#list persons as p>
Id:${p.id}
Name:${p.name}
</#list>

FreeMarker语法

这里我们根据业务需求,自定义数据结构。在ftl文件中解析数据结构,以这个过程为串联,学习FreeMarker语法

数据结构

NetInterface:用于描述网络请求接口

public class NetInterface {
	// 请求名称
	private String interfaceId;
	// 请求功能描述
	private String caption;
	// 备注信息
	private String comment;
	// 请求相对路径
	private String path = "";
	// 自定义请求地址
	private String customFullPath = "";
	// 请求类型(Post 和 Get,会覆盖 service 中配置)
	private String request_mode;
	// 成功标识
	private String succFlag;
	// 错误提示信息
	private String errorMsg;
	// 请求 model
	private SCRequestModel requestModel = new SCRequestModel();
	// 返回数据 model
	private SCResponseModel responseModel = new SCResponseModel();

	public SCInterface(String methodName, SCRequestModel request, SCResponseModel response) {
		this.interfaceId = methodName;
		this.requestModel = request;
		this.responseModel = response;
	}
}

RequestModel:描述请求参数

public class RequestModel {
	private String modelName = "";
	// 请求参数
	private List<SCParam> fields = new ArrayList<SCParam>();
	private Boolean hasCustomModel = false;
	//嵌套的子Model
	private List<RequestModel> subModels = new ArrayList<SCResponseModel>();
}	

ResponseModel:描述返回数据参数

public class ResponseModel {
	private String modelName = "";
	// 请求参数
	private List<SCParam> fields = new ArrayList<SCParam>();
	private Boolean hasCustomModel = false;
	//嵌套的子Model
	private List<ResponseModel> subModels = new ArrayList<SCResponseModel>();
}

Param:描述一个参数

public class SCParam {
    //枚举数据类型
	public enum ParamEnum {
	    //系统类型 String等
		ParamSystem(0),
		//系统List 如List<String>
		ParamArray_sys(1),
		//自定义对象类型
		ParamObject(2),
		//List 泛型为自定义对象
		ParamArray_object(3);
		
		private int mState = 0;
	    private ParamEnum(int value) {
	        mState = value;
	    }
	    public int getState() {
	    	return mState;
	    }
	}
	// 字段名称
	private String paramName;
	// 参数类型
	private ParamEnum paramType;
	// 系统字段类型
	private String sysType;
	// 备注信息
	private String caption;
	// 扩展数据类型(当不为默认类型时,使用此字符存储)
	private List<SCParam> extendParam;
}	

这里,假设我们已经有了一个List,并把它放入map中,如下:

List<NetInterface> netInterfaces = DataProvider.getInterfaces();
Map<String,Object> root = new HashMap();
root.put("interfaces",netInterfaces)
root.put("Id","abcd")
template.process(root, writer);

这样,我们在ftl文件中就能通过key值interfaces来访问List。下面我们介绍一下常用的语法

注释

<#-- 注释内容 -->

访问值

<#-- result:abcd -->
${Id}

List相关

循环list

<#list interfaces as interface>
    <#-- 访问interface -->
    path:${interface.path}
    interfaceId:${interface.interfaceId}
</#list>

list size判断

<#list interfaces as interface>
    <#-- 注意一定要加括号,否则报错 -->
    <#if (interface.requestModel.fields?size == 0)>
    <#-- gt代表大于 -->
    <#elseif (interface.requestModel.fields?size gt 0)>
    <#-- lt代表小于 -->
    <#elseif (interface.requestModel.fields?size lt 0)>
    </#if>
</#list>

下标判断

<#list interfaces as interface>
    <#-- 是否是最后一个 -->
    <#if interface_has_next>
        非最后一个
    <#else>最后一个元素
    </#if>
    <#-- 是否为第一个-->
    <#if (interface_index == 0)></#if>
    <#if >
</#list>

if条件判断

<#-- 判空-->
<#if interface.request_mode??>
    <#if interface.request_mode == "post">
    <#-- 输出内容 -->
    <#elseif interface.request_mode == "post">
    <#-- 输出内容 -->
    <#elseif interface.request_mode == "post">
    <#-- 输出内容 -->
    <#elseif interface.request_mode == "post">
    <#-- 输出内容 -->
    <#else>
    error
    </#if>
</#if>

首字母大小写

<#-- 首字母大写 -->
${param.paramName?cap_first}
<#-- 首字母小写 -->
${param.paramName?uncap_first}

宏定义

可以理解为自定义方法,我们看一个解析字段名的宏

<#-- 解析字段 -->
<#macro parserField target>
<#list target as param>
    // ${param.caption}
<#if param.paramType.getState() == 0>
<#if param.sysType == "string">
    public String ${param.paramName?uncap_first};
<#elseif param.sysType == "int32">
    public int ${param.paramName?uncap_first};
<#elseif param.sysType == "boolean">
    public boolean ${param.paramName?uncap_first};
<#elseif param.sysType == "double">
    public double ${param.paramName?uncap_first};
<#elseif param.sysType == "int64">
    public long ${param.paramName?uncap_first};
<#elseif param.sysType == "float">
    public float ${param.paramName};
<#else>
    parserClass error type state:${paramType.getState()},type:${param.sysType}
</#if>
<#elseif param.paramType.getState() == 2>
    public ${param.sysType?trim?cap_first}Object ${param.sysType?uncap_first}Object;
<#elseif param.paramType.getState() == 3>
    public List<${param.sysType?trim?cap_first}Object> ${param.sysType?uncap_first}ObjectList = new ArrayList();
<#elseif param.paramType.getState() == 1>
<#if param.paramName == "list">
    public List<<@parserType target = param.sysType/>> list = new ArrayList();
<#else>
    public List<<@parserType target = param.sysType/>>  ${param.paramName}List = new ArrayList();
</#if>
</#if>
</#list>
</#macro>

大家可以结合文章上面阐述的数据结构来看,就难理解了
调用方式

<@parserField target=interface.responseModel.fields/>

判空

正确写法

<#if responseModel.subModels??>

错误写法

<#if responseModel?.subModels>

暂时用到的语法就这些

后记

Freemarker比较难调试,是因为暂时没找到IDE提示错误,全部要肉眼来看,靠freemarker的提示来找线索。所以写的时候一定要注意语法规范,错一点就会报错。如果有好的IDE,请安利给我

展开阅读全文

没有更多推荐了,返回首页