大家好,我是TJ

一个励志推荐10000款开源项目与工具的程序员

TJ君做项目的时候最头疼什么?当然是写各种文档啦,尤其是在大公司做项目,各种规范文档不可少,虽然说一个成熟的项目管理过程中的确是要依靠各种文档来明确项目里程碑及具体的设计确认和需求分工,但是TJ君还是更喜欢把时间花在开发代码上。

尤其是有些文档的格式都差不多,那是不是我们程序猿可以发挥特长,用程序来生成输出指定的word文档,减少自己的手写时间呢?

当然是可以的!

今天TJ君就要给大家分享一款Word专用的模板引擎,Poi-tl(Poi-template-language)。这款引擎基于Apache Poi,可以根据用户输入的内容直接生成相应的word文档,很是方便。

Apache Poi是用Java编写的一款免费开源的跨平台的JavaAPI,该API可以通过Java程序对Office格式文档进行读写操作,可以说是现阶段Java库当中最好用的office处理库了,可能都不用加之一两个字。所以基于Apache Poi的Poi-tl可以让你在word文档的任何地方做任何你想做的事情。

举个例子,如果想生成一个名叫TJ君真棒.docx的文档,并且在文档里包含文本{{title}},只需要一句代码,这句代码也是整个引擎的核心所在:

//核心API采用了极简设计,只需要一行代码
XWPFTemplate.compile("TJ君真棒.docx").render(new HashMap<String, Object>(){{put("title", "Poi-tl 模板引擎");
}}).writeToFile("out_TJ君真棒.docx");

Poi-tl整体设计采用了Template + data-model = output模式.

Configure提供了模板配置功能,比如语法配置和插件配置:

/*** 插件化配置* * @author Sayi* @version 1.0.0*/
public class Configure {// defalut expressionprivate static final String DEFAULT_GRAMER_REGEX = "[\\w\\u4e00-\\u9fa5]+(\\.[\\w\\u4e00-\\u9fa5]+)*";// Highest priorityprivate Map<String, RenderPolicy> customPolicys = new HashMap<String, RenderPolicy>();// Low priorityprivate Map<Character, RenderPolicy> defaultPolicys = new HashMap<Character, RenderPolicy>();/*** 引用渲染策略*/private List<ReferenceRenderPolicy<?>> referencePolicies = new ArrayList<>();/*** 语法前缀*/private String gramerPrefix = "{{";/*** 语法后缀*/private String gramerSuffix = "}}";/*** 默认支持中文、字母、数字、下划线的正则*/private String grammerRegex = DEFAULT_GRAMER_REGEX;/*** 模板表达式模式,默认为POI_TL_MODE*/private ELMode elMode = ELMode.POI_TL_STANDARD_MODE;/*** 渲染数据校验不通过时的处理策略* <ul>* <li>DiscardHandler: 什么都不做</li>* <li>ClearHandler: 清空标签</li>* <li>AbortHandler: 抛出异常</li>* </ul>*/private ValidErrorHandler handler = new ClearHandler();private Configure() {plugin(GramerSymbol.TEXT, new TextRenderPolicy());plugin(GramerSymbol.IMAGE, new PictureRenderPolicy());plugin(GramerSymbol.TABLE, new MiniTableRenderPolicy());plugin(GramerSymbol.NUMBERIC, new NumbericRenderPolicy());plugin(GramerSymbol.DOCX_TEMPLATE, new DocxRenderPolicy());}/*** 创建默认配置* * @return*/public static Configure createDefault() {return newBuilder().build();}/*** 构建器* * @return*/public static ConfigureBuilder newBuilder() {return new ConfigureBuilder();}/*** 新增或变更语法插件* * @param c*            语法* @param policy*            策略*/public Configure plugin(char c, RenderPolicy policy) {defaultPolicys.put(Character.valueOf(c), policy);return this;}/*** 新增或变更语法插件* * @param symbol*            语法* @param policy*            策略* @return*/Configure plugin(GramerSymbol symbol, RenderPolicy policy) {defaultPolicys.put(symbol.getSymbol(), policy);return this;}/*** 自定义模板和策略* * @param tagName*            模板名称* @param policy*            策略*/public void customPolicy(String tagName, RenderPolicy policy) {customPolicys.put(tagName, policy);}/*** 新增引用渲染策略* * @param policy*/public void referencePolicy(ReferenceRenderPolicy<?> policy) {referencePolicies.add(policy);}/*** 获取标签策略* * @param tagName*            模板名称* @param sign*            语法*/// Query Operationspublic RenderPolicy getPolicy(String tagName, Character sign) {RenderPolicy policy = getCustomPolicy(tagName);return null == policy ? getDefaultPolicy(sign) : policy;}public List<ReferenceRenderPolicy<?>> getReferencePolicies() {return referencePolicies;}private RenderPolicy getCustomPolicy(String tagName) {return customPolicys.get(tagName);}private RenderPolicy getDefaultPolicy(Character sign) {return defaultPolicys.get(sign);}public Map<Character, RenderPolicy> getDefaultPolicys() {return defaultPolicys;}public Map<String, RenderPolicy> getCustomPolicys() {return customPolicys;}public Set<Character> getGramerChars() {return defaultPolicys.keySet();}public String getGramerPrefix() {return gramerPrefix;}public String getGramerSuffix() {return gramerSuffix;}public String getGrammerRegex() {return grammerRegex;}public ELMode getElMode() {return elMode;}public ValidErrorHandler getValidErrorHandler() {return handler;}public static class ConfigureBuilder {private boolean regexForAll;private Configure config;public ConfigureBuilder() {config = new Configure();}public ConfigureBuilder buildGramer(String prefix, String suffix) {config.gramerPrefix = prefix;config.gramerSuffix = suffix;return this;}public ConfigureBuilder buildGrammerRegex(String reg) {config.grammerRegex = reg;return this;}public ConfigureBuilder supportGrammerRegexForAll() {this.regexForAll = true;return this;}public ConfigureBuilder setElMode(ELMode mode) {config.elMode = mode;return this;}public ConfigureBuilder setValidErrorHandler(ValidErrorHandler handler) {config.handler = handler;return this;}public ConfigureBuilder addPlugin(char c, RenderPolicy policy) {config.plugin(c, policy);return this;}public ConfigureBuilder customPolicy(String tagName, RenderPolicy policy) {config.customPolicy(tagName, policy);return this;}public ConfigureBuilder referencePolicy(ReferenceRenderPolicy<?> policy) {config.referencePolicy(policy);return this;}public ConfigureBuilder bind(String tagName, RenderPolicy policy) {config.customPolicy(tagName, policy);return this;}public Configure build() {if (config.elMode == ELMode.SPEL_MODE) {regexForAll = true;}if (regexForAll) {config.grammerRegex = RegexUtils.createGeneral(config.gramerPrefix,config.gramerSuffix);}return config;}}
}

