自动化文档生成工具(亲测可运行)

本文介绍了一个用Java编写的自动化文档生成工具,通过读取开发清单文本自动生成格式规范的Word文档。该工具的主要特点包括:

  1. 采用Apache POI库处理Word文档,支持多级标题和段落自动生成
  2. 实现中文数字转换功能,将编号转换为"一、二、三"等样式
  3. 预设标准的文档结构(输入/流程/输出/财务/异常/源代码等章节)
  4. 通过Maven打包成可执行JAR,只需将清单文本与JAR同目录即可运行

使用该工具可将原本繁琐的手动文档编写工作自动化,显著提高开发文档的编写效率。

单位要写开发文档,文档大致结构是上面有一个表格,填入开发内容清单,比如是这样:

1新增用户
2删除用户
3查询用户

下面需要有对应的二级标题和三级标题,我就需要每次都去复制粘贴,改编号,很是麻烦。干脆用java写个脚本来处理吧。

核心思路是,把开发清单复制到txt文本,然后去读取,生成一个新的word,带上这些格式,再拷贝回去即可,省了不少时间。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com</groupId><artifactId>doc-server</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version></dependency></dependencies><build><plugins><!-- 其他插件 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><version>3.5.0</version><configuration><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs><archive><manifest><mainClass>main.WordGenerator</mainClass> <!-- 替换为你的主类 --></manifest></archive></configuration><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin></plugins></build></project>

WordGenerator.java

package main;import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;import java.io.*;
import java.math.BigInteger;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;public class WordGenerator {/*** 使用BufferedReader按行读取文件*/public static List<String> readLinesWithBufferedReader(String filePath) {List<String> lines = new ArrayList<>();try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), StandardCharsets.UTF_8))) {String line;while ((line = reader.readLine()) != null) {lines.add(line);}} catch (IOException e) {System.err.println("读取文件失败: " + e.getMessage());}return lines;}static class Transaction {private String num;private String content;public Transaction(String num, String content) {this.num = num;this.content = content;}public String getNum() {return num;}public String getContent() {return content;}@Overridepublic String toString() {return "Transaction{" +"num='" + num + '\'' +", content='" + content + '\'' +'}';}}public static String getPath(){String path = WordGenerator.class.getProtectionDomain().getCodeSource().getLocation().getPath();System.out.println("原始路径:" +  path);if(System.getProperty("os.name").contains("dows")){//path -> file:/D:/Haier/hlmcheckup-admin.jar!/BOOT-INF/lib/hlmcheckup-common-1.0.0.jar!///如果是windows系统,前面有可能有“file:”要替换掉。path = path.replace("file:", "");path = path.substring(1,path.length());System.out.println("原始路径:" +  path);}if(path.contains("jar")){//这里根据你jar包名称分割//D:/Haier/hlmcheckup-admin.jar!/BOOT-INF/lib/hlmcheckup-common-1.0.0.jar!/// -> D:/Haier/String[] split = path.split("doc-server-1.0-SNAPSHOT-jar-with-dependencies.jar");System.out.println("jar包路径:" +  split[0]);return split[0];}//"hlmcheckup-common/target/classes/" 为当前类路径 linux与macos需要替换掉return path.replace("hlmcheckup-common/target/classes/", "");}public static String getParentDirectory(String jarFilePath) {if (jarFilePath == null || jarFilePath.isEmpty()) {return null;}File jarFile = new File(jarFilePath);File parentDir = jarFile.getParentFile();if (parentDir != null && parentDir.exists() && parentDir.isDirectory()) {return parentDir.getAbsolutePath();}return null;}public static void main(String[] args) throws Exception {File jarFile = new File( getPath() + "\\1.txt" );System.out.println(jarFile.getAbsoluteFile());List<String> lines = readLinesWithBufferedReader(jarFile.getAbsolutePath());List<Transaction> transactionList = new ArrayList<>();System.out.println("读取的行数: " + lines.size());for (int i = 0; i <  lines.size(); i++) {transactionList.add(new Transaction(lines.get(i).split("\\t")[0],lines.get(i).split("\\t")[2]));}System.out.println(transactionList);// 创建新的Word文档try (XWPFDocument document = new XWPFDocument()) {ensureHeadingStylesExist(document);for (Transaction transaction: transactionList) {int index = 1;String chinese = NumberToChinese.toChinese(Long.parseLong(transaction.getNum()));// 创建一级标题createHeading(document, " 交易" + chinese + ":" + transaction.getContent(), 2);createHeading(document, " 输入" , 3 );createParagraph(document, " " + transaction.getContent() + " 输入参数" );createHeading(document, " 流程" , 3 );createParagraph(document, " 开始 -> " + transaction.getContent() + " -> 结束");createHeading(document, " 输出" , 3 );createParagraph(document, " " + transaction.getContent() + " 输出参数");createHeading(document, " 财务" , 3 );createParagraph(document, " 无");createHeading(document, " 异常" , 3 );createParagraph(document, " 无");createHeading(document,  " 源代码" , 3 );createParagraph(document, " 无");}// 保存文档try (FileOutputStream out = new FileOutputStream(new File("out.docx"))) {document.write(out);System.out.println("Word文档生成成功!");}} catch (IOException e) {e.printStackTrace();}}/*** 创建标题段落* @param document Word文档对象* @param text 标题文本* @param level 标题级别(1-9)*/private static void createHeading(XWPFDocument document, String text, int level) {XWPFParagraph paragraph = document.createParagraph();paragraph.setStyle("Heading" + level); // 设置标题样式XWPFRun run = paragraph.createRun();run.setText(text);run.setFontSize(16 - (level - 1) * 2); // 标题1:16pt, 标题2:14pt, 依此类推run.setBold(true);}/*** 创建正文段落* @param document Word文档对象* @param text 段落文本*/private static void createParagraph(XWPFDocument document, String text) {XWPFParagraph paragraph = document.createParagraph();XWPFRun run = paragraph.createRun();run.setText(text);run.setFontSize(12); // 正文默认12pt}// 确保文档包含必要的标题样式private static void ensureHeadingStylesExist(XWPFDocument document) {try {XWPFStyles styles = document.getStyles();if (styles == null) {styles = document.createStyles();}// 检查Heading 1样式是否存在,不存在则创建if (!hasStyle(styles, "Heading1")) {createHeadingStyle(document, "Heading1", "Heading 1", 1, 24);}if (!hasStyle(styles, "Heading2")) {createHeadingStyle(document, "Heading2", "Heading 2", 2, 18);}if (!hasStyle(styles, "Heading3")) {createHeadingStyle(document, "Heading3", "Heading 3", 3, 14);}} catch (Exception e) {System.err.println("创建标题样式失败: " + e.getMessage());}}// 检查样式是否存在private static boolean hasStyle(XWPFStyles styles, String styleId) {return styles.getStyle(styleId) != null;}// 创建标题样式(兼容所有POI版本)private static void createHeadingStyle(XWPFDocument document, String styleId, String styleName, int level, int fontSize) {XWPFStyles styles = document.getStyles();// 创建新样式CTStyle ctStyle = CTStyle.Factory.newInstance();ctStyle.setStyleId(styleId);// 设置样式名称CTString name = CTString.Factory.newInstance();name.setVal(styleName);ctStyle.setName(name);// 设置样式类型为段落ctStyle.setType(STStyleType.PARAGRAPH);// 设置为标题样式CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance();indentNumber.setVal(BigInteger.valueOf(level));ctStyle.setUiPriority(indentNumber);// 设置基于Normal样式ctStyle.setBasedOn(CTString.Factory.newInstance());ctStyle.getBasedOn().setVal("Normal");// 设置段落属性CTPPr ppr = ctStyle.addNewPPr();ppr.addNewSpacing().setAfter(BigInteger.valueOf(100)); // 段后间距// 设置字体和大小(兼容旧版POI)CTRPr rpr = ctStyle.addNewRPr();CTFonts fonts = rpr.addNewRFonts();fonts.setAscii("宋体");fonts.setEastAsia("宋体");rpr.addNewSz().setVal(BigInteger.valueOf(fontSize * 2)); // 字体大小(Twips单位)rpr.addNewB().setVal(STOnOff.TRUE); // 加粗// 添加样式到文档XWPFStyle newStyle = new XWPFStyle(ctStyle);styles.addStyle(newStyle);}
}

NumberToChinese.java 工具类

package main;import java.math.BigDecimal;public class NumberToChinese {// 中文数字字符映射private static final String[] CN_NUMBERS = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"};private static final String[] CN_INTEGER_UNITS = {"", "十", "百", "千", "万", "十", "百", "千", "亿", "十", "百", "千", "兆"};private static final String[] CN_DECIMAL_UNITS = {"角", "分", "厘", "毫"};// 中文金额单位映射(用于财务场景)private static final String[] CN_FINANCIAL_UNITS = {"", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟", "兆"};private static final String CN_ZERO = "零";private static final String CN_INTEGER = "整";private static final String CN_NEGATIVE = "负";/*** 将数字转换为中文大写(普通模式)* 例如:1234 → 一千二百三十四*/public static String toChinese(long number) {if (number == 0) {return CN_NUMBERS[0];}StringBuilder result = new StringBuilder();boolean isNegative = number < 0;if (isNegative) {number = -number;result.append(CN_NEGATIVE);}String numStr = String.valueOf(number);int length = numStr.length();for (int i = 0; i < length; i++) {int digit = numStr.charAt(i) - '0';int unitIndex = length - i - 1;// 处理零的情况if (digit == 0) {// 避免多个连续的零if (i > 0 && numStr.charAt(i - 1) != '0') {result.append(CN_NUMBERS[0]);}// 处理万亿等单位if (unitIndex % 4 == 0 && i < length - 1 && numStr.charAt(i + 1) != '0') {result.append(CN_INTEGER_UNITS[unitIndex]);}continue;}result.append(CN_NUMBERS[digit]);result.append(CN_INTEGER_UNITS[unitIndex]);}return result.toString();}/*** 将数字转换为中文大写(财务模式)* 例如:1234.56 → 壹仟贰佰叁拾肆元伍角陆分*/public static String toFinancialChinese(double number) {// 使用BigDecimal避免浮点数精度问题BigDecimal bd = new BigDecimal(String.valueOf(number));boolean isNegative = bd.signum() < 0;if (isNegative) {bd = bd.negate();}// 分离整数和小数部分BigDecimal integerPart = bd.setScale(0, BigDecimal.ROUND_DOWN);BigDecimal decimalPart = bd.subtract(integerPart).multiply(new BigDecimal(100)); // 转换为分StringBuilder result = new StringBuilder();if (isNegative) {result.append(CN_NEGATIVE);}// 处理整数部分String integerStr = integerPart.toPlainString();if (integerStr.equals("0")) {result.append(CN_NUMBERS[0]);} else {int length = integerStr.length();for (int i = 0; i < length; i++) {int digit = integerStr.charAt(i) - '0';int unitIndex = length - i - 1;// 处理零的情况if (digit == 0) {if (i > 0 && integerStr.charAt(i - 1) != '0') {result.append(CN_ZERO);}if (unitIndex % 4 == 0 && i < length - 1 && integerStr.charAt(i + 1) != '0') {result.append(CN_FINANCIAL_UNITS[unitIndex]);}continue;}result.append(CN_NUMBERS[digit]);result.append(CN_FINANCIAL_UNITS[unitIndex]);}}result.append("元");// 处理小数部分int decimalInt = decimalPart.intValue();if (decimalInt == 0) {result.append(CN_INTEGER);} else {int jiao = decimalInt / 10;int fen = decimalInt % 10;if (jiao > 0) {result.append(CN_NUMBERS[jiao]).append(CN_DECIMAL_UNITS[0]);} else if (decimalInt > 9) {result.append(CN_ZERO);}if (fen > 0) {result.append(CN_NUMBERS[fen]).append(CN_DECIMAL_UNITS[1]);}}return result.toString();}// 测试示例public static void main(String[] args) {System.out.println("普通模式:");System.out.println("1234 → " + toChinese(1234));System.out.println("10001 → " + toChinese(10001));System.out.println("10030 → " + toChinese(10030));System.out.println("100000001 → " + toChinese(100000001));System.out.println("-123 → " + toChinese(-123));System.out.println("\n财务模式:");System.out.println("1234.56 → " + toFinancialChinese(1234.56));System.out.println("1000.01 → " + toFinancialChinese(1000.01));System.out.println("0.50 → " + toFinancialChinese(0.50));System.out.println("1000000 → " + toFinancialChinese(1000000));System.out.println("-123.45 → " + toFinancialChinese(-123.45));}
}

用maven打包后,将1.txt和jar放在同一个目录,双击jar,就会生成目标word文件。

1.txt

1    无    新增用户
2    无    删除用户
3    无    查询用户

生成out

目录大纲也是正常的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/84270.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/84270.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

湖北理元理律师事务所债务优化模型:法律与生活的平衡之道

在债务重组领域&#xff0c;专业机构需同时解决两个矛盾&#xff1a;法律合规性与债务人可持续生存能力。湖北理元理律师事务所通过“三维干预模型”&#xff0c;在武汉某餐饮连锁企业债务危机中验证了该方案的有效性。 一、法律底层设计&#xff1a;还款方案的合法性审查 以该…

Web3-代币ERC20/ERC721以及合约安全溢出和下溢的研究

Web3-代币ERC20/ERC721以及合约安全溢出和下溢的研究 以太坊上的代币 如果你对以太坊的世界有一些了解&#xff0c;你很可能听人们聊过代币— ERC20代币 一个 代币 在以太坊基本上就是一个遵循一些共同规则的智能合约——即它实现了所有其他代币合约共享的一组标准函数&…

论文笔记 <交通灯><多智能体>MetaLight:基于价值的元强化学习用于交通信号控制

今天看的论文是这篇MetaLight:基于价值的元强化学习用于交通信号控制 里面提到的创新点就是MetaLight框架&#xff1a;他目标是让交通信号控制智能体&#xff08;Agent&#xff09;在新路口&#xff08;即使结构或流量模式不同&#xff09;上能​​快速学习​​&#xff08;Few…

华为OD-2024年E卷-寻找符合要求的最长子串[200分] -- python

问题描述&#xff1a; 给定一个字符串s&#xff0c;找出这样一个子串: 1)该子串中的任意一个字符最多出现2次; 2)该子串不包含指定某个字符; 请你找出满足该条件的最长子串的长度。 输入描述 第一行为要求不包含的指定字符&#xff0c;为单个字符&#xff0c;取值范围[0-9a-zA…

CppCon 2016 学习:What C++ Programmers Need to Know about Header <random>

随机数生成的历史背景 Middle-Square 方法&#xff08;中位平方法&#xff09;&#xff1a; 已知最早的随机算法之一或由修道士 Brother Edvin 在 1245 年发明由 John von Neumann 在 1949 年重新发现缺点明显&#xff0c;但执行速度快 Monte Carlo 方法&#xff1a; 起初是…

Origin:误差棒点线图绘制

1.首先将你的数据复制到表格 2.选中B(y)列数据&#xff0c;依次点击图示选项 3.选中图中红框数据&#xff0c;点击绘制点线图即可 4.结果展示

Spring 源码学习 1:ApplicationContext

Spring 源码学习 1&#xff1a;ApplicationContext Bean 定义和 Bean 实例 AnnotationConfigApplicationContext 首先&#xff0c;创建一个最简单的 Spring Boot 应用。 在入口类中接收SpringApplication.run的返回值&#xff1a; SpringBootApplication public class Dem…

CppCon 2017 学习:Design Patterns for Low-Level Real-Time Rendering

这段内容讲的是离散显卡&#xff08;Discrete GPU&#xff09;中的内存管理模型&#xff0c;重点是CPU和GPU各自独立管理自己的物理内存&#xff0c;以及它们如何通过虚拟内存和DMA引擎实现高效通信。以下是详细的理解和梳理&#xff1a; 1. 基本概念 CPU 和 GPU 是两个独立的…

【单调队列】-----【原理+模版】

单调队列 一、什么是单调队列&#xff1f; 单调队列是一种在滑动窗口或区间查询中维护候选元素单调性的数据结构&#xff0c;通常用于解决“滑动窗口最大值/最小值”等问题。 核心思想是&#xff1a;利用双端队列&#xff08;deque&#xff09;维护当前窗口内或候选范围内元素…

CSS语法中的选择器与属性详解

CSS:层叠样式表&#xff0c;Cascading Style Sheets 层叠样式表 内容和样式分离解耦&#xff0c;便于修改样式。 特殊说明&#xff1a; 最后一条声明可以没有分号&#xff0c;但是为了以后修改方便&#xff0c;一般也加上分号为了使用样式更加容易阅读&#xff0c;可以将每条代…

模拟设计的软件工程项目

考核题目 论文论述题&#xff1a;结合你 参与开发、调研或模拟设计的软件工程项目 &#xff0c;撰写一篇论文 完成以下任务&#xff0c;论文题目为《面向微服务架构的软件系统设计与建模分析》&#xff0c;总分&#xff1a; 100 分。 1. 考核内容&#xff1a; 一、系统论述…

个人理解redis中IO多路复用整个网络处理流

文章目录 1.redis网络处理流2.理解通知机制 1.redis网络处理流 10个客户端通过TCP与Redis建立socket连接&#xff0c;发送GET name指令到服务器端。服务器端的网卡接收数据&#xff0c;数据进入内核态的网络协议栈。Redis通过IO多路复用机制中的epoll向内核注册监听这些socket的…

【郑州轻工业大学|数据库】数据库课设-酒店管理系统

该数据课设是一个基于酒店管理系统的数据库设计 建库语句 create database hotel_room default charset utf8 collate utf8_general_ci;建表语句 use hotel_room;-- 房型表 create table room_type( id bigint primary key auto_increment comment 房型id, name varchar(50)…

TCP 三次握手与四次挥手详解

前言 在当今互联网时代&#xff0c;前端开发的工作范畴早已超越了简单的页面布局和交互设计。随着前端应用复杂度的不断提高&#xff0c;对网络性能的优化已成为前端工程师不可忽视的重要职责。而要真正理解并优化网络性能&#xff0c;就需要探究支撑整个互联网的基础协议——…

RTD2735TD/RTD2738 (HDMI,DP转EDP 高分辨率高刷新率显示器驱动芯片)

一、芯片概述 RTD2738是瑞昱半导体&#xff08;Realtek&#xff09;推出的一款高性能显示驱动芯片&#xff0c;专为高端显示器、便携屏、专业显示设备及多屏拼接系统设计。其核心优势在于支持4K分辨率下240Hz高刷新率及8K30Hz显示&#xff0c;通过集成DisplayPort 1.4a与HDMI …

C++实现手写strlen函数

要实现求字符串长度的函数&#xff0c;核心思路是通过指针或索引遍历字符串&#xff0c;直到遇到字符串结束标志 \0 。以下是两种常见的实现方式&#xff1a; 指针遍历版本 #include <iostream> using namespace std; // 指针方式实现strlen size_t myStrlen(const cha…

NVPL 函数库介绍和使用

文章目录 NVPL 函数库介绍和使用什么是 NVPLNVPL 的主要组件NVPL 的优势安装 NVPL基本使用示例示例1&#xff1a;使用 NVPL RAND 生成随机数示例2&#xff1a;使用 NVPL FFT 进行快速傅里叶变换 编译 NVPL 程序性能优化建议总结 NVPL 函数库介绍和使用 什么是 NVPL NVPL (NVI…

HTTP相关内容补充

目录 一、URI 和 URL 二、使用 Cookie 的状态管理 三、返回结果的 HTTP状态码 一、URI 和 URL URI &#xff1a;统一资源标识符 URL&#xff1a;统一资源定位符 URI 格式 登录信息&#xff08;认证&#xff09;指定用户名和密码作为从服务器端获取资源时必要的登录信息&a…

MySQL: Invalid use of group function

https://stackoverflow.com/questions/2330840/mysql-invalid-use-of-group-function 出错SQL: 错误原因&#xff1a; 1. 不能在 WHERE 子句中使用聚合&#xff08;或分组&#xff09;函数 2. HAVING 只能筛选分组后的聚合结果或分组字段 # Write your MySQL query statem…

C#财政票查验接口集成-医疗发票查验-非税收入票据查验接口

财政票据是企事业单位、医疗机构、金融机构等组织的重要报销凭证&#xff0c;其真实性、完整性和合规性日益受到重视。现如今&#xff0c;为有效防范虚假票据报销、入账、资金流失等问题的发生&#xff0c;财政票据查验接口&#xff0c;结合财政票据识别接口&#xff0c;旨在为…