使用poi根据模版生成word文档并转换成PDF文件

一、首先制作word模版(这里需要注意的是文件后缀是docx不能是doc),${xxxx}是一会要替换的内容
文档示例

关于为何必须是docx后缀可以看这篇文章https://www.cnblogs.com/ct-csu/p/8178932.html

二、添加poi所需要的jar包文件,我用的maven对jar包进行管理
poi依赖
三、由于poi自身bug,会出现图片无法显示问题,这里需要自定义一个类继承XWPFDocument类,接下来使用的都是我们自己创建的这个类来操作word对象,这个

类对XWPFDocument进行了继承,所以不用担心会有什么问题

package com.newdo.base;

import java.io.IOException;
import java.io.InputStream;

import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

/**
 * word  导出工具类
 */
public class CustomXWPFDocument extends XWPFDocument{
	public CustomXWPFDocument(InputStream in) throws IOException {
		super(in);
	}

	public CustomXWPFDocument() {
		super();
	}

	public CustomXWPFDocument(OPCPackage pkg) throws IOException {
		super(pkg);
	}
}

四、接下来就是导出word的工具类了

package com.newdo.base;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletResponse;

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;

import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComThread;
import com.jacob.com.Dispatch;

/**
 * word 导出工具类
 */
public class WordUtils {

	/**
	 * 用于判断导出的word是否转pdf
	 */
	public static int judgment = 0;

	public WordUtils() {
		judgment = 0;
	}

	/**
	 * 根据模板生成word
	 * 
	 * @param path      模板的路径
	 * @param params    需要替换的参数
	 * @param tableList 需要插入的参数
	 * @param fileName  生成word文件的文件名
	 * @param response
	 */
	public void getWord(String path, Map<String, Object> params, List<String[]> tableList, String fileName,
			HttpServletResponse response) throws Exception {
		String saveRoute = path.substring(0, path.indexOf("\\"));

		File file = new File(path);
		InputStream is = new FileInputStream(file);
		CustomXWPFDocument doc = new CustomXWPFDocument(is);

		this.replaceInPara(doc, params); // 替换文本里面的变量
		this.replaceInTable(doc, params, tableList); // 替换表格里面的变量
		OutputStream os = null;
		if (judgment == 0) {
			fileName = java.net.URLDecoder.decode(fileName, "UTF-8");
			os = new FileOutputStream(saveRoute + "\\word\\" + fileName);

			doc.write(os);

			String pdf = fileName.substring(0, fileName.lastIndexOf(".")) + ".pdf"; // 截掉
			wToPdfChange(saveRoute + "\\word\\" + fileName, saveRoute + "\\word\\" + pdf);

			try {
				System.out.println("========================pdf下载开始========================");
				// path是指欲下载的文件的路径。
				file = new File(saveRoute + "\\word\\" + pdf);
				// 取得文件名。
				String filename = URLEncoder.encode(file.getName(), "utf-8");
				// 取得文件的后缀名。
				String ext = filename.substring(filename.lastIndexOf(".") + 1).toUpperCase();
				// 以流的形式下载文件。
				is = new BufferedInputStream(new FileInputStream(saveRoute + "\\word\\" + pdf));
				byte[] buffer = new byte[is.available()];
				is.read(buffer);
				// 清空response
				response.reset();
				// 设置response的Header
				response.addHeader("Content-Disposition", "attachment;filename=" + filename);
				response.addHeader("Content-Length", "" + file.length());
				os = new BufferedOutputStream(response.getOutputStream());
				response.setContentType("application/octet-stream");
				os.write(buffer);
				os.flush();
				System.out.println("========================pdf下载结束========================");
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		} else {
//			os = response.getOutputStream();
            fileName = java.net.URLDecoder.decode(fileName, "UTF-8");
            os = new FileOutputStream(saveRoute + "\\word\\" + fileName);
			response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
			doc.write(os);
			judgment = 0;
		}

		this.close(os);
		this.close(is);
	}

	/**
	 * word 转 pdf
	 * 
	 * @param wordFile word 的路径 word 的路径
	 * @param pdfFile  pdf 的路径
	 */
	public static void wToPdfChange(String wordFile, String pdfFile) {
		ActiveXComponent app = null;
		Dispatch document = null;
		System.out.println("========================开始转换========================");
		try {
			// 打开word
			System.out.println("开始打开word");
			app = new ActiveXComponent("Word.Application");

			// 获得word中所有打开的文档
			Dispatch documents = app.getProperty("Documents").toDispatch();
			System.out.println("打开文件: " + wordFile);
			// 打开文档
			document = Dispatch.call(documents, "Open", wordFile, false, true).toDispatch();
			// 如果文件存在的话,不会覆盖,会直接报错,所以我们需要判断文件是否存在
			File target = new File(pdfFile);
			if (target.exists()) {
				target.delete();
			}
			System.out.println("另存为: " + pdfFile);
			Dispatch.call(document, "SaveAs", pdfFile, 17);
		} catch (Exception e) {
			System.out.println("转换失败" + e.getMessage());
		} finally {
			// 关闭office
//			app.invoke("Quit", 0);

			if (document != null) {
				// 关闭文档
				Dispatch.call(document, "Close", false);
			}
			if (app != null) {
				app.invoke("Quit", 0);
			}
			
			// 获取系统类型
			String osName = System.getProperty("os.name");
			// 判断是系统类型
			if (osName.toLowerCase().startsWith("win")) {
				System.out.println(osName);
				// window系统
				String killCmd = "taskkill /f /im wps.exe";
				String killCmd1 = "taskkill /f /im wpscenter.exe";
				Process p;
				try {
					p = Runtime.getRuntime().exec(killCmd);
					p = Runtime.getRuntime().exec(killCmd1);
					int runnngStatus = p.waitFor();
					System.out.println("已杀" + runnngStatus);
				} catch (IOException e) {
					e.printStackTrace();
					System.out.println("转换失败" + e.getMessage());
				} catch (InterruptedException e) {
					e.printStackTrace();
					System.out.println("转换失败" + e.getMessage());
				}
			}
		}
		System.out.println("========================转换结束========================");
	}

	/**
	 * 替换段落里面的变量
	 * 
	 * @param doc    要替换的文档
	 * @param params 参数
	 */
	private void replaceInPara(CustomXWPFDocument doc, Map<String, Object> params) {
		Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
		XWPFParagraph para;
		while (iterator.hasNext()) {
			para = iterator.next();
			this.replaceInPara(para, params, doc);
		}
	}

	/**
	 * 替换段落里面的变量
	 *
	 * @param para   要替换的段落
	 * @param params 参数
	 */
	private void replaceInPara(XWPFParagraph para, Map<String, Object> params, CustomXWPFDocument doc) {
		List<XWPFRun> runs;
		Matcher matcher;
		if (this.matcher(para.getParagraphText()).find()) {
			runs = para.getRuns();
			int start = -1;
			int end = -1;
			String runsIndex = "";
			String str = "";
			for (int i = 0; i < runs.size(); i++) {
				XWPFRun run = runs.get(i);
				String runText = run.toString().trim();
				if (!runText.equals("") && (runText.indexOf("${")!=-1 || runText.equals("}"))){
                    if ('$' == runText.charAt(0) && '{' == runText.charAt(1)) {
                        start = i;
                        runsIndex += i+",";
                    }
                    if ((start != -1)) {
                        str += runText;
                    }
                    if ('}' == runText.charAt(runText.length() - 1)) {
                        if (start != -1) {
                            end = i;

                            for (int k = start; k <= end; k++) {
                                para.removeRun(k);
                                k--;
                                end--;
                            }
                        }
                    }
                }

			}

//			for (int i = start; i <= end; i++) {
//				para.removeRun(i);
//				i--;
//				end--;
//			}
            int doInt = 0;
            String[] runsIns = runsIndex.split(",");
            for (int k=0;k<runsIns.length;k++){
                if (!"".equals(str)) {
                    for (Map.Entry<String, Object> entry : params.entrySet()) {
                        String key = entry.getKey();
                        if (str.indexOf(key) != -1) {

                            Object value = entry.getValue();
                            if (value instanceof String) {
                                str = str.replace(key, value.toString());
                                if (((String) str).indexOf("\r") > 0) {
                                    // 设置换行
                                    String[] text = str.toString().split("\r");
                                    para.removeRun(0);
                                    for (int f = 0; f < text.length; f++) {
                                        if (f == 0) {
                                            // 此处不缩进因为word模板已经缩进了。
                                            para.createRun().setText(text[f].trim());
                                        } else {
                                            para.createRun().addCarriageReturn();// 硬回车
                                            // 注意:wps换行首行缩进是三个空格符,office要的话可以用
                                            // run.addTab();缩进或者四个空格符
                                            para.createRun().setText(text[f]);
                                        }
                                    }
                                } else {
//								para.createRun().setText((String) value);
                                    int num = 0;
                                    if (doInt==0){
                                        num = CFunc.ToInt(runsIns[k]);
                                    }else{
                                        num = CFunc.ToInt(runsIns[k])+doInt;
                                    }
                                    para.insertNewRun(num).setText((String) value);
                                    doInt++;
                                }
                                // para.createRun().setText(str, 0);
                                break;
                            } else if (value instanceof Map) {
                                str = str.replace(key, "");
                                Map pic = (Map) value;
                                int width = Integer.parseInt(pic.get("width").toString());
                                int height = Integer.parseInt(pic.get("height").toString());
                                int picType = getPictureType(pic.get("type").toString());
                                byte[] byteArray = (byte[]) pic.get("content");
                                ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);
                                try {
                                    // int ind =
                                    // doc.addPicture(byteInputStream,picType);
                                    // doc.createPicture(ind, width , height,para);
                                    doc.addPictureData(byteInputStream, picType);
                                    para.createRun().setText(str, 0);
                                    break;
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                }
            }

		}
	}

	/**
	 * 为表格插入数据,行数不够添加新行
	 *
	 * @param table     需要插入数据的表格
	 * @param tableList 插入数据集合
	 */
	private static void insertTable(XWPFTable table, List<String[]> tableList) {
		// 创建行,根据需要插入的数据添加新行,不处理表头
		for (int i = 0; i < tableList.size(); i++) {
			XWPFTableRow row = table.createRow();
		}
		// 遍历表格插入数据
		List<XWPFTableRow> rows = table.getRows();
		int length = table.getRows().size();
		for (int i = 1; i < length - 1; i++) {
			XWPFTableRow newRow = table.getRow(i);
			List<XWPFTableCell> cells = newRow.getTableCells();
			for (int j = 0; j < cells.size(); j++) {
				XWPFTableCell cell = cells.get(j);
				String s = tableList.get(i - 1)[j];
				cell.setText(s);
			}
		}
	}

	/**
	 * 替换表格里面的变量
	 * 
	 * @param doc    要替换的文档
	 * @param params 参数
	 */
	private void replaceInTable(CustomXWPFDocument doc, Map<String, Object> params, List<String[]> tableList) {
		Iterator<XWPFTable> iterator = doc.getTablesIterator();
		XWPFTable table;
		List<XWPFTableRow> rows;
		List<XWPFTableCell> cells;
		List<XWPFParagraph> paras;
		while (iterator.hasNext()) {
			table = iterator.next();
//			System.out.println("------------>" + table.getRows().size());
			if (table.getRows().size() > 1) {
				// 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
				if (this.matcher(table.getText()).find()) {
					rows = table.getRows();
					for (XWPFTableRow row : rows) {
						cells = row.getTableCells();
						for (XWPFTableCell cell : cells) {
							paras = cell.getParagraphs();
							for (XWPFParagraph para : paras) {
								this.replaceInPara(para, params, doc);
							}
						}
					}
				} else {
					insertTable(table, tableList); // 插入数据
				}
			}
		}
	}

	/**
	 * 正则匹配字符串
	 *
	 * @param str
	 * @return
	 */
	private Matcher matcher(String str) {
		Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
		Matcher matcher = pattern.matcher(str);
		return matcher;
	}

	/**
	 * 根据图片类型,取得对应的图片类型代码
	 *
	 * @param picType
	 * @return int
	 */
	private static int getPictureType(String picType) {
		int res = CustomXWPFDocument.PICTURE_TYPE_PICT;
		if (picType != null) {
			if (picType.equalsIgnoreCase("png")) {
				res = CustomXWPFDocument.PICTURE_TYPE_PNG;
			} else if (picType.equalsIgnoreCase("dib")) {
				res = CustomXWPFDocument.PICTURE_TYPE_DIB;
			} else if (picType.equalsIgnoreCase("emf")) {
				res = CustomXWPFDocument.PICTURE_TYPE_EMF;
			} else if (picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")) {
				res = CustomXWPFDocument.PICTURE_TYPE_JPEG;
			} else if (picType.equalsIgnoreCase("wmf")) {
				res = CustomXWPFDocument.PICTURE_TYPE_WMF;
			}
		}
		return res;
	}

	/**
	 * 将输入流中的数据写入字节数组
	 *
	 * @param in
	 * @return
	 */
	public static byte[] inputStream2ByteArray(InputStream in, boolean isClose) {
		byte[] byteArray = null;
		try {
			int total = in.available();
			byteArray = new byte[total];
			in.read(byteArray);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (isClose) {
				try {
					in.close();
				} catch (Exception e2) {
					e2.getStackTrace();
				}
			}
		}
		return byteArray;
	}

	/**
	 * 关闭输入流
	 *
	 * @param is
	 */
	public void close(InputStream is) {
		if (is != null) {
			try {
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 关闭输出流
	 *
	 * @param os
	 */
	public void close(OutputStream os) {
		if (os != null) {
			try {
				os.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

五、word转pdf文件我们需要用到一个jacob.jar(下载地址在文章下面 )的一个包,将该jar包放入项目中的resources文件下的lib中
在这里插入图片描述
maven中引入本地jar包
在这里插入图片描述
同时需要将jacob中的dll文件放到自己的jdk环境中,将 dll 文件拷贝到 C:\Program Files\Java\jdk1.8.0_191\jre\bin (这是我自己的jdk位置)下,或者拷贝到当前项目运行的 jdk 的目录下的 jre/bin 目录下
在这里插入图片描述
这里的文件多少位(×64或×86)是根据自己的电脑来的
在这里插入图片描述

完成以上操作word才能正常转换为pdf文件

六、最后就是进行测试了,我是用的是springboot框架,这里放出测试代码

	@Override
    public void contractPrintDetail(HttpServletRequest request, HttpServletResponse response, Map<String, Object> mapArgu) {
    	//查询出来的数据
	    Map<String,Object> map = contractPrintMapper.mySelect(mapArgu);
        WordUtils wordUtil = new WordUtils();
        Map<String, Object> params = new LinkedHashMap<String, Object>();
        List<String[]> testList = new ArrayList<String[]>();
        params.put("${DWMC}",map.get("DWMC"));
        params.put("${DWDZ}",map.get("DWDZ"));
        params.put("${FDDBR}",map.get("FDDBR"));
        params.put("${XM}",map.get("XM"));
        params.put("${XBMC}",map.get("XBMC"));
        params.put("${LXDH}",map.get("LXDH"));
        params.put("${JG}",map.get("JG"));
        params.put("${ZS}",map.get("ZS"));
        params.put("${SFZHM}",map.get("SFZHM"));
        params.put("${GWMC}",map.get("GWMC"));
        try{
            String path = CFunc.clobToString((Clob) map.get("HTMB"));
            String name = CFunc.ToString(map.get("XM")) + "_" + CFunc.ToString(map.get("HTLX"))+"合同.docx";
            String filename = URLEncoder.encode(name, "utf-8");
            response.setContentType(request.getServletContext().getMimeType(filename));
            wordUtil.getWord(path, params, testList, filename, response);
        }catch (Exception e){
            e.printStackTrace();
        }

七、最后生成的pdf文档
  在这里插入图片描述

POI官网:https://poi.apache.org/
Apache POI Word 简易示例文档:https://my.oschina.net/skymozn/blog/3189732
JACOB:https://sourceforge.net/projects/jacob-project/?source=typ_redirect

参考链接:
https://www.cnblogs.com/duanrantao/p/8682897.html

  • 5
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
好的,你可以使用 Apache POI 和 iText 库来实现将 Word 文档转换成 PDF 文件的功能。首先,确保你已经将这两个库添加到你的项目中。 以下是一个简单的 Java 代码示例,可以将 Word 文档换为 PDF 文件: ```java import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; import com.itextpdf.text.Document; import com.itextpdf.text.Paragraph; import com.itextpdf.text.pdf.PdfWriter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class WordToPdfConverter { public static void main(String[] args) { String inputWordFile = "input.docx"; // 输入的 Word 文件路径 String outputPdfFile = "output.pdf"; // 输出的 PDF 文件路径 try { // 打开 Word 文档 XWPFDocument document = new XWPFDocument(new FileInputStream(inputWordFile)); // 创建 PDF 文档 Document pdfDoc = new Document(); PdfWriter.getInstance(pdfDoc, new FileOutputStream(outputPdfFile)); // 打开 PDF 文档 pdfDoc.open(); // 读取 Word 文档中的段落内容,并将其写入 PDF 文档 for (XWPFParagraph paragraph : document.getParagraphs()) { String text = paragraph.getText(); pdfDoc.add(new Paragraph(text)); } // 关闭 PDF 文档 pdfDoc.close(); System.out.println("Word 文档成功换为 PDF 文件!"); } catch (IOException e) { System.out.println("换过程出现错误:" + e.getMessage()); } } } ``` 在代码中,你需要将 `input.docx` 替换为你要换的 Word 文档路径,`output.pdf` 替换为输出的 PDF 文件路径。请确保输入的 Word 文档是正确的,且具有正确的扩展名(.docx)。 希望这段代码对你有所帮助!如果有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值