原文: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. Python洗牌算法重写

    Python有自带的洗牌算法函数shuffle(). 自己也通过学习也琢磨了一下它的实现,然后给出一个时间复杂度O(n),空间复杂度O(4)的例子: import random def shuffle ...

  2. HDU 2491

    欢迎参加——BestCoder周年纪念赛(高质量题目+多重奖励) Priest John's Busiest Day Time Limit: 4000/2000 MS (Java/Others)    ...

  3. MVC从Controller到view进行传值的方法

    这几天基本上都是交接的一些杂事,没有什么工作任务,就有空来回顾一下MVC.虽然工作中也用到了MVC,但已经被微软的架构师设计的找不到MVC的影子了,可能有别的考虑吧,至今还没研究出来.所以,今天就来回 ...

  4. [blockchain-035]eos的部署安装智能合约

    0.参考资料 https://github.com/EOSIO/eos/wiki 1. eos的github地址 https://github.com/EOSIO/eos 2.下载eos源码 git ...

  5. JAVA输出最大值和最小值

    public class MaxMin{ public static void main(String[] args) { int[] arr = new int[6]; Scanner input ...

  6. 石子归并的三种打开方式——难度递增———51Node

    1021 石子归并    N堆石子摆成一条线.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价.计算将N堆石子合并成一堆的最小代价.   ...

  7. 一元多项式的表示及相加(抽象数据类型Polynomial的实现)

    // c2-6.h 抽象数据类型Polynomial的实现(见图2.45) typedef struct // 项的表示,多项式的项作为LinkList的数据元素 { float coef; // 系 ...

  8. MySQL的菜鸟级操作

    windows下启动和关闭mysql 启动(windows): 在命令行下,进入到mysql安装路径的bin文件夹下执行:net start mysql 关闭(windows): 在启动的情况下执行: ...

  9. HDU1541 经典树状数组

    HDU1541 题意: 如图,等级为0的点有1,等级为1得点有4,2  等级为2的点有3,等级为3的点有5-------即即左下角的点的个数 现给你一些点(x,y),输入顺序按y升序,y相等时按x升序 ...

  10. poj1039 Pipe(计算几何叉积求交点)

    F - Pipe Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Sta ...