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

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

 

場景:在咱們工做中,有時須要生成一些文件,可能它不是一種標準的格式,好比JSON。java

目的:配置一個模板,根據前端傳入的值動態生成配置文件,而且支持循環判斷node


項目路徑:

這裏寫圖片描述 
請無視YamlTest.Java和YamlTemplate.ftldocker

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

說明:此處其實生成的是.json文件。打錯字了。其實無所謂,本身把ftl裏面的改成yaml格式便可。api

這裏寫圖片描述

遇到的問題

花了2小時把這個玩意大致搞定了。 
遇到的坑: 
1.如何遍歷list 
以前我按本身想的寫的是<#list ${portList} as portInfo>,一直報錯,後來修修改改發現原來不須要,直接portList便可。tomcat

2.加入判斷 list.hasNext來決定是否加逗號。 
以前直接每一個後面加逗號,而後就成這樣了app

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

因此須要加上一個判斷。不過freemark直接支持dom

<#if portInfo_has_next>,</#if>

仍是很給力.tcp

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>
            }
        }
    }
}
相關文章
相關標籤/搜索