springboot+freemarker实现生成数据库设计Word文档
以前在项目完成后都会按照要求写数据库设计文档,表少的时候还无所谓,当有上百张表的时候就不好写了。当然也有一些自动化软件可以帮我们实现这个功能,但是自定义的程度比较低。所以今天自己来实现这个功能,可以按照自己的喜好定义样式和模板,是不是很酷。
首先新建一个Word文档
然后另存为xml格式,用NotePad打开。
在xml中使用freemarker的标签将数据填充。不会freemarker的可以先自己研究一下。
<w:body>
<wx:sect>
//循环遍历所有table
<#list tables as table>
<w:p wsp:rsidR="0017374B" wsp:rsidRPr="00481323" wsp:rsidRDefault="00AD2DC7">
<w:pPr>
<w:rPr>
<w:b/>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
</w:pPr>
<w:r wsp:rsidRPr="00481323">
<w:rPr>
<wx:font wx:val="宋体"/>
<w:b/>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
<w:t>表名</w:t>
</w:r>
<w:r wsp:rsidRPr="00481323">
<w:rPr>
<w:rFonts w:hint="fareast"/>
<wx:font wx:val="宋体"/>
<w:b/>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
<w:t>:</w:t>
</w:r>
<w:r wsp:rsidRPr="00481323">
<w:rPr>
<w:b/>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
<w:t>${table.tableName} </w:t>
</w:r>
<w:r wsp:rsidRPr="00481323">
<w:rPr>
<wx:font wx:val="宋体"/>
<w:b/>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
<w:t>注释</w:t>
</w:r>
<w:r wsp:rsidRPr="00481323">
<w:rPr>
<w:rFonts w:hint="fareast"/>
<wx:font wx:val="宋体"/>
<w:b/>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
<w:t>:</w:t>
</w:r>
<w:r wsp:rsidR="005A39AB">
<w:rPr>
<w:b/>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
<w:t>${table.tableComment} </w:t>
</w:r>
</w:p>
<w:tbl>
<w:tblPr>
<w:tblW w:w="0" w:type="auto"/>
<w:tblBorders>
<w:top w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
<w:left w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
<w:bottom w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
<w:right w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
<w:insideH w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
<w:insideV w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>
</w:tblBorders>
<w:tblLook w:val="04A0"/>
</w:tblPr>
<w:tblGrid>
<w:gridCol w:w="1659"/>
<w:gridCol w:w="1659"/>
<w:gridCol w:w="1659"/>
<w:gridCol w:w="1659"/>
<w:gridCol w:w="1660"/>
</w:tblGrid>
<w:tr wsp:rsidR="00DE1640" wsp:rsidRPr="00FA35C4" wsp:rsidTr="00FA35C4">
<w:tc>
<w:tcPr>
<w:tcW w:w="1659" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="AEAAAA"/>
</w:tcPr>
<w:p wsp:rsidR="00DE1640" wsp:rsidRPr="00FA35C4" wsp:rsidRDefault="00DE1640">
<w:pPr>
<w:rPr>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
</w:pPr>
<w:r wsp:rsidRPr="00FA35C4">
<w:rPr>
<w:rFonts w:hint="fareast"/>
<wx:font wx:val="宋体"/>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
<w:t>列名</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1659" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="AEAAAA"/>
</w:tcPr>
<w:p wsp:rsidR="00DE1640" wsp:rsidRPr="00FA35C4" wsp:rsidRDefault="00DE1640">
<w:pPr>
<w:rPr>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
</w:pPr>
<w:r wsp:rsidRPr="00FA35C4">
<w:rPr>
<w:rFonts w:hint="fareast"/>
<wx:font wx:val="宋体"/>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
<w:t>数据类型</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1659" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="AEAAAA"/>
</w:tcPr>
<w:p wsp:rsidR="00DE1640" wsp:rsidRPr="00FA35C4" wsp:rsidRDefault="00DE1640">
<w:pPr>
<w:rPr>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
</w:pPr>
<w:r wsp:rsidRPr="00FA35C4">
<w:rPr>
<w:rFonts w:hint="fareast"/>
<wx:font wx:val="宋体"/>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
<w:t>约束</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1659" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="AEAAAA"/>
</w:tcPr>
<w:p wsp:rsidR="00DE1640" wsp:rsidRPr="00FA35C4" wsp:rsidRDefault="00DE1640">
<w:pPr>
<w:rPr>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
</w:pPr>
<w:r wsp:rsidRPr="00FA35C4">
<w:rPr>
<w:rFonts w:hint="fareast"/>
<wx:font wx:val="宋体"/>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
<w:t>允许空</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1660" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="AEAAAA"/>
</w:tcPr>
<w:p wsp:rsidR="00DE1640" wsp:rsidRPr="00FA35C4" wsp:rsidRDefault="00DE1640">
<w:pPr>
<w:rPr>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
</w:pPr>
<w:r wsp:rsidRPr="00FA35C4">
<w:rPr>
<w:rFonts w:hint="fareast"/>
<wx:font wx:val="宋体"/>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
<w:t>备注</w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
<#list table.columns as column>
<w:tr wsp:rsidR="00DE1640" wsp:rsidRPr="00FA35C4" wsp:rsidTr="00FA35C4">
<w:tc>
<w:tcPr>
<w:tcW w:w="1659" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p wsp:rsidR="00DE1640" wsp:rsidRPr="00FA35C4" wsp:rsidRDefault="00D01744">
<w:pPr>
<w:rPr>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:hint="fareast"/>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
<w:t>${column.columnName}</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1659" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p wsp:rsidR="00DE1640" wsp:rsidRPr="00FA35C4" wsp:rsidRDefault="00D01744">
<w:pPr>
<w:rPr>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
<w:t>${column.columnType}</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1659" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p wsp:rsidR="00DE1640" wsp:rsidRPr="00FA35C4" wsp:rsidRDefault="00D01744">
<w:pPr>
<w:rPr>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
<w:t>${column.columnKey}</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1659" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p wsp:rsidR="00DE1640" wsp:rsidRPr="00FA35C4" wsp:rsidRDefault="001C4911">
<w:pPr>
<w:rPr>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
<w:t>${column.isNullable}</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1660" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p wsp:rsidR="00DE1640" wsp:rsidRPr="00FA35C4" wsp:rsidRDefault="003F3E19">
<w:pPr>
<w:rPr>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
<w:t>${column.columnComment}</w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
</#list>
</w:tbl>
<w:p wsp:rsidR="00DE1640" wsp:rsidRDefault="00DE1640">
<w:pPr>
<w:rPr>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
</w:pPr>
</w:p>
<w:p wsp:rsidR="00913083" wsp:rsidRPr="00481323" wsp:rsidRDefault="00913083">
<w:pPr>
<w:rPr>
<w:sz w:val="18"/>
<w:sz-cs w:val="18"/>
</w:rPr>
</w:pPr>
</w:p>
<w:sectPr wsp:rsidR="00913083" wsp:rsidRPr="00481323" wsp:rsidSect="00BB620F">
<w:pgSz w:w="11906" w:h="16838"/>
<w:pgMar w:top="1440" w:right="1800" w:bottom="1440" w:left="1800" w:header="851" w:footer="992" w:gutter="0"/>
<w:cols w:space="425"/>
<w:docGrid w:type="lines" w:line-pitch="312"/>
</w:sectPr>
</#list>
</wx:sect>
</w:body>
关键部分到了,从数据库中获取所有的表信息并将数据填充到模板中生成doc文件。
package com.dwl.mindoc.service;
import com.dwl.mindoc.dao.BaseDao;
import com.dwl.mindoc.database.BaseFactory;
import com.dwl.mindoc.database.Database;
import com.dwl.mindoc.domain.TableVo;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;
import javax.annotation.PostConstruct;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @program: mindoc
* @description: generator
* @author: daiwenlong
* @create: 2018-10-13 13:00
**/
@Service
public class GenerateService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private BaseFactory factory;
@Autowired
private BaseDao dao;
@PostConstruct
public void genertator(){
try {
Database base = factory.getDataBase();
List<TableVo> tables = dao.getTables(base);
tables.forEach(table->{
table.setColumns(dao.getColumns(base,table.getTableName()));
logger.info("mindoc - TableName:{} TableComment:{} loading...",table.getTableName(),table.getTableComment());
});
makeDoc(tables);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 生成doc
* @param tables
* @return
* @throws IOException
* @throws TemplateException
*/
public void makeDoc(List<TableVo> tables){
logger.info("mindoc - makeDoc Satrting...");
// 第一步:创建一个Configuration对象。
Configuration configuration = new Configuration(Configuration.getVersion());
// 第二步:设置模板文件所在的路径。
try {
configuration.setDirectoryForTemplateLoading(ResourceUtils.getFile("classpath:"));
// 第三步:设置模板文件使用的字符集。
configuration.setDefaultEncoding("utf-8");
// 第四步:加载一个模板,创建一个模板对象。
Template template = configuration.getTemplate("doc.xml");
// 第五步:创建一个模板使用的数据集。
Map<String,Object> dataModel = new HashMap<>();
dataModel.put("tables",tables);
//生成文件放在项目根目录下
File outFile = new File(System.getProperty("user.dir")+"\\DatabaseDesign.doc");
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile)));
// 第六步:调用模板对象的process方法输出文件。
template.process(dataModel, out);
logger.info("mindoc - MakeDoc succeeded.");
logger.info("mindoc - Doc directory {}",outFile);
} catch (IOException |TemplateException e) {
logger.warn("mindoc - MakeDoc failed.");
}
}
}
查看控制台信息,文件已经生成。
我们去文件目录下查看文档。
是不是很方便,终于可以随心所欲的写Word了。除了能生成数据库设计文档,我们还可以生成其他有固定模式的Word文档,大家可以根据自己业务场景试一试。
上面只贴了一部分代码,详细代码可以到github上下载mindoc