Visitor提供了模板解析功能:

/*** 模板解析器* * @author Sayi* @version 1.4.0*/
public class TemplateVisitor implements Visitor {private static Logger logger = LoggerFactory.getLogger(TemplateVisitor.class);private Configure config;private List<ElementTemplate> eleTemplates;private Pattern templatePattern;private Pattern gramerPattern;static final String FORMAT_TEMPLATE = "{0}{1}{2}{3}";static final String FORMAT_GRAMER = "({0})|({1})";public TemplateVisitor(Configure config) {this.config = config;initPattern();}@Overridepublic List<ElementTemplate> visitDocument(XWPFDocument doc) {if (null == doc) return null;this.eleTemplates = new ArrayList<ElementTemplate>();logger.info("Visit the document start...");visitParagraphs(doc.getParagraphs());visitTables(doc.getTables());visitHeaders(doc.getHeaderList());visitFooters(doc.getFooterList());logger.info("Visit the document end, resolve and create {} ElementTemplates.",this.eleTemplates.size());return eleTemplates;}void visitHeaders(List<XWPFHeader> headers) {if (null == headers) return;for (XWPFHeader header : headers) {visitParagraphs(header.getParagraphs());visitTables(header.getTables());}}void visitFooters(List<XWPFFooter> footers) {if (null == footers) return;for (XWPFFooter footer : footers) {visitParagraphs(footer.getParagraphs());visitTables(footer.getTables());}}void visitParagraphs(List<XWPFParagraph> paragraphs) {if (null == paragraphs) return;for (XWPFParagraph paragraph : paragraphs) {visitParagraph(paragraph);}}void visitTables(List<XWPFTable> tables) {if (null == tables) return;for (XWPFTable tb : tables) {visitTable(tb);}}void visitTable(XWPFTable table) {if (null == table) return;List<XWPFTableRow> rows = table.getRows();if (null == rows) return;for (XWPFTableRow row : rows) {List<XWPFTableCell> cells = row.getTableCells();if (null == cells) continue;for (XWPFTableCell cell : cells) {visitParagraphs(cell.getParagraphs());visitTables(cell.getTables());}}}void visitParagraph(XWPFParagraph paragraph) {if (null == paragraph) return;RunningRunParagraph runningRun = new RunningRunParagraph(paragraph, templatePattern);List<XWPFRun> refactorRun = runningRun.refactorRun();if (null == refactorRun) return;for (XWPFRun run : refactorRun) {visitRun(run);}}void visitRun(XWPFRun run) {String text = null;if (null == run || StringUtils.isBlank(text = run.getText(0))) return;ElementTemplate elementTemplate = parseTemplateFactory(text, run);if (null != elementTemplate) eleTemplates.add(elementTemplate);}private <T> ElementTemplate parseTemplateFactory(String text, T obj) {logger.debug("Resolve where text: {}, and create ElementTemplate", text);// temp ,future need to word analyzeif (templatePattern.matcher(text).matches()) {String tag = gramerPattern.matcher(text).replaceAll("").trim();if (obj.getClass() == XWPFRun.class) {return TemplateFactory.createRunTemplate(tag, config, (XWPFRun) obj);} else if (obj.getClass() == XWPFTableCell.class)// return CellTemplate.create(symbol, tagName, (XWPFTableCell)// obj);return null;}return null;}private void initPattern() {String signRegex = getGramarRegex(config);String prefixRegex = RegexUtils.escapeExprSpecialWord(config.getGramerPrefix());String suffixRegex = RegexUtils.escapeExprSpecialWord(config.getGramerSuffix());templatePattern = Pattern.compile(MessageFormat.format(FORMAT_TEMPLATE, prefixRegex,signRegex, config.getGrammerRegex(), suffixRegex));gramerPattern = Pattern.compile(MessageFormat.format(FORMAT_GRAMER, prefixRegex, suffixRegex));}private String getGramarRegex(Configure config) {List<Character> gramerChar = new ArrayList<Character>(config.getGramerChars());StringBuilder reg = new StringBuilder("(");for (int i = 0;; i++) {Character chara = gramerChar.get(i);String escapeExprSpecialWord = RegexUtils.escapeExprSpecialWord(chara.toString());if (i == gramerChar.size() - 1) {reg.append(escapeExprSpecialWord).append(")?");break;} else reg.append(escapeExprSpecialWord).append("|");}return reg.toString();}}

最后,RenderPolicy是渲染策略扩展点,Render模块提供了RenderDataCompute表达式计算扩展点,通过RenderPolicy对每个标签进行渲染。

当然,如果想将Poi-tl用的好的话,还是要花一点时间来研究其中具体模块的语法,好在Poi-tl提供详细的示例代码讲解,小伙伴们只要用心学一下,很快就能掌握的

到底能不能让小伙伴们减轻写文档的压力呢?记得用过之后来给TJ君反馈哦!想用的小伙伴,完整项目地址在这里:

点击下方卡片,关注公众号“TJ君

回复“生成word”,获取仓库地址

关注我,每天了解一个牛x、好用、有趣的东东

往期推荐

GitHub高赞,一款足以取代迅雷的开源下载工具

Copilot 爆裂更新,通过注释自动生成代码现已支持 IntelliJ IDEA、PyCharm

可能是你用过最好用的Redis客户端!

IDEA中文字符自动转换插件,再也不用担心程序因为中文字符报错了!

IDEA编码自动注释工具,让你的开发更有效率

十万伏特!让你的操作终端变成宝可梦!

用JAVA写的word模板自动生成引擎相关推荐

