原文: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>
}
}
}
}

JAVA中使用freemark生成自定义文件(json、excel、yaml、txt)的更多相关文章

  1. Java中使用HttpPost上传文件以及HttpGet进行API请求(包含HttpPost上传文件)

    Java中使用HttpPost上传文件以及HttpGet进行API请求(包含HttpPost上传文件) 一.HttpPost上传文件 public static String getSuffix(fi ...

  2. java中sort方法的自定义比较器写法(转载)

    java中sort方法的自定义比较器写法 摘要 在做一些算法题时常常会需要对数组.自定义对象.集合进行排序. 在java中对数组排序提供了Arrays.sort()方法,对集合排序提供Collecti ...

  3. 4.产生10个1-100的随机数,并放到一个数组中 (1)把数组中大于等于10的数字放到一个list集合中,并打印到控制台。 (2)把数组中的数字放到当前文件夹的numArr.txt文件中

    package cn.it.text; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayLis ...

  4. 在java中调用mockjs生成模拟数据

    一.手写版 在前端有个模拟数据的神器 Mock.js 能生成随机数据,拦截 Ajax 请求,然后我觉得他的这个生成随机数据不错.然后我就到度娘一顿操作,没找到类似的java实现,于是就有了下面的代码: ...

  5. java中采用dom4j解析xml文件

    一.前言 在最近的开发中用到了dom4j来解析xml文件,以前听说过来解析xml文件的几种标准方式:但是从来的没有应用过来,所以可以在google中搜索dmo4j解析xml文件的方式,学习一下dom4 ...

  6. java中Array/List/Map/Object与Json互相转换详解

    http://blog.csdn.net/xiaomu709421487/article/details/51456705 JSON(JavaScript Object Notation): 是一种轻 ...

  7. Java解析XML与生成XML文件

    XML是eXtensible Markup Language(可扩展标记语言)的简写形式,它是一种元标记语言(meta-markup language),也就是说它没有一套能够适用于各个领域中所有用户 ...

  8. 如何让使用create-react-app构建的项目在build过程中如何不生成.map文件

    避免create-react-app的项目在build的过程中生成 .map 文件的方法:主要是更改 package.json 里面的 build 命令!正式进入修改步骤前,推荐安装 cross-en ...

  9. Java中常用IO流之文件流的基本使用姿势

    所谓的 IO 即 Input(输入)/Output(输出) ,当软件与外部资源(例如:网络,数据库,磁盘文件)交互的时候,就会用到 IO 操作.而在IO操作中,最常用的一种方式就是流,也被称为IO流. ...

随机推荐

  1. 删除maven仓库中的lastUpdate文件

    使用idea时导入hibernate 5.1.0的jar包,然后发现本地仓库中找不到该版本的jar 然后手贱 alt+enter 发现提示 update maven indices 然后以为更新就会好 ...

  2. Glibc说明

    Glibc glibc是gnu发布的libc库,也即c运行库.glibc是linux系统中最底层的api(应用程序开发接口),几乎其它任何的运行库都会倚赖于glibc.glibc除了封装linux操作 ...

  3. Tomcat学习笔记(十)

    StandardWrapper容器 Context容器包含一个或者多个Wrapper实例,每个Wrapper实例表示一个具体的servlet定义. 方法调用序列 具体过程 (1)连接器创建reques ...

  4. npm下载包失败的几个原因

    1. 可能是由于网络问题导致下载包失败,因为qiang,所以,直接使用npm有些情况会导致下载包失败,使用cnpm源或者yarn下载等方法可以解决这个问题. 2. 这个包不存在,检查一下包的拼写或者路 ...

  5. Topcoder SRM 606 div1题解

    打卡! Easy(250pts): 题目大意:一个人心中想了一个数,另一个人进行了n次猜测,每一次第一个人都会告诉他实际的数和猜测的数的差的绝对值是多少,现在告诉你所有的猜测和所有的差,要求你判断心中 ...

  6. 接下来打算写一下visual stuido 2013使用git进行远端管理。

    虽然我有了vs的账号,也vs2013开始已经可以进行远端的账户管理了,可是vs的版控毕竟有些依赖vs,想想还是用git吧 今天把这个环境的整套都弄地基本熟了.记录一下,算是一个小结.开始搭建系统框架

  7. 过河(DP)

    原题传送门 这道题要用到压缩的思想(原来DP还能这么用...) 其实很简单,假如我们要到某一个位置w 如果我们原位置为Q 很显然,如果(W-Q>=s*t)那么我们一定能到达W 换言之,就是如果我 ...

  8. MFC中CTime获取日期时间的方法

    MFC中CTime类的功能非常强大,可以获取年.月.日.小时.分钟.秒.星期等等,最最重要的是可根据需要去格式化.下面是具体的使用方式: ① 定义一个CTime类对象 CTime time; ② 得到 ...

  9. Linux虚拟地址空间布局以及进程栈和线程栈总结

    原文链接:http://blog.csdn.net/freeelinux/article/details/53782986[侵删] 本文转自多个博客,以及最后有我的总结.我没有单独从头到尾写一个总结的 ...

  10. UCRT: VC 2015 Universal CRT, by Microsoft

    https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt/ App local UCRT DLL ...