之前用XWPFDocument生成的docx在转pdf的时候总是会报java.lang.IllegalStateException: Expecting one Styles document part, but found 0。
转出来的pdf总是会损坏,给我气够呛,网上找了办法使用doc.createStyles();
然后又给我报什么文件提前结束?或者SAXParseException; Premature end of file.
一直以为是样式的问题,最后试验发现,手动创建的docx文档是可以完美转换成pdf的,我就突然有一种想法,能不能用手动创建docx的模板进行操作呢?比如说我替换掉里面的内容再导出,其实就跟我自己创建的docx没有什么区别呢?说干就干,接下来就是正文了。
该方法不限制页数,带图片的应该也可以,大家可以试试看。

创建docx

1、先自己手动创建一个docx模板,内容是什么不重要。
在这里插入图片描述
2、其次读取该模板并删除模板里面的内容,所以里面是什么内容并不重要。

File file = new File("E:/模板.docx");
XWPFDocument doc = new XWPFDocument(new FileInputStream(file));
XWPFParagraph paragraph = doc.getLastParagraph();
paragraph.removeRun(0);

3、写自己需要的内容在word里。

XWPFParagraph paragraph= doc.createParagraph(); // 新建一个标题段落对象(就是一段文字)
paragraph.setVerticalAlignment(TextAlignment.CENTER);
XWPFRun titleFun = paragraph.createRun(); // 创建文本对象
titleFun.setText(titleText); //设置标题的名字
fun.setTextPosition(20); // 设置两行之间的行间距
fun.setBold(isBold); // 加粗
fun.setColor("000000");// 设置颜色
fun.setFontSize(fontSize); // 字体大小
fun.setFontFamily("宋体");//设置字体

4、导出pdf。

OutputStream os = new FileOutputStream(new File("E:/转换结果.pdf"));
PdfOptions options = PdfOptions.create();
PdfConverter.getInstance().convert(doc, os, options);
doc.write(os);
os.flush();
os.close();

导出表格的时候遇到的问题

1、第一个问题

Caused by: java.lang.NullPointerException
	at fr.opensagres.poi.xwpf.converter.core.utils.XWPFTableUtil.getGridColList(XWPFTableUtil.java:184)
	at fr.opensagres.poi.xwpf.converter.core.utils.XWPFTableUtil.computeColWidths(XWPFTableUtil.java:117)
	at fr.opensagres.poi.xwpf.converter.core.XWPFDocumentVisitor.visitTable(XWPFDocumentVisitor.java:970)
	at fr.opensagres.poi.xwpf.converter.core.XWPFDocumentVisitor.visitBodyElements(XWPFDocumentVisitor.java:267)
	at fr.opensagres.poi.xwpf.converter.core.XWPFDocumentVisitor.start(XWPFDocumentVisitor.java:215)
	at fr.opensagres.poi.xwpf.converter.pdf.PdfConverter.doConvert(PdfConverter.java:57)
	... 4 more

跟着断点知道是grid为null,所以取不到值。
在这里插入图片描述
所以在创建表格的时候加上:

CTTblGrid grid = table.getCTTbl().getTblGrid();
if (grid == null) {
	table.getCTTbl().addNewTblGrid();

2、紧接着出现第二个问题

Caused by: java.lang.NullPointerException at fr.opensagres.poi.xwpf.converter.core.utils.XWPFTableUtil.getWidth(XWPFTableUtil.java:274) at fr.opensagres.poi.xwpf.converter.core.utils.XWPFTableUtil.computeColWidths(XWPFTableUtil.java:285) at fr.opensagres.poi.xwpf.converter.core.utils.XWPFTableUtil.computeColWidths(XWPFTableUtil.java:128) at fr.opensagres.poi.xwpf.converter.core.XWPFDocumentVisitor.visitTable(XWPFDocumentVisitor.java:970) at fr.opensagres.poi.xwpf.converter.core.XWPFDocumentVisitor.visitBodyElements(XWPFDocumentVisitor.java:267) at fr.opensagres.poi.xwpf.converter.core.XWPFDocumentVisitor.start(XWPFDocumentVisitor.java:215) at fr.opensagres.poi.xwpf.converter.pdf.PdfConverter.doConvert(PdfConverter.java:57) ... 4 more

跟着断点知道TcPr是null,所以取值的时候就会报null。
在这里插入图片描述
所以在创建表格样式的时候遍历一下列,创建出TcPr,顺便创建TcTw,因为如果不创建的话,还是会报错。

for (XWPFTableRow row : table.getRows()) {
    for(XWPFTableCell cell : row.getTableCells()) {
        CTTblWidth ctTblWidth = cell.getCTTc().addNewTcPr().addNewTcW();
        ctTblWidth.setW(new BigInteger(width));

3、本以为这样就好了,结果又报错了。

Caused by: java.lang.NullPointerException
	at fr.opensagres.poi.xwpf.converter.core.utils.XWPFTableUtil.getTableWidth(XWPFTableUtil.java:347)
	at fr.opensagres.poi.xwpf.converter.core.utils.XWPFTableUtil.getTableWidth(XWPFTableUtil.java:331)
	at fr.opensagres.poi.xwpf.converter.core.utils.XWPFTableUtil.computeColWidths(XWPFTableUtil.java:290)
	at fr.opensagres.poi.xwpf.converter.core.utils.XWPFTableUtil.computeColWidths(XWPFTableUtil.java:128)
	at fr.opensagres.poi.xwpf.converter.core.XWPFDocumentVisitor.visitTable(XWPFDocumentVisitor.java:970)
	at fr.opensagres.poi.xwpf.converter.core.XWPFDocumentVisitor.visitBodyElements(XWPFDocumentVisitor.java:267)
	at fr.opensagres.poi.xwpf.converter.core.XWPFDocumentVisitor.start(XWPFDocumentVisitor.java:215)
	at fr.opensagres.poi.xwpf.converter.pdf.PdfConverter.doConvert(PdfConverter.java:57)
	... 4 more

再打断点看到是Type为空。
在这里插入图片描述
在上一行代码的setW()下增加一行

ctTblWidth.setType(STTblWidth.DXA);

运行结果完成,虽然还会报一个OpenXML4JRuntimeException 但是不影响结果就不管了。。。累了。
在这里插入图片描述

完整的代码

1、Maven依赖(里面自带poi-4.0.1)

<dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>fr.opensagres.poi.xwpf.converter.pdf-gae</artifactId>
    <version>2.0.2</version>
</dependency>

2、WordOutputUtil 工具类

import org.apache.poi.xwpf.usermodel.*; import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; import java.math.BigInteger; import java.util.List; public class WordOutputUtil { public static void setBigTitle(XWPFDocument doc, String bigTitle, String authorName) { XWPFParagraph bigTitleParagraph = doc.createParagraph(); // 新建一个标题段落对象(就是一段文字) bigTitleParagraph.setAlignment(ParagraphAlignment.CENTER);// 样式居中 XWPFRun titleFun = bigTitleParagraph.createRun(); // 创建文本对象 titleFun.setText(bigTitle); //设置标题的名字 setBigTitleFontStyle(titleFun); titleFun.addBreak(); // 换行 titleFun = bigTitleParagraph.createRun(); // 创建文本对象 titleFun.setText(authorName); //设置标题的名字 setBigTitleTextFontStyle(titleFun); public static void setTitleText(XWPFParagraph paragraph, String titleText) { XWPFRun titleFun = paragraph.createRun(); // 创建文本对象 titleFun.setText(titleText); //设置标题的名字 setTitleFontStyle(titleFun); public static void setTableTitle(XWPFDocument doc, String tableTitleName) { XWPFParagraph bigTitleParagraph = doc.createParagraph(); // 新建一个标题段落对象(就是一段文字) bigTitleParagraph.setAlignment(ParagraphAlignment.CENTER);// 样式居中 XWPFRun titleFun = bigTitleParagraph.createRun(); // 创建文本对象 titleFun.addBreak(); titleFun.setText(tableTitleName); //设置标题的名字 setTableTitleFontStyle(titleFun); public static void setGroupTitle(XWPFParagraph paragraph, String tableTitleName) { XWPFRun titleFun = paragraph.createRun(); // 创建文本对象 titleFun.addBreak(); titleFun.addTab(); titleFun.setText(tableTitleName); //设置标题的名字 setTitleFontStyle(titleFun); public static void setText(XWPFParagraph paragraph, String text) { XWPFRun textFun = paragraph.createRun(); // 创建文本对象 textFun.addBreak(); textFun.addTab(); textFun.setText(text); //设置标题的名字 setTextFontStyle(textFun); public static XWPFTable createTable(XWPFDocument doc, int rows, int cols) { XWPFTable table = doc.createTable(rows, cols); // 校验一下grid是否为空,如果为空就创建。转pdf的时候如果为空会报空指针 CTTblGrid grid = table.getCTTbl().getTblGrid(); if (grid == null) { table.getCTTbl().addNewTblGrid(); setTableWidthAndHAlign(table, "8288", STJc.CENTER); return table; * @Description: 设置表格总宽度与水平对齐方式 public static void setTableWidthAndHAlign(XWPFTable table, String width, STJc.Enum enumValue) { CTTblPr tblPr = getTableCTTblPr(table); // 表格宽度 CTTblWidth tblWidth = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr.addNewTblW(); if (enumValue != null) { CTJc cTJc = tblPr.addNewJc(); cTJc.setVal(enumValue); // 设置宽度 tblWidth.setW(new BigInteger(width)); tblWidth.setType(STTblWidth.DXA); // 转换pdf的时候如果没有这个可能会报空指针 for (XWPFTableRow row : table.getRows()) { for(XWPFTableCell cell : row.getTableCells()) { CTTblWidth ctTblWidth = cell.getCTTc().addNewTcPr().addNewTcW(); ctTblWidth.setW(new BigInteger(width)); ctTblWidth.setType(STTblWidth.DXA); * @Description: 得到Table的CTTblPr, 不存在则新建 public static CTTblPr getTableCTTblPr(XWPFTable table) { CTTbl ttbl = table.getCTTbl(); // 表格属性 CTTblPr tblPr = ttbl.getTblPr() == null ? ttbl.addNewTblPr() : ttbl.getTblPr(); return tblPr; * 合并表格单元格 * @param table 表格对象 * @param startRow 开始行 * @param endRow 结束行 * @param startCol 开始列 * @param endCol 结束列 public static void mergeTableCellsAndRow(XWPFTable table, int startRow, int endRow, int startCol, int endCol) { for (int rowIndex = startRow; rowIndex <= endRow; rowIndex++) { XWPFTableRow row = table.getRow(rowIndex); for (int cellIndex = startCol; cellIndex <= endCol; cellIndex++) { XWPFTableCell cell = row.getCell(cellIndex); // 第一个合并单元格用重启合并值设置 if (cellIndex == startCol) { cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART); } else { // 合并第一个单元格的单元被设置为“继续” cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE); for (int rowIndex = startRow; rowIndex <= endRow; rowIndex++) { XWPFTableRow row = table.getRow(rowIndex); XWPFTableCell cell = row.getCell(startCol); // 第一个合并单元格用重启合并值设置 if (rowIndex == startRow) { cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART); } else { // 合并第一个单元格的单元被设置为“继续” cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE); * 往表格中填充数据 * @param table * @param tableData * @Author Huangxiaocong 2018年12月16日 public static void setTableData(XWPFTable table, List<List<Object>> tableData) { List<XWPFTableRow> rowList = table.getRows(); for (int i = 0; i < rowList.size(); i++) { if (i >= tableData.size()) break; List<Object> list = tableData.get(i); List<XWPFTableCell> cellList = rowList.get(i).getTableCells(); for (int j = 0; j < cellList.size(); j++) { if (j >= list.size()) break; XWPFParagraph cellParagraph = cellList.get(j).getParagraphArray(0); XWPFRun cellParagraphRun = cellParagraph.createRun(); setTableTextFontStyle(cellParagraphRun); cellParagraphRun.setText(String.valueOf(list.get(j))); public static void setBigTitleFontStyle(XWPFRun fun) { fun.setBold(true); // 加粗 fun.setColor("000000");// 设置颜色 fun.setFontSize(20); // 字体大小 fun.setFontFamily("黑体");//设置字体 public static void setBigTitleTextFontStyle(XWPFRun fun) { setFontStyle(fun, 12, false); public static void setTitleFontStyle(XWPFRun fun) { fun.setTextPosition(20); // 设置两行之间的行间距 setFontStyle(fun, 12, true); public static void setTableTitleFontStyle(XWPFRun fun) { fun.setBold(true); // 加粗 fun.setColor("000000");// 设置颜色 fun.setFontSize(12); // 字体大小 fun.setFontFamily("黑体");//设置字体 public static void setTableTextFontStyle(XWPFRun fun) { fun.setBold(false); // 加粗 fun.setColor("000000");// 设置颜色 fun.setFontSize(10); // 字体大小 fun.setFontFamily("仿宋");//设置字体 public static void setTextFontStyle(XWPFRun fun) { setFontStyle(fun, 12, false); public static void setFontStyle(XWPFRun fun, int fontSize, boolean isBold) { fun.setBold(isBold); // 加粗 fun.setColor("000000");// 设置颜色 fun.setFontSize(fontSize); // 字体大小 fun.setFontFamily("宋体");//设置字体

3、测试代码

import com.top.ckdemo.ck.common.WordOutputUtil; import fr.opensagres.poi.xwpf.converter.pdf.PdfConverter; import fr.opensagres.poi.xwpf.converter.pdf.PdfOptions; import org.apache.poi.xwpf.usermodel.*; import java.io.*; import java.util.ArrayList; import java.util.List; * docx转pdf public class Docx2Pdf { public static void main(String[] args) { String modelPath = "E:/模板.docx"; String outPath = "E:/转换结果.pdf"; docx2Pdf(modelPath, outPath); public static void docx2Pdf(String modelPath, String outPath) { try { File file = new File(modelPath); XWPFDocument doc = new XWPFDocument(new FileInputStream(file)); XWPFParagraph paragraph = doc.getLastParagraph(); paragraph.removeRun(0); String bigTitle = "这是大标题"; String authorName = "这是作者小标题"; WordOutputUtil.setBigTitle(doc, bigTitle, authorName); // 大标题 XWPFParagraph paragraph1 = doc.createParagraph(); // 新建一个标题段落对象(就是一段文字) paragraph1.setVerticalAlignment(TextAlignment.CENTER); XWPFParagraph paragraph2 = doc.createParagraph(); // 新建一个标题段落对象(就是一段文字) paragraph2.setVerticalAlignment(TextAlignment.CENTER); XWPFParagraph paragraph3 = doc.createParagraph(); // 新建一个标题段落对象(就是一段文字) paragraph3.setVerticalAlignment(TextAlignment.CENTER); String titleText = "一、内容1"; WordOutputUtil.setTitleText(paragraph1, titleText); // 段落标题 titleText = "二、内容2"; WordOutputUtil.setTitleText(paragraph2, titleText); // 段落标题 titleText = "三、内容3"; WordOutputUtil.setTitleText(paragraph3, titleText); // 段落标题 List<List<Object>> list = new ArrayList<List<Object>>(); List<Object> rowList = new ArrayList<>(); rowList.add("1"); rowList.add("2"); rowList.add("3"); list.add(rowList); // 创建表格, WordOutputUtil.setTableTitle(doc, "表1-1"); XWPFTable table = WordOutputUtil.createTable(doc, 3, 10); // 数据行数+1行标题,列数 WordOutputUtil.setTableData(table, list); OutputStream os = new FileOutputStream(new File(outPath)); PdfOptions options = PdfOptions.create(); PdfConverter.getInstance().convert(doc, os, options); doc.write(os); os.flush(); os.close(); } catch (IOException e) { e.printStackTrace();

需要注意的是,表格合并的时候,如果是横向合并的话,字数太多或者列数太多会出现段落不齐的情况,竖向合并不会,所以请自行选择是否横向合并。

File.Copy(“source”, “targetFileName”, true);//文件拷贝,true表示当文件存在时“覆盖”,如果不加true,则文件存在报异常。 File.Exists();//判断文件是否存在 File.Move(“source”,“target”);//移动(剪切),思考如何为文件重命名?文件的剪切是可以跨磁盘的。 File.Delete...
在word编辑写个变量ACCOUNTINGMETHOD1,然后用WordReplaceUtil.getCTSym(“Wingdings 2”, “F052”)去替换就是打勾的复选框 busRecord.put(“ACCOUNTINGMETHOD1”, WordReplaceUtil.getCTSym(“Wingdings 2”, “F052”)); 没打勾的复选框 busRecord.put(“A...
今天运行项目时出现的这个问题,java.lang.IllegalStateExceptio,第一次见到这个异常, 错误原因:该异常表示,当前对客户端的响应已经结束,不能在响应已经结束(或说消亡)后再向 客户端(实际上是缓冲区)输出任何内容。 具体分析:首先解释下flush(),我们知道在使用读写流的时候数据先被读入内存这个缓冲区中, 然后再写入文件,但是当数据读完时不代表数据已经写入文件完...
使用Apache poi解析word文档为html文件时出现空指针异常: org.apache.poi.xwpf.converter.core.XWPFConverterException: java.lang.NullPointerException at org.apache.poi.xwpf.converter.xhtml.XHTMLConverter.convert(XHTMLC...
异常一:java.lang.IllegalStateException:Cannot   forward   a   response   that   is   already   committed  异常二:IllegalStateException:response already commited  异常三:IllegalStateException:getOutputStream(
import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.PDPageTree; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; import org.apache.poi.xwpf.usermodel.XWPFRun; public class DocxToPdfConverter { public static void main(String[] args) throws Exception { // 读取docx文件 FileInputStream fis = new FileInputStream(new File("input.docx")); XWPFDocument document = new XWPFDocument(fis); // 创建PDF文档 PDDocument pdfDocument = new PDDocument(); PDPageTree pages = pdfDocument.getPages(); PDPage pdfPage = new PDPage(PDRectangle.A4); pages.add(pdfPage); // 创建PDF内容流 PDPageContentStream contentStream = new PDPageContentStream(pdfDocument, pdfPage); // 遍历docx文件中的段落 for (XWPFParagraph para : document.getParagraphs()) { // 获取段落中的文本 String text = para.getText(); // 创建PDF文本对象 contentStream.beginText(); contentStream.setFont(PDType1Font.HELVETICA, 12); contentStream.newLineAtOffset(50, 700); // 添加文本到PDF中 contentStream.showText(text); contentStream.endText(); // 关闭PDF内容流 contentStream.close(); // 保存PDF文档 pdfDocument.save(new FileOutputStream(new File("output.pdf"))); // 关闭PDF文档 pdfDocument.close(); 此代码将读取名为 `input.docx` 的Word文档并将其换为名为 `output.pdf` 的PDF文件。您可以根据需要修改此代码以满足您的需求。 报错:Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed betwee
报错:Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed betwee 酷小孩612: 表情包谢谢大佬!我的可以 报错:Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed betwee 小琳o泡.: 加了没有用表情包 报错:Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed betwee 我叫情愿啊: 抛开问题不谈是一点问题都没有 报错:Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed betwee XT4625: feign: compression: request: enabled: true response: enabled: true useGzipDecoder: true 报错:Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed betwee 大佬在哪里加 报错:Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed betwee 一个比phantomjs更好的网页截图工具puppeteer