  1. python 用word模板自动生成报告

    不啰嗦,直接进入正题,先放上结果: 利用下面的模板自动生成报告篇: 注:后面会详细讲解如何生成模板. 如何生成模板: 新建一个 docx 文件. 2.代码部分 import tushare as ts ...

  2. Java中利用freemarker模板动态生成word含表格

    最近公司有导出word的需求,由于word的样式有的很复杂所以记录一下Java中利用freemarker模板动态生成word含表格,以防以后忘记. 1.word表格的模板 删掉无用的数据留下基础的样式 ...

  3. 使用java通过固定的excel模板自动生成数据库表的ddl建表语句

    有时候要建很多表或一个表有很多字段,一个个复制字段弄太麻烦了,为了提高点工作效率,写了个小工具通过固定的excel模板自动生成基础的ddl建表语句 maven依赖 <!--核心jar包--> ...

  4. java word模板poi生成文件_利用poi读取word模板文件生成新的word文档

    利用poi读取word模板文件生成新的word文档 利用poi读取word模板文件,并回填逻辑数据,生成并导出需要的word文档源码.解决模板读取异常问题,提供wordUtils工具类(各种功能实现) ...

  5. Java将对象信息写到word模板中(全网最简单版)

    Java将对象信息写到word模板中 一.首先进行依赖的导入 <!-- 证书模板写入信息 --><dependency><groupId>com.deepoove& ...

  6. 通过一个word模板来生成新的word并且填充内容

    关于用Java编写生成word文档,动态添加数据到word文档的一些心得,经过翻阅了无数的有用的和无用的资料以后,总算找到了一种靠谱的方法 1.概述 经过反反复复的查阅资料,总算找到了一个靠谱的生成w ...

  7. Java POI导出word文件及生成表格

    HWPF是处理 Microsoft Word 97(-2007) .doc文件格式,它还为较旧的Word 6和Word 95文件格式提供了有限的只读支持.包含在poi-scratchpad-XXX.j ...

  8. 根据Word表格自动生成SQL数据库脚本的VBScript代码

    这是几年前写的根据Word表格自动生成SQL数据库脚本的VBScript代码,最近修改了下(原来只支持单个Word表格)使其支持一个Word文档中的多个表格,生成的SQL文件名以Word文件名+.SQ ...

  9. Java实现根据Word模板填充表格数据(poi方式),以及doc和docx转PDF,最全最详细版本,解决外部引用jar在linux上报ClassNotFound的问题。

    Java实现根据Word模板填充表格数据(poi方式),以及doc和docx转PDF,最全最详细版本,解决外部引用jar在linux上报ClassNotFound的问题. 适用场景: 1.固定格式的W ...

最新文章

  1. mysql常用命令汇总
  2. 8086CPU的出栈(pop)和入栈(push) 都是以字为单位进行的
  3. 详解设计模式之工厂模式(简单工厂+工厂方法+抽象工厂)
  4. java 枚举可以循环吗_(转载)java 枚举 循环遍历以及一些简单常见的使用
  5. 《 自动化测试最佳实践:来自全球的经典自动化测试案例解析》一一1.3 建立自动化策略...
  6. kibana 查询_干货 | Elasticsearch、Kibana数据导出实战
  7. Redis之内存分析
  8. 麒麟990 5G获外媒好评:华为Mate30系列有望引领5G时代新体验
  9. 【Vue2.0】—Vue中的key有什么作用?(四)
  10. python 工程 ——文件、包、__init__及导入方法
  11. 事务(进程 ID )与另一个进程已被死锁在 lock 资源上,且该事务已被选作死锁牺牲品。请重新运行该事务...
  12. android百度地图获取定位信息吗,android使用百度地圖定位(獲取當前經緯度和地址信息)...
  13. OpenCvSharp DnnSuperres图像超分辨率Demo测试
  14. bus hound usb 调试
  15. 修改app的名字和图标
  16. 计算机中毒后开机变慢,电脑中毒后运行慢的解决方法
  17. 相机标定(笔记本摄像头和usb相机)
  18. 论文学习笔记:PoseFix: Model-agnostic General Human Pose Refinement Network
  19. 王菲给师父打电话拜年,受高人指点,她扶摇直上联手天王横扫歌坛
  20. 招商银行一网通H5接口调试和测试报告撰写注意事项

热门文章

  1. 使用 libevent 和 libev 提高网络应用性能
  2. SQL查询所有客人的第一次用餐时间
  3. sql 根据多个ID删除表中多行数据
  4. 学会用core dump调试程序错误(转)
  5. linux 密码文件 /etc/shadow md5,SHA256,SHA512 破解
  6. php 换行 \n \r\n br 简介
  7. linux bash shell for 循环使用简介
  8. umdh windbg分析内存泄露
  9. Android开发--多媒体应用开发(一)--MediaPlayer的使用介绍
  10. Java学习之do-while-if语句实操