JAVA中使用freemark生成自定义文件(json、excel、yaml、txt)

原文:http://blog.csdn.net/jinzhencs/article/details/51461776

 

场景:在我们工作中,有时需要生成一些文件,可能它不是一种标准的格式,比如JSON。

目的:配置一个模板,根据前端传入的值动态生成配置文件,并且支持循环判断


项目路径:

这里写图片描述 
请无视YamlTest.Java和YamlTemplate.ftl

JAVA代码:

package com.ming.freemark.demo;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

public class YamlTestList {
    //模板配置对象
    private Configuration cfg;           
    //Yaml目录
    private static String yamlPath = "resources\\yaml";

    /**
     * 初始化配置
     */
    public void init() {
        cfg = new Configuration();
        File yamlFile = null;
        try {
            yamlFile = new File(yamlPath);
            cfg.setDirectoryForTemplateLoading(yamlFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void process(Map<String, Object> map){
        try {
            Template template = cfg.getTemplate("YamlTemplate2.ftl");
            template.process(map, new FileWriter(new File(yamlPath + "\\test.yaml")));
        } catch (IOException | TemplateException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        YamlTestList test = new YamlTestList();
        test.init();

        //生成一个pod的yaml文件
        Map<String,Object> podMap = new HashMap<String,Object>();
        podMap.put("kind", "Pod");
        podMap.put("apiVersion", "v1");
        podMap.put("metadataName", "test-pod");
        podMap.put("lablesName", "test-pod");
        podMap.put("lablesVersion", "1.0");

        //此处是一个循环 一个pod包含多个微服务组件
        podMap.put("containerName", "tomcat");
        podMap.put("imageName", "tomcatImage");

        //组装一个container里面的port列表
        //一个docker container里面可能有多个组件,比如一个container部署了两个tomcat,则此处是port的列表
        List<Map<String,Object>> portList = new ArrayList<>(); 
        Map<String,Object> portMap1 = new HashMap<String,Object>();
        portMap1.put("containerPort", 8080);
        Map<String,Object> portMap2 = new HashMap<String,Object>();
        portMap2.put("containerPort", 8081);
        portList.add(portMap1);
        portList.add(portMap2);

        podMap.put("portList", portList);
        test.process(podMap);

        // myMap[key]?default(""),这里是判断值是否为null,如果为null,设置默认值为空,freemarker不支持null,如果值为null,会抛出异常报错。
    }
}

 

ftl模板文件:

{
    "kind": "${kind}",
    "apiVersion": "${apiVersion}",
    "metadata": {
        "name": "${metadataName}",
        "labels": {
            "name": "${lablesName}",
            "version": "${lablesVersion}"
        }
    },
    "spec": {
        "containers": [
            {
                "name": "${containerName}",
                "image": "${imageName}",  
                "ports":[
                    <#list portList as portInfo>
                    {
                        "containerPort":${portInfo.containerPort?c}
                    }<#if portInfo_has_next>,</#if>
                    </#list>
                ]

            }
        ]
    }
}

最终效果:

test.yaml 
之前是空白的,运行程序后自动生成一份文件(k8s的编排文件)

说明:此处其实生成的是.json文件。打错字了。其实无所谓,自己把ftl里面的改为yaml格式即可。

这里写图片描述

遇到的问题

花了2小时把这个玩意大体搞定了。 
遇到的坑: 
1.如何遍历list 
之前我按自己想的写的是<#list ${portList} as portInfo>,一直报错,后来修修改改发现原来不需要,直接portList即可。

2.加入判断 list.hasNext来决定是否加逗号。 
之前直接每个后面加逗号,然后就成这样了

"ports":[
    {
        "containerPort":8080
    },
    {
        "containerPort":8081
    },
]

所以需要加上一个判断。不过freemark直接支持

<#if portInfo_has_next>,</#if>

还是很给力.

2016-05-27 新增:

经过完整的测试部署之后的一份ftl及Demo示例,解决了list循环嵌套且list的是map的问题

ftl:

{
    "kind": "ReplicationController",
    "apiVersion": "v1",
    "metadata": {
        "name": "${appName}-rc",
        "labels": {
            "name": "${appName}-rc",
            "version": "v1"
        }
    },
    "spec": {
        "replicas": ${replicas},
        "selector": {
            "name": "${appName}-pod"
        },
        "template": {
            "metadata": {
                "name": "${appName}-pod",
                "labels": {
                    "name": "${appName}-pod",
                    "version": "v1"
                }
            },
            "spec": {
                "containers": [
                <#list containerList as containerInfo>{
                        "name": "${containerInfo.microServiceName}",
                        "image": "${containerInfo.imageUrl}",
                        "ports": [
                            <#list containerInfo.portList as portInfo>{
                                "containerPort": ${portInfo.port?c}
                            }<#if portInfo_has_next>,</#if>
                            </#list>
                        ],
                        "resources": {
                            "limits":{
                                "cpu": "${containerInfo.cpu}",
                                "memory": "${containerInfo.memory}"
                            }
                        }
                   }
                </#list>]
            }
        }
    }
}

 

测试代码:

public static String layoutData(String name,int exposePort){
        // 编排基本信息
        JSONObject layoutInfoJSON = new JSONObject();
        layoutInfoJSON.put("name", name + "layout");
        layoutInfoJSON.put("version", "v1.0");
        layoutInfoJSON.put("dmsAppName", name);
        layoutInfoJSON.put("dmsAppId", "0a2f9r8t7y6j7hg9");     //dms的应用Id
        layoutInfoJSON.put("replicas", 2);                      //副本数
        layoutInfoJSON.put("masterId", "beijing1");             //北京一区
        layoutInfoJSON.put("basicCpuScale", 1);                 //pod基础设置:6核cpu
        layoutInfoJSON.put("basicMemScale", 2);                 //pod基础设置:12G内存

        //构建微服务信息list
        //微服务1
        JSONArray msArray = new JSONArray();
        JSONObject msJsonObjectOne = new JSONObject();
        msJsonObjectOne.put("name", "tomcat");
        msJsonObjectOne.put("version", "1.0");
        msJsonObjectOne.put("type", 1);                         //微服务类型:1:service、2:job
        msJsonObjectOne.put("domain", "www.test.com");
        msJsonObjectOne.put("imageUrl", "tomcat-1");
        msJsonObjectOne.put("memRatio", 1);
        msJsonObjectOne.put("cpuRatio", 1);
        //微服务1中的ports 端口列表
        JSONArray portArray = new JSONArray();
        JSONObject portJsonObjectOne = new JSONObject();
        portJsonObjectOne.put("port", 8080);                        //容器本身的端口
        portJsonObjectOne.put("protocol", "tcp");                  //端口协议类型
        portJsonObjectOne.put("exposePort", exposePort);          //容器端口 - 外网暴露端口 注意端口占用
        portArray.add(portJsonObjectOne);
        msJsonObjectOne.put("ports", portArray);

        //微服务1中的evns 环境变量列表
        JSONArray evnArray = new JSONArray();
        JSONObject evnJsonObjectOne = new JSONObject();
        evnJsonObjectOne.put("key", "evn_key1");
        evnJsonObjectOne.put("value", "evn_value1");
        evnJsonObjectOne.put("option", "evn_option1");
        evnArray.add(evnJsonObjectOne);

        msJsonObjectOne.put("evns", evnArray);

        msArray.add(msJsonObjectOne);

        //把微服务放入编排信息中
        layoutInfoJSON.put("microServiceInfoList", msArray);

        return JSONObject.toJSONString(layoutInfoJSON);
    }

结果:

{
    "kind": "ReplicationController",
    "apiVersion": "v1",
    "metadata": {
        "name": "k8stest6-rc",
        "labels": {
            "name": "k8stest6-rc",
            "version": "v1"
        }
    },
    "spec": {
        "replicas": 2,
        "template": {
            "metadata": {
                "name": "k8stest6-pod",
                "labels": {
                    "name": "k8stest6-pod",
                    "version": "v1"
                }
            },
            "spec": {
                "containers": [
                {
                        "name": "tomcat",
                        "image": "tomcat-1",
                        "ports": [
                            {
                                "containerPort": 8080
                            }
                        ],
                        "resources": {
                            "limits":{
                                "cpu": "1",
                                "memory": "2.0Gi"
                            }
                        }
                   }
                ]
            }
        }
    }
}

注意:要使用这个json最好 
.trim().replaceAll(" ", ""); 
并且要注意不要有缩进,会被坑


持续更新ing…..

2016-07-06:

{
    "kind": "ReplicationController",
    "apiVersion": "v1",
    "metadata": {
        "name": "${stackName}",
        "labels": {
            "appName": "${appName}",
            "stackName": "${stackName}",
            <#list containerList as containerInfo>
                   "${containerInfo.microServiceName}-major": "${containerInfo.major}",
                   "${containerInfo.microServiceName}-version": "${containerInfo.version}"
            <#if containerInfo_has_next>,</#if></#list>
            }
        },
    "spec": {
        "replicas": ${replicas},
        "template": {
            "metadata": {
                "name": "${stackName}",
                "labels": {
                 "appName": "${appName}",
                 "stackName": "${stackName}",
                  <#list containerList as containerInfo>
                              "${containerInfo.microServiceName}-major": "${containerInfo.major}",
                              "${containerInfo.microServiceName}-version": "${containerInfo.version}"
                  <#if containerInfo_has_next>,</#if></#list>
                  }
                },
            "spec": {
                "volumes":
                    [{
                        "name": "flumelog",
                        "hostPath":
                            {
                            "path": "/var/logs/ulog/${appName}-${stackName}"
                            }
                    }],
                "containers": [
                <#list containerList as containerInfo>{
                        "name": "${containerInfo.microServiceName}",
                        "image": "${containerInfo.imageUrl}",
                        "ports": [
                            <#list containerInfo.portList as portInfo>{
                                "containerPort": ${portInfo.targetPort?c}
                           }
                           <#if portInfo_has_next>,</#if> 
                           </#list>
                        ],
                        "env": [
                            <#list containerInfo.envList as envInfo>{
                                "name": "${envInfo.name}",
                                "value": "${envInfo.value}"
                           }
                           <#if envInfo_has_next>,</#if> 
                           </#list>
                        ],
                        "volumeMounts": [
                        {
                          "mountPath": "${containerInfo.logPath}",
                          "name": "flumelog"
                        }
                        ],
                        "resources": {
                          "limits":{
                            <#if containerInfo.cpu??>
                              "cpu": "${containerInfo.cpu}"
                            </#if>
                            <#if containerInfo.memory??>
                              ,"memory": "${containerInfo.memory}"
                            </#if>
                          }
                        }
                   }<#if containerInfo_has_next>,</#if></#list>
                   ]
                <#if nodeSelector??>  //这里是判断是否为null
                ,
                "nodeSelector": {
                    <#list nodeSelector as nodeSelector>
                        "${nodeSelector.key}": "${nodeSelector.value}"
                        <#if nodeSelector_has_next>,</#if> 
                    </#list>
                }
                </#if>
            }
        }
    }
}

 

转载于:https://www.cnblogs.com/shihaiming/p/6100618.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Velocity 是一种基于模板的 Java 技术,它使用模板来生成文本输出,而 Freemarker 是一种用来生成动态内容的 Java 框架。Velocity 是一种简单的模板语言,它只允许在模板使用简单的语法来控制文本输出;而 Freemarker 是一种功能强大的模板语言,它支持对文本输出的复杂控制。 ### 回答2: Velocity和FreeMarker都是Java常用的模板引擎,用于动态生成文本输出。两者都有各自的优点和特点。 Velocity是老牌的模板引擎,它使用简单,模板语法相对简单易懂,非常符合Java语言习惯。Velocity支持将Java对象与模板进行绑定,通过模板引擎可以方便地对数据进行处理和渲染。Velocity的语法也非常简洁,使得模板的编写很容易上手。Velocity的最大优点是速度较快,生成速度远高于其他模板引擎。 而FreeMarker相较于Velocity更加功能强大,具有很高的可扩展性,对逻辑处理更灵活。FreeMarker的语法相较于Velocity更加严格,更面向对象。它提供了很多高级特性,如条件语句、循环语句、自定义指令等,使得模板的编写更加灵活和强大。另外,FreeMarker还支持模板继承和布局,可以更好地复用和管理模板。FreeMarker生成的输出也更加规范和可控。 总体来说,Velocity适合简单的模板处理,对于需要快速生成大量文本的场景更适合;而FreeMarker适合需要更复杂逻辑处理和更高度定制化的情景。根据具体的项目需求和开发经验,选择合适的模板引擎可以有效提高开发效率和代码质量。 ### 回答3: Java的Velocity和Freemarker都是流行的模板引擎,用于将数据和模板结合生成动态的HTML代码或其他格式的文本。 Velocity是由Apache软件基金会开发和维护的开源项目。它被设计成非常简单和易于使用的模板引擎。Velocity使用简单的语法和标签来表示变量、循环和条件语句等。它的语法类似于HTML标签,因此很容易理解和学习。这也是它被广泛使用的一个原因。另外,Velocity具有较低的学习曲线,可以轻松地与Java程序集成,使得它成为开发人员的首选。 Freemarker也是一个开源的模板引擎,它由Apache软件基金会提供支持。相比于Velocity,Freemarker提供了更强大和灵活的功能。Freemarker支持更复杂的表达式和逻辑运算符。它还提供了模板继承、宏、条件判断、循环等高级特性。这些特性使得Freemarker可以处理更复杂和多样化的模板需求。 在性能方面,Velocity和Freemarker都表现出色,但实际的性能取决于具体的使用场景和实现方式。一般来说,二者的效率相差不大。 另一个重要的区别是文档的渲染方式。Velocity使用动态方法调用的方式进行文档渲染,而Freemarker使用强类型对象模型和方法调用。这意味着在Freemarker,您需要传递一个完整的数据模型对象,而在Velocity,您可以传递多个键值对。 综上所述,Velocity和Freemarker都是优秀的Java模板引擎,它们各有特点并适用于不同的需求。Velocity易于学习和使用,而Freemarker则提供了更强大和灵活的功能。开发人员可以根据具体的项目需求选择适合的模板引擎来处理动态模板生成的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值