Word通过模版生成文档

目的是通过使用预先设置好的模版文档,通过使用调度任务产生的数据(包括文本、图片、列表、报表等),回填生成完整的Word文档,通常可用于需要定时生成文档的场景。

基本思路

使用开源项目Word模版生成文档项目poi-tl,把后台组织好的数据,包括文本、列表、表格和图片,填到相应的模版里,生成一份完整的文档。

使用说明

poi-tl是一个jar包,使用时只需在项目pom文件内引入依赖即可:

1
2
3
4
5
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.2.0</version>
</dependency>

该组件对模版文档内的语法结构要求都是以 结束,具体如下:

1
2
3
4
> 普通文本:{{template}},渲染类为String或者TextRenderData
> 图片:{{@template}},渲染类为PictureRenderData
> 表格:{{#template}},渲染类为TableRenderData
> 列表:{{*template}},渲染类为NumbericRenderData

另外,关于文档样式的问题,默认会使用模版占位符的样式,如果需要动态变化样式,可以在构造渲染类的时候注入样式。

Demo

具体使用代码如下,其中Map里的所有Key都是模版文档里的占位符:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public static void main(String[] args) throws IOException {
Map<String, Object> renderData = new HashMap<String, Object>() {{
// 文本
put("date", "2018-03-19"); // 直接用String写入文本
put("title", new TextRenderData("Here is the Title.")); // 通过渲染类写入文本
put("author", new TextRenderData("66ccFF", "Elvis")); // 添加样式,另外还可以修改渲染类的Style属性配置完整的样式

// 通过文件系统路径方式加载图片
put("image1", new PictureRenderData(700, 300, "/image1.png"));
// 通过Http方式加载图片
String url = "xxx"; // 请求的URL
byte[] imageByHttp = getImageByHttp(url, "[{...}]"); // param参数为JSON字符串,url参数根据实际需要修改(此处使用的是post方法的请求)
put("image2", new PictureRenderData(700, 300, "image.png", imageByHttp)); // 由于path参数会有验证不能为空且必须为合法格式,但其实通过字节数组的方式不需要读文件,所以填定义一个合法文件名即可

// 表格
put("Table", new TableRenderData(new ArrayList<RenderData>() {{
add(new TextRenderData("d0d0d0", "column1"));
add(new TextRenderData("111111", "column2"));
add(new TextRenderData("d0d0d0", "column3"));
}}, new ArrayList<Object>() {{
add("row1;r1c2;");
add("row2;;r2c3");
add("row3;r3c2;r3c3");
}}, "no datas", 10600));

// 列表
put("List", new NumbericRenderData(FMT_DECIMAL, new ArrayList<TextRenderData>() {{
add(new TextRenderData("Deeply in love with the things you love, just deepoove."));
add(new TextRenderData("df2d4f", "Deeply in love with the things you love, just deepoove."));
}}));
}};

// 读取模版并生成文档
XWPFTemplate template = XWPFTemplate.compile("/xx/template.docx").render(renderData);

// 输出到文件系统
FileOutputStream out = new FileOutputStream("/xx/output.docx");
template.write(out);
template.close();
out.close();
}

上面有使用Http请求的方法来获取图片,其实poi-tl包里提供了Http请求的Get的工具方法,但上面我们给出了Post方法的使用方法,下面是Post请求的工具方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public static byte[] getImageByHttp(String urlStr, String param) throws IOException {
try {
URL url = new URL(urlStr);
URLConnection conn = url.openConnection();
conn.setRequestProperty("Content-Type", "application/png;charset=UTF-8");
conn.setDoOutput(true);
conn.setDoInput(true);
PrintWriter out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(), "utf-8"));
out.print(param);
out.flush();

int len;
byte[] data = new byte[1024];
InputStream inputStream = conn.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
while ((len = inputStream.read(data)) != -1) {
outputStream.write(data, 0, len);
}
byte[] result = outputStream.toByteArray();

out.close();
inputStream.close();
outputStream.close();
return result;
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}

题外话

使用poi-tl基本上只能生成一些结构比较基本的文档,当需要相对复杂的图或者表的时候是处理不来的,这种情况下的一种解决方法是把需要的图或者表转成图片然后插入到文档中。至于如何生成图和表,可以在PhantomJS的环境下利用诸如EcharsHighCharts这些图表插件生成。

Dockerfile常用语法

介绍Dockerfile部分较为常用的语法,关于Docker常用命令参考Docker常用命令

  • FROM ${IMAGE}[:${TAG}]

    • 仅且必须出现在Dockerfile的第一个指令,指定构建镜像的基础源镜像;
    • 不填TAG时默认TAG为latest
  • MAINTAINER ${AUTHOR} ${EMAIL}

    • 记录构建镜像的作者及其邮箱的信息;
  • RUN ${COMMAND} ${PARAM}..

    • 每执行一次RUN都会形成一层新的镜像,因为镜像只读,在后续命令里删除、卸载等操作无法影响前面已形成的镜像,因此体积也不会下降;
    • 因为每一个RUN命令都会形成新的镜像,因此可以通过&&符号连接多条命令一次完成;
    • 执行的命令不继承原来的环境变量;
  • CMD ${COMMAND} ${PARAM}..

    • Dockerfile启动时的提供的默认命令;
    • 只能有一个CMD,写多个时最后一个生效,启动容器时用户提供了命令的话则此项会被覆盖而失效;
  • ENTRYPOINT ${COMMAND} ${PARAM}..

    • CMD,但不会被用户启动容器时指定的CMD命令覆盖,如果要覆盖需要指定OPTION --entrypoint
    • 同样只能有一个ENTRYPOINT,写多个时最后一个生效;
  • EXPOSE ${CONTAINER_PORT}

    • 指定容器需要与外部进行映射的端口,允许使用多个EXPOSE进行多端口映射,在启动添加OPTION-P时生效;
  • ENV ${KEY}=${VALUE}

    • 设置容器的环境变量,也可以提供给后面的RUN命令使用;
    • 如需要一行设置多个环境变量时可以用空格分隔;
  • ARG ${KEY}

    • 设置构建镜像时需要使用的参数,ARG ${KEY}=${VALUE}可以设置默认值;
    • 使用方式为在docker build时通过--build-arg ${KEY}=${VALUE}传入参数;
  • ADD ${SOURCE} ${DEST}

    • 把本地或者远程文件或文件夹复制到容器中;
    • 如果传输的是压缩包则会自动解压;
  • COPY ${SOURCE} ${DEST}

    • 功能同ADD,但不能处理网络文件,也不会自动解压压缩文件;
  • VOLUME ${PATH}

    • 指定容器内要挂载到主机的目录;
    • 使用该方式时对应主机的目录是自动生成的,无法被指定;
    • 可以在使用docker run启动容器时通过OPTION-v的方式代替该方式;
  • USER ${USER_NAME}

    • 指定运行容器的用户;
  • WORKDIR ${PATH}

    • 为后续的RUNCMDENTRYPOINT命令指定容器内的工作目录;
  • ONBUILD ${INSTRUCTION}

    • 配置该镜像被作为其它镜像的基础镜像时需要执行的命令;

Docker常用命令

列举部分较常用的Docker命令行指令。

镜像相关命令

对特指的某个镜像操作时必须要指定该镜像的名称和TAG,如果不指定TAG会默认TAG为latest,另外也可以通过镜像ID来直接指定。

  • docker images : 查看当前本地仓库所有镜像

  • docker search ${KEYWORD} : 在线查找镜像

  • docker login [${SERVER}] : 登录某个Docker仓库,默认为官方仓库DockerHub

    • -u ${USERNAME} : 指定登录用户名
    • -p ${PASSWORD} : 指定登录用户的密码
  • docker logout [${SERVER}] : 退出登录

  • docker pull ${IMAGE}:${TAG} : 下载镜像,不指定TAG则默认下载latest版本

  • docker push ${IMAGE}:${TAG} : 上传镜像到镜像仓库,需要先登陆镜像仓库

  • docker rmi ${IMAGE}:${TAG} : 删除本地仓库中镜像

  • docker save ${IMAGE}:${TAG} -o ${FILE_NAME} : 把镜像保存为tar文件,也可以写成docker save ${IMAGE}:${TAG}>${FILE_NAME}

  • docker load -i ${FILE_NAME} : 把镜像文件导入到仓库,也可以写成docker load <${FILE_NAME}

  • docker export ${CONTAINER_ID} -o ${FILE_NAME} : 把容器保存为tar文件,也可以写成docker export ${IMAGE}:${TAG}>${FILE_NAME}

  • docker import ${FILE_NAME} ${IMAGE}:${TAG} : 把镜像文件导入到仓库,需要指定导入后镜像的IMAGE和TAG

  • docker tag ${IMAGE}:${TAG} ${NEWIMAGE}:${NEWTAG} : 为某个镜像增加新的镜像名和TAG

  • docker commit ${CONTAINER_ID} ${IMAGE}:${TAG} : 提交对某个容器的更改操作,输出为新的镜像

    • -m="${COMMIT_MESSAGE}" : 填写提交信息
    • -a="${AUTHOR}" : 填写镜像作者
    • -p : commit时暂停容器
  • docker build ${DOCKER_FILE_PATH} -t ${IMAGE}:${TAG} : 通过Dockerfile创建镜像

容器运行相关命令

对容器进行操作时需要指定该容器的ID,另外也可以通过分配的或自定义的容器名来确定容器。

  • docker run : 启动一个新的容器

    • -t : 在新容器内指定一个伪终端或终端
    • -i : 允许对容器内的标准输入(STDIN)进行交互
    • -d : 后台运行
    • -P : 选取主机的随机端口对容器端口进行映射
    • -p ${HOST_PORT}:${CONTAINER_PORT} : 指定端口的映射,可以使用多次-p以映射多个端口
    • --name ${CONTAINER_NAME} : 指定容器的NAME
    • -v ${HOST_PATH}:${CONTAINER_PATH} : 把本机某个目录挂载到容器的某个目录下
  • docker stop ${CONTAINER_ID} : 停止某个Docker容器

  • docker start ${CONTAINER_ID} : 启动某个关掉的Docker容器

  • docker restart ${CONTAINER_ID} : 重启某个正在运行的Docker容器

  • docker kill ${CONTAINER_ID} : 强行停止某个Docker容器

  • docker attach ${CONTAINER_ID} : 进入某个正在后台运行的容器,通过CTRL+P+Q可以把容器再次切换回后台

  • docker exec ${CONTAINER_ID} ${COMMAND} : 在某个运行中的容器里执行COMMAND后退出,如果要进入容器则COMMAND为/bin/bash

  • docker pause ${CONTAINER_ID} : 暂停容器

  • docker unpause ${CONTAINER_ID} : 恢复被暂停的容器

  • docker ps : 查看当前正在运行的容器的信息

    • -a : 查看包括已关闭的容器
    • -q : 只列出容器的ID,可以与其他需要容器ID的命令组合使用,如[docker rm `docker ps -a -q`]可以删除全部的容器
  • docker port ${CONTAINER_ID} : 查看容器的端口映射情况

  • docker logs ${CONTAINER_ID} : 查看容器内的标准输出

    • -f : tail形式输出log
  • docker top ${CONTAINER_ID} : 查看容器内部运行的进程

  • docker stats : 查看容器资源使用状态

  • docker inspect ${CONTAINER_ID} : 查看容器的底层信息

  • docker rm ${CONTAINER_ID} : 移除不需要的容器

  • docker diff ${CONTAINER_ID} : 查看容器发生改变的文件结构

  • docker cp ${HOST_PATH} ${CONTAINER_ID}:${CONTAINER_PATH} : 本机和容器间的文件传输,在前的为源路径,在后面的为目标路径,容器侧的路径前要加上容器ID

Docker自身服务相关命令

  • docker version : 查看当前使用的Docker版本信息

  • docker info : 查看Docker当前的详细系统信息

EditorConfig

EditorConfig 是一套用于统一代码风格的方案,可以帮助开发者在不同的编辑器和IDE之间定义和维护一致的代码风格,同时有利于团队的合作,避免不必要的格式重构。

原理

当打开一个文件时,EditorConfig插件会从该文件所在目录开始往上每一级目录中查找.editorconfig文件,直到找到.editorconfig文件中有root=true这个配置为止,并把该配置文件作为根配置。EditorConfig插件会从根配置文件开始开始往下层读取,下层文件配置会覆盖上层文件配置,所以最接近所打开文件的配置优先级最高。另外,配置文件里的属性名和属性值大小写不敏感,编译时都会被转为小写,而没有被明确指定的某个属性则会使用编辑器默认的配置。

通配符说明

通配符 作用
* 匹配除/之外的任意字符串(即不跨目录,特殊字符可以用\ 转义)
** 匹配任意单个字符(即遍历子目录下的文件)
? 匹配任意单个字符
[name] 匹配name字符
[!name] 匹配非name字符
{s1,s3,s3} 匹配任意给定的字符串

通用属性

属性 说明
indent_style [tab/space]
indent_size 对应indent_style=space时的列数
tab_width 对应indent_style=tab时的列数,默认等于indent_size
end_of_line [lf/crlf/cr] lf(\n)为Unix和OS X的默认值/crlf(\r\n)为Windows的默认值/cr(\r)为Classic Mac OS的默认值
charset [utf-8/latin1/gbk/etc..]
trim_trailing_whitespace [true/false] 是否将行尾空格自动删除
insert_final_newline [true/false]是否使文件以一个空白行结尾
root [true]表明是最顶层的配置文件,发现设为true时,才会停止继续查找

设置为unset时可以把配置重置为编辑器默认配置,另外有一些适配不同编辑器的属性,详见wiki

磁盘性能测试工具FIO的简单使用

简介

FIO是一个用来进行磁盘IO压力测试的工具,可以产生足够多的任意类型的负载 (arbitrary load),测试并得出对应的比较详细而易懂的报告。FIO支持13种不同的I/O引擎,包括:sync,mmap, libaio, posixaio, SG v3, splice, null, network, syslet,guasi, solarisaio 等等。

FIO官网

2.1.10版本下载

安装

官方默认提供的版本是源码安装,安装前需要确认是否有安装GCC。以下是安装步骤:

1
2
3
4
5
6
7
8
9
10
11
# wget直接下载
wget http://brick.kernel.dk/snaps/fio-2.1.10.tar.gz
# 解压:
tar -zxvf fio-2.1.10.tar.gz
# 编译安装:
cd fio-2.1.10
./configure
make
make install
# 检查是否安装成功:
fio

使用

简单例子

1
2
# 当前目录下,建立5G大小的test文件进行顺序读,单个线程以4k一个块大小执行,最大执行时间为1000秒,最后结果汇总输出报告,报告名为reportName
$ fio -filename=./test -direct=1 -iodepth 1 -thread -rw=read -ioengine=psync -bs=4k -size=5G -numjobs=1 -runtime=1000 -group_reporting -name=reportName

参数说明

参数 解析
filename 测试文件名称,在需要测试的挂载的盘的目录下
direct=1 direct=1表示测试过程绕过机器自带的buffer,使测试结果更真实
rw read/write/randread/randwrite,读写模式[顺序读/顺序写/随机读/随机写]
bs 单次io的块大小
bsrange 设定数据块大小范围
size 测试文件总大小
numjobs 线程数
runtime 设置执行最大时间,不设置则运行至size设置的大小全部完成
ioengine 设定io引擎类型
group_reporting 显示结果汇总每个进程的信息
name 输出报告的名称

报告例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
read : io=40960MB, bw=238459KB/s, iops=59614, runt=175892msec
clat (usec): min=35, max=22978, avg=131.27, stdev=61.13
lat (usec): min=35, max=22979, avg=131.49, stdev=61.14
clat percentiles (usec):
| 1.00th=[ 74], 5.00th=[ 90], 10.00th=[ 98], 20.00th=[ 107],
| 30.00th=[ 114], 40.00th=[ 119], 50.00th=[ 125], 60.00th=[ 131],
| 70.00th=[ 139], 80.00th=[ 149], 90.00th=[ 169], 95.00th=[ 195],
| 99.00th=[ 258], 99.50th=[ 286], 99.90th=[ 346], 99.95th=[ 378],
| 99.99th=[ 564]
bw (KB /s): min=23680, max=35216, per=12.53%, avg=29882.13, stdev=1601.01
lat (usec) : 50=0.03%, 100=11.33%, 250=87.42%, 500=1.20%, 750=0.01%
lat (usec) : 1000=0.01%
lat (msec) : 2=0.01%, 4=0.01%, 10=0.01%, 20=0.01%, 50=0.01%
cpu : usr=2.97%, sys=21.49%, ctx=10524303, majf=0, minf=819
IO depths : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued : total=r=10485760/w=0/d=0, short=r=0/w=0/d=0
latency : target=0, window=0, percentile=100.00%, depth=1

报告的重要指标解析

  • read/write 表示是读或者写部分的报告;
  • io表示当次执行完毕的io文件大小,bw表示带宽,iops表示每秒io次数,runt表示执行时间;
  • clat percentiles表示提交延时的排名分布;
  • lat表示响应时间,slat是提交延时,clat是完成延时;
  • lat部分的数据表示完成时延具体分布在那些时间段,可以用来直观对比不同磁盘的响应时延;
  • util表示磁盘利用率;