原文: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. Codeforces Round #384 (Div. 2) 734E(二分答案+状态压缩DP)

    题目大意 给定一个序列an,序列中只有1~8的8个整数,让你选出一个子序列,满足下列两个要求 1.不同整数出现的次数相差小于等于1 2.子序列中整数分布是连续的,即子序列的整数必须是1,1,1.... ...

  2. HDU - 2814 Visible Trees

    题意: m*n(1<=m,n<=100000)的森林里,起始点在(1,1),某人从(0,0)点开始看,问能看到多少棵树. 题解: 求出1~x中的每个数与1~y的数中互质的数的总和.用素数筛 ...

  3. 《R语言实战》读书笔记--第二章 创建数据集

    2.1数据集的概念 变量的类型是不同的,比如标示符.日期变量.连续变量.名义变量.有序型变量等,记得数据挖掘导论中有专门的描述. R可以处理的数据类型包括了数值型.字符型.逻辑型.复数型(虚数).原生 ...

  4. 第二届360杯全国大学生信息安全技术大赛部分解题思路(WEB安全)

    第一题如下: 用burpsuit设置好代理后,点击发送验证码,可以看到如下: 然后go之后可以看到如下的验证码: 提交验证码后即可获得key 第二题如下: 通过/data/mysql_error_tr ...

  5. 图表绘制工具--Matplotlib 1

    ''' [课程3.] Matplotlib简介及图表窗口 Matplotlib → 一个python版的matlab绘图接口,以2D为主,支持python.numpy.pandas基本数据结构,运营高 ...

  6. (转)python爬虫----(scrapy框架提高(1),自定义Request爬取)

    摘要 之前一直使用默认的parse入口,以及SgmlLinkExtractor自动抓取url.但是一般使用的时候都是需要自己写具体的url抓取函数的. python 爬虫 scrapy scrapy提 ...

  7. VIM使用技巧1

    .命令是vim中很重要的一个命令,用法如下: 加入有一个文件vimtest.txt,内容如下: 1 Line one  2 Line two                               ...

  8. python enumerate元素的时候可以获取下标,并且可以指定开始的下标值。

    list=["a","b","c","d","e"] for i,item in enumerate ...

  9. PHP-MYSQL时间

     Unix 时间戳  Unix timestamp ('1970-01-01 00:00:00' GMT 之后的秒数) MySQL: FROM_UNIXTIME() 给定一个Unix 时间戳 (可以是 ...

  10. Java定义bean实体类中的变量时变量名的问题

    首先:TMD,这个问题花了我两个多小时,居然是因为一个字母的大小写导致的,我瞬间就&Y^%^&%&()*%¥%¥¥&^#@%&; 事情是酱紫的: 我定义了一个变 ...