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>
}
}
}
}
JAVA中使用freemark生成自定义文件(json、excel、yaml、txt)的更多相关文章
- Java中使用HttpPost上传文件以及HttpGet进行API请求(包含HttpPost上传文件)
Java中使用HttpPost上传文件以及HttpGet进行API请求(包含HttpPost上传文件) 一.HttpPost上传文件 public static String getSuffix(fi ...
- java中sort方法的自定义比较器写法(转载)
java中sort方法的自定义比较器写法 摘要 在做一些算法题时常常会需要对数组.自定义对象.集合进行排序. 在java中对数组排序提供了Arrays.sort()方法,对集合排序提供Collecti ...
- 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 ...
- 在java中调用mockjs生成模拟数据
一.手写版 在前端有个模拟数据的神器 Mock.js 能生成随机数据,拦截 Ajax 请求,然后我觉得他的这个生成随机数据不错.然后我就到度娘一顿操作,没找到类似的java实现,于是就有了下面的代码: ...
- java中采用dom4j解析xml文件
一.前言 在最近的开发中用到了dom4j来解析xml文件,以前听说过来解析xml文件的几种标准方式:但是从来的没有应用过来,所以可以在google中搜索dmo4j解析xml文件的方式,学习一下dom4 ...
- java中Array/List/Map/Object与Json互相转换详解
http://blog.csdn.net/xiaomu709421487/article/details/51456705 JSON(JavaScript Object Notation): 是一种轻 ...
- Java解析XML与生成XML文件
XML是eXtensible Markup Language(可扩展标记语言)的简写形式,它是一种元标记语言(meta-markup language),也就是说它没有一套能够适用于各个领域中所有用户 ...
- 如何让使用create-react-app构建的项目在build过程中如何不生成.map文件
避免create-react-app的项目在build的过程中生成 .map 文件的方法:主要是更改 package.json 里面的 build 命令!正式进入修改步骤前,推荐安装 cross-en ...
- Java中常用IO流之文件流的基本使用姿势
所谓的 IO 即 Input(输入)/Output(输出) ,当软件与外部资源(例如:网络,数据库,磁盘文件)交互的时候,就会用到 IO 操作.而在IO操作中,最常用的一种方式就是流,也被称为IO流. ...
随机推荐
- HDU 4288 Coder ( 离散化 + 离线 + 线段树 )
这题跟ZOJ 3606的解题思路很相似. 题意:有3中操作:1.向集合中增加一个数x(1≤x≤1e9):2.从集合中删去一个数x(保证这个数存在):3.查询集合中所有位置满足i%5==3的数a[i]的 ...
- maven学习(十七)——在eclipse中导入外部maven项目
外部maven项目,导入Eclipse中进行开发 操作步骤如下所示:
- HttpWebRequest调用WebService后台需要Session信息问题的解决办法
今天在用HttpWebRequest调用后台ASP.NET 的WebService方法时遇到了一个问题,后台的WebService方法里使用到了Session对象中的用户信息,而Session对象中的 ...
- 少年Pi的奇幻漂流
选择怀疑作为生活哲学就像选择静止作为交通方式. 的确,我们遇见的人可能改变我们,有时候改变如此深刻,在那之后我们成了完全不同的人,甚至我们的名字都不一样了. 声音会消失,但伤害却留了下来,像小便蒸 ...
- nginx+php-fpm配置后页面显示空白的解决方法以及用nginx和php-fpm解决“502 Bad Gateway”问题
For reference, I am attaching my location block for catching files with the .php extension: location ...
- POJ 2406 Power Strings 暴力
emmmm 显然的是a串长度是s串长度的因数 我们可以暴力枚举因数然后暴力check #include<cstdio> #include<algorithm> #include ...
- 刷题总结——子串(NOIP2015)
题目: 题目背景 NOIP2015 提高组 Day2 T2 题目描述 有两个仅包含小写英文字母的字符串 A 和 B .现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在 ...
- linux——rhel安装yum
在进行下面的操作之前,一定要确保网络正常,如果没有网络,下面的所有操作一个都不能实现.(下次会写个本地源的配置,这个就可以离线的状态下进行,需要用到系统的镜像文件,安装好系统之后不要删掉.) 首先配置 ...
- 论文笔记《Deep Hand: How to Train a CNN on 1 Million Hand Images When Your Data Is Continuous and Weakly Labelled》
一.概述 这个是最近的核心工作了,基本上都是靠着这篇paper的model过日子了啊.. 论文主要讲的是hand gesture recognition,实际上是用googlenet做的一个class ...
- HDU 5752
Sqrt Bo Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total S ...