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

 

posted @ 2016-11-25 10:32  这个名字想了很久~  阅读(3202)  评论(2编辑  收藏  举报