这篇文章给大家介绍java 通过POI技术生成word ,这种实现方式项目中也很常用,比如生成常用表格,报表等。废话少说,下面就给大家详细介绍实现原理!
A、word文档正文段落概述:
一个word文档包含多个段落,一个段落包含多个Runs,一个Runs包含多个Run,Run是文档的最小单位
获取所有段落:List<XWPFParagraph> paragraphs = word.getParagraphs();
获取一个段落中的所有Runs:List<XWPFRun> xwpfRuns = xwpfParagraph.getRuns();
获取一个Runs中的一个Run:XWPFRun run = xwpfRuns.get(index);
B、word文档正文表格概述:
一个文档可包含多个表格,每个表格可以包含多行,每行可以包含多列(格),每一格的内容相当于一个完整的文档
获取所有表格:List<XWPFTable> xwpfTables = doc.getTables();
获取一个表格中的所有行:List<XWPFTableRow> xwpfTableRows = xwpfTable.getRows();
获取一行中的所有列:List<XWPFTableCell> xwpfTableCells = xwpfTableRow.getTableCells();
获取一格里的内容:List<XWPFParagraph> paragraphs = xwpfTableCell.getParagraphs();
A,B介绍有利于大家理解POI实现原理,所需jar包如图:这几个jar包足够

一、首先、该word模板是直接用word文档做模板,如下图:模板里面的参数大家可以随意定义,可以用${name},也可不用,直接 name

二、咱们就利用这个模板做测试,生成文档和文档里面的表格,测试成功直接可以使用,直接上代码:如下
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
/**
* 通过word模板生成新的word工具类
*
*/
public class BokeWordUtils {
/**
* 根据模板生成新word文档
* 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
* @param inputUrl 模板存放地址
* @param outPutUrl 新文档存放地址
* @param textMap 需要替换的信息集合
* @param tableList 需要插入的表格信息集合
*/
public static boolean changWord(String inputUrl, String outputUrl,
Map<String, String> textMap, List<String[]> tableList) {
//模板转换默认成功
boolean changeFlag = true;
try {
//获取docx解析对象
// Resource resource = new ClassPathResource(inputUrl);//放到代码的根目录下面, "templates/report.docx";模板
// InputStream inputStream = resource.getInputStream();
// XWPFDocument document = new XWPFDocument(inputStream);
//获取docx解析对象
XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));//放到服务器的目录下
//解析替换文本段落对象
BokeWordUtils.changeText(document, textMap);
//解析替换表格对象
BokeWordUtils.changeTable(document, textMap, tableList);
//生成新的word
Files.createDirectories(Paths.get(outputUrl).getParent());//如果没有,需要先创建,有了就不需要再创建了
File file = new File(outputUrl);
FileOutputStream stream = new FileOutputStream(file);
document.write(stream);
stream.close();
System.out.println("成功生成!");
} catch (IOException e) {
e.printStackTrace();
changeFlag = false;
}
return changeFlag;
}
/**
* 替换段落文本
* @param document docx解析对象
* @param textMap 需要替换的信息集合
*/
public static void changeText(XWPFDocument document, Map<String, String> textMap){
//获取段落集合
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
//判断此段落时候需要进行替换
String text = paragraph.getText();
if(checkText(text)){
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//替换模板原来位置
// run.setText(changeValue(run.toString(), textMap),0);
String textValue = changeValue(run.toString(), textMap);
run.setText(textValue,0);
}
}
}
}
/**
* 替换表格对象方法
* @param document docx解析对象
* @param textMap 需要替换的信息集合
* @param tableList 需要插入的表格信息集合
*/
public static void changeTable(XWPFDocument document, Map<String, String> textMap,
List<String[]> tableList){
//获取表格对象集合
List<XWPFTable> tables = document.getTables();
for (int i = 0; i < tables.size(); i++) {
//只处理行数大于等于2的表格,且不循环表头
XWPFTable table = tables.get(i);
if(table.getRows().size()>1){
//判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
if(checkText(table.getText())){
List<XWPFTableRow> rows = table.getRows();
//遍历表格,并替换模板
eachTable(rows, textMap);
}else{
// System.out.println("插入"+table.getText());
insertTable(table, tableList);
}
}
}
}
/**
* 遍历表格
* @param rows 表格行对象
* @param textMap 需要替换的信息集合
*/
public static void eachTable(List<XWPFTableRow> rows ,Map<String, String> textMap){
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
//判断单元格是否需要替换
if(checkText(cell.getText())){
List<XWPFParagraph> paragraphs = cell.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
run.setText(changeValue(run.toString(), textMap),0);
}
}
}
}
}
}
/**
* 为表格插入数据,行数不够添加新行
* @param table 需要插入数据的表格
* @param tableList 插入数据集合
*/
public static void insertTable(XWPFTable table, List<String[]> tableList){
//创建行,根据需要插入的数据添加新行,不处理表头
for(int i = 1; i < tableList.size(); i++){
XWPFTableRow row =table.createRow();
}
//遍历表格插入数据
List<XWPFTableRow> rows = table.getRows();
for(int i = 1; i < rows.size(); i++){
XWPFTableRow newRow = table.getRow(i);
List<XWPFTableCell> cells = newRow.getTableCells();
for(int j = 0; j < cells.size(); j++){
XWPFTableCell cell = cells.get(j);
cell.setText(tableList.get(i-1)[j]);
}
}
}
/**
* 判断文本中时候包含$
* @param text 文本
* @return 包含返回true,不包含返回false
*/
public static boolean checkText(String text){
boolean check = false;
if(text.indexOf("$")!= -1){
check = true;
}
return check;
}
/**
* 匹配传入信息集合与模板
* @param value 模板需要替换的区域
* @param textMap 传入信息集合
* @return 模板需要替换区域信息集合对应值
*/
public static String changeValue(String value, Map<String, String> textMap){
Set<Entry<String, String>> textSets = textMap.entrySet();
for (Entry<String, String> textSet : textSets) {
//匹配模板与替换值 格式${key}
String key = "${"+textSet.getKey()+"}";
if(value.indexOf(key)!= -1){
// value = textSet.getValue();//全部参数替换
value = value.replace(key, textSet.getValue());//仅替换参数
}
}
//模板未匹配到区域替换为空
if(checkText(value)){
value = "";
}
return value;
}
public static void main(String[] args) {
//模板文件地址
String inputUrl = "F://testWord/test0.docx";
//新生产的模板文件
String outputUrl = "F://testWord/testBoke.docx";
Map<String, String> testMap = new HashMap<String, String>();
testMap.put("name", "小明");
testMap.put("sex", "男");
testMap.put("nling", "18");
testMap.put("address", "北京市");
testMap.put("neirong", "好的内容");
testMap.put("address", "软件园");
testMap.put("xuehao", "88888888");
List<String[]> testList = new ArrayList<String[]>();
testList.add(new String[]{"1","1mm","1开开","1uu"});
testList.add(new String[]{"2","2密码","2B","基金C"});
testList.add(new String[]{"3","3看看","3B","基看C"});
testList.add(new String[]{"4","4累了","4B","4谁说的"});
BokeWordUtils.changWord(inputUrl, outputUrl, testMap, testList);
}
}
1)组合每一行的数组
private List<String[]> convertToTestList( List<UserDTO> userList) {
List<String[]> testList = new ArrayList<>();
int i =1;
for (UserDTO user : userList) {
BigDecimal wat = user.getWat();
if(wat == null){
wat = new BigDecimal("0");
}
//String s = DateUtil.formatTime(user.getTm());
i++;
testList.add(new String[]{ //为每个对象生成一行数据
i+"",
user.getArea(),
user.getLocation(),
user.getTime(),
wat.toString(),
user.getCircuit(),
user.getAge(),
user.getName()
});
}
return testList;
}
2) pom.xml引用的jar
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
<version>3.0.2</version>
</dependency>
<!-- OOXML Schema -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.2</version>
</dependency>
<!-- 压缩库支持 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.20</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
<exclusions>
<!-- 排除旧版xmlbeans -->
<exclusion>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
poi-ooxml-schemas 没有开发更高版本,因此暂时都有4.*版本。
三、次代码是我在网上查询出来的,经过修改优化,成功使用。改模板代码参数设置为${name},类似EL表达式。同时这种方式能很好地避免XWPFParagraph.getRuns分段混乱问题(分段混乱原因:是${name}是手打上去的,如果先在记事本输入,再复制粘贴进docx则不会出现分段问题)。代码非常详细,大家有不明白大地方及时留言!!!
四、下篇文章给大家介绍word文档上有图片生成的问题,敬请期待!!!

本文详细介绍了如何使用Java的POI库来生成Word文档,包括段落、Runs和表格的操作,并提供了相关代码示例,帮助理解实现原理。文章还提及了模板制作注意事项及解决分段混乱问题的方法,最后预告了关于Word文档图片生成的内容。
&spm=1001.2101.3001.5002&articleId=86645510&d=1&t=3&u=00f8c6ca4b484416b7d200f6ecb6b83c)
5615

被折叠的 条评论
为什么被折叠?



