背景:由于项目需要,需要把csv表里的数据进行处理后生成枚举类,由于数据量较大,这就需要编写一个自动生成代码的程序。
FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。一般来说,使用FreeMarker生成HTML页面较为常用。模板编写为FreeMarker Template Language (FTL)。它是简单的,专用的语言, 不是 像PHP那样成熟的编程语言。 那就意味着要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。在模板中,你可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据
模板(FTL编程)是由如下部分混合而成的:
文本:文本会照着原样来输出。
插值:这部分的输出会被计算的值来替换。插值由
${
and}
所分隔(或者#{
and}
,这种风格已经不建议再使用了);FTL 标签:FTL标签和HTML标签很相似,但是它们却是给FreeMarker的指示, 而且不会打印在输出内容中。
注释:注释和HTML的注释也很相似,但它们是由
<#--
和-->
来分隔的。注释会被FreeMarker直接忽略, 更不会在输出内容中显示。
常用指令参考:
❗ if, else, elseif 进行判断
<#if condition>
...
<#elseif condition2>
...
<#elseif condition3>
...
...
<#else>
...
</#if>
❗ list, else, items, sep, break 进行循环
<#list sequence>
....
<#items as item>
....
</#items>
....
<#else>
....
</#list>
❗include 在你的模板中插入另外一个 FreeMarker 模板文件 (由 path 参数指定)
<#include path>
或
<#include path options>
❗ switch, case, default, break
<#switch value>
<#case refValue1>
...
<#break>
<#case refValue2>
...
<#break>
...
<#case refValueN>
...
<#break>
<#default>
...
</#switch>
本程序的目的是实现通过freemarker将csv中的数据转为枚举类并生成.java文件
首先添加依赖
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
.ftl文件如下 (需要放在resources/templates)
package ${package_name};
public enum ${enum_class_name}Enum {
<#if enum_list?exists>
<#list enum_list as enum>
${enum.enumName}("${enum.fullName}","${enum.description}",${enum.dataType},${enum.section})<#if enum_index == ((enum_list?size) - 1)>;<#else >,</#if>
</#list>
</#if>
private String fullName;
private String description;
private DataType dataType;
private Section section;
${enum_class_name}Enum(String fullName, String description, DataType dataType,Section section) {
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public DataType getDataType() {
return dataType;
}
public void setDataType(DataType dataType) {
this.dataType = dataType;
}
public Section getSection() {
return section;
}
}
CSV生成枚举类的主程序
/**
* CSV转枚举类
* created by lug on 2019/7/18.
*/
public class CSV2Enum {
private static ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
//枚举需要生成到那个包下面
private static String packageName = "com.enumerate";
//枚举类名称
private static String enumClassName = "name";
//枚举类生成后类上的注解
private static String enumAnnotation = "枚举类";
//这里比较重要
//类上的作者
private static String AUTHOR = "Lug";
//类上的日期
private static String CURRENT_DATE = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
public static void main(String[] args) throws Exception {
//我这里是把多个csv文件放到一个文件夹中并读取的所有文件
File file=new File("...");
File[] files=file.listFiles();
List<File> fileList=Arrays.asList(files);
List<DataDomain> list=handleCSV(fileList); //将CSV文件存入list中
generateEnumClassFile(list);
System.out.println("执行结束!");
}
public static void generateEnumClassFile(List<DataDomain> list) throws Exception{
final String suffix = "Enum.java"; //后缀
final String path = "D:\\" + suffix; //.java文件的地址
final String templateName = "EnumClass.ftl"; //ftl文件的地址
File mapperFile = new File(path);
Map<String,Object> dataMap = new HashMap<>();
dataMap.put("enum_list", list);
generateFileByTemplate(templateName,mapperFile,dataMap);
}
public static void generateFileByTemplate(final String templateName,File file,Map<String,Object> dataMap) throws Exception{
Template template = FreeMarkerTemplateUtils.getTemplate(templateName);
FileOutputStream fos = new FileOutputStream(file);
dataMap.put("author",AUTHOR);
dataMap.put("date",CURRENT_DATE);
dataMap.put("package_name",packageName);
dataMap.put("enum_annotation",enumAnnotation);
dataMap.put("enum_class_name",enumClassName);
Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"),10240);
template.process(dataMap,out);
}
//CSV存入list中
private static List<DataDomain> handleCSV(List<File> files) {
//DataDomain是CSV文件对应实体类,这个不多加赘述
List<DataDomain> list = new ArrayList<>();
BufferedReader br = null;
for (File file:files
) {
try {
br = new BufferedReader(new FileReader(file));
String[] line;
while ((line = br.readLine().split(",")) != null) {
list.add(new DataDomain(line[0],line[1],line[2]))
}
} catch (Exception e) {
} finally {
if (br != null) {
try {
br.close();
br = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return list;
}
}
Freemarker配置类:
public class FreeMarkerTemplateUtils {
private FreeMarkerTemplateUtils(){}
private static final Configuration CONFIGURATION = new Configuration(Configuration.VERSION_2_3_22);
static{
//这里比较重要,用来指定加载模板所在的路径
CONFIGURATION.setTemplateLoader(new ClassTemplateLoader(FreeMarkerTemplateUtils.class, "/templates"));
CONFIGURATION.setDefaultEncoding("UTF-8");
CONFIGURATION.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
CONFIGURATION.setCacheStorage(NullCacheStorage.INSTANCE);
}
public static Template getTemplate(String templateName) throws IOException {
try {
return CONFIGURATION.getTemplate(templateName);
} catch (IOException e) {
throw e;
}
}
public static void clearCache() {
CONFIGURATION.clearTemplateCache();
}
}
至此,就完成了自动生成枚举类代码的编写啦