当前位置 博文首页 > qq_31734611的博客:JAVA用word文档生成或转换成PDF文档,并支持

    qq_31734611的博客:JAVA用word文档生成或转换成PDF文档,并支持

    作者:[db:作者] 时间:2021-08-01 17:59

    之前发布的JAVA生成PDF相关功能的博客不够完善,最近又结合了添加水印与页眉页脚的功能,故在此重新梳理一版,结合实际代码,希望能帮到大家

    功能准备:

    本功能基于freemaker+openoffice+itext实现通过DOCX模板生成PDF文件或者直接转换DOC到PDF,支持水印页眉、页脚。

    相关依赖,需要事先安装好openoffice并开启服务(自行百度)。

    ?? ?<dependency>
    ?? ??? ??? ?<groupId>com.artofsolving</groupId>
    ?? ??? ??? ?<artifactId>jodconverter</artifactId>
    ?? ??? ??? ?<version>2.2.1</version>
    ?? ??? ?</dependency>
    ?? ?<dependency>
    ?? ??? ?<groupId>com.itextpdf</groupId>
    ?? ??? ?<artifactId>itextpdf</artifactId>
    ?? ??? ?<version>5.5.10</version>
    ?? ?</dependency>?
    ?? ?<!-- https://mvnrepository.com/artifact/com.itextpdf/itext-asian -->
    ?? ?<dependency>
    ?? ??? ?<groupId>com.itextpdf</groupId>
    ?? ??? ?<artifactId>itext-asian</artifactId>
    ?? ??? ?<version>5.2.0</version>
    ?? ?</dependency>

    1.?生成docx模板和xml模板

    生成docx与XML模板,这样做是使结合数据生成的DOC文件是真正的.DOC格式的文件,而不是只是将后缀名改为.doc的XML文件(因为这种文件有些软件与浏览器解析不了,显示的是XML文件的内容)

    准备需要用的DOCX的文档如test.docx作为DOCX模板。

    用压缩文件打开test.docx,复制word目录下的document.xml,取出来作为XML模板。

    ?

    ?

    ?

    XML模板里用${参数}代表传入的参数,如需遍历的话用<#list datalist(传入的集合名称) as datalist?>? ${datalist.shuxing} </#list>来控制遍历的开关?

    2.用freemaker填充模板数据,然后执行相关转换方法,最终下载。

    ?/**
    ? ? ?* @方法名称?
    ? ? ?* @功能描述 生成下载PDF
    ? ? ?* @作者 fan
    ? ? ?* @创建时间?
    ? ? ?* @param dataMap 模板参数
    ? ? ?* @param xmlTempName xml模板名称 (即前文准备的test.xml)
    ? ? ?* @param docxTempName docx模板名称(即前文准备的test.docx)
    ? ? ?* @param pdfName 生成的PDF名称
    ? ? ?* @param response
    ? ? ?* @param request
    ? ? ?* @return
    ? ? ?*/
    ? ? public static void downloadPdf(Map<String, Object> dataMap, String xmlTempName, String docxTempName, String pdfName,
    ? ? ? ? ? ? HttpServletResponse response, HttpServletRequest request) {
    ? ? ? ? try {
    ? ? ? ? ? ? // Configuration 用于读取ftl文件
    ? ? ? ? ? ? Configuration configuration = new Configuration(new Version("2.3.0"));
    ? ? ? ? ? ? configuration.setDefaultEncoding("utf-8");
    ? ? ? ? ? ? // 指定路径的第一种方式(根据某个类的相对路径指定)
    ? ? ? ? ? ? // configuration.setClassForTemplateLoading(this.getClass(), "");
    ? ? ? ? ? ? // 指定路径的第二种方式,我的路径是C:/a.ftl
    ? ? ? ? ? ? // configuration.setDirectoryForTemplateLoading(new File("c:/"));
    ? ? ? ? ? ? configuration.setServletContextForTemplateLoading(request.getSession().getServletContext(), "./WEB-INF/template");
    ? ? ? ? ? ? // 输出文档路径及名称
    ? ? ? ? ? ? File outFile = new File(request.getSession().getServletContext().getRealPath("/WEB-INF/template/temp.xml"));
    ? ? ? ? ? ? // 以utf-8的编码读取ftl文件
    ? ? ? ? ? ? Template template = configuration.getTemplate(xmlTempName, "utf-8");
    ? ? ? ? ? ? Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"), 10240);
    ? ? ? ? ? ? template.process(dataMap, out);//将初始模板结合数据得到新的xml模板
    ? ? ? ? ? ? out.close();
    ? ? ? ? ? ? String wordFile = request.getSession().getServletContext().getRealPath("/WEB-INF/template/temp.doc"); ? ?
    ? ? ? ? ? ? String pdfFile = request.getSession().getServletContext().getRealPath("/WEB-INF/template/temp.pdf");
    ? ? ? ? ? ? outDocx(new File(request.getSession().getServletContext().getRealPath("/WEB-INF/template/temp.xml")), docxTempName, wordFile, request);//将结合数据后的XML模板转换为标准的DOC格式文档
    ? ? ? ? ? ? WordToPDF(wordFile, pdfFile);//将标准的DOC格式文档转换为PDF格式
    ? ? ? ? ? ? addFooterAndWater(pdfFile, request.getSession().getServletContext().getRealPath("/WEB-INF/template/temp22.pdf"), "水印", "页眉", "页脚");//为PDF添加水印、页眉页脚等
    ? ? ? ? ? ? download(request.getSession().getServletContext().getRealPath("/WEB-INF/template/temp22.pdf"), pdfName, response, false);
    ? ? ? ? ? ? new File(wordFile).delete();//下载完成后删除生成的模板文件
    ? ? ? ? ? ? new File(pdfFile).delete();
    ? ? ? ? ? ? new File(request.getSession().getServletContext().getRealPath("/WEB-INF/template/temp22.pdf")).delete();
    ? ? ? ? ? ? outFile.delete();

    ? ? ? ? } catch (Exception e) {
    ? ? ? ? ? ? e.printStackTrace();
    ? ? ? ? }
    ? ? }

    3.? ?生成标准的DOC文件方法

    ?/**
    ? ? ?* @方法名称?
    ? ? ?* @功能描述 生成下载PDF
    ? ? ?* @作者 fan
    ? ? ?* @创建时间?
    ? ? ?* @param documentFile?原始xml结合数据集生成的xml模板
    ? ? ?* @param docxTemplate?初始准备的docx格式的模板路径
    ? ? ?* @param toFilePath?生成的文档路径(后缀名取.doc)
    ? ? ?* @param response
    ? ? ?* @param request
    ? ? ?* @return
    ? ? ?*/

    ?// 生成标准的DOC文件方法
    ? ? public static void outDocx(File documentFile, String docxTemplate, String toFilePath, HttpServletRequest request)
    ? ? ? ? ? ? throws ZipException, IOException {

    ? ? ? ? try {
    ? ? ? ? ? ? File docxFile = new File(request.getSession().getServletContext().getRealPath("/WEB-INF/template/" + docxTemplate));
    ? ? ? ? ? ? ZipFile zipFile = new ZipFile(docxFile);
    ? ? ? ? ? ? Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();
    ? ? ? ? ? ? ZipOutputStream zipout = new ZipOutputStream(new FileOutputStream(toFilePath));
    ? ? ? ? ? ? int len = -1;
    ? ? ? ? ? ? byte[] buffer = new byte[1024];
    ? ? ? ? ? ? while (zipEntrys.hasMoreElements()) {
    ? ? ? ? ? ? ? ? ZipEntry next = zipEntrys.nextElement();
    ? ? ? ? ? ? ? ? InputStream is = zipFile.getInputStream(next);
    ? ? ? ? ? ? ? ? // 把输入流的文件传到输出流中 如果是word/document.xml由我们输入
    ? ? ? ? ? ? ? ? zipout.putNextEntry(new ZipEntry(next.toString()));
    ? ? ? ? ? ? ? ? if ("word/document.xml".equals(next.toString())) {
    ? ? ? ? ? ? ? ? ? ? // InputStream in = new FileInputStream(new
    ? ? ? ? ? ? ? ? ? ? // File(XmlToDocx.class.getClassLoader().getResource("").toURI().getPath()+"template/test.xml"));
    ? ? ? ? ? ? ? ? ? ? InputStream in = new FileInputStream(documentFile);
    ? ? ? ? ? ? ? ? ? ? while ((len = in.read(buffer)) != -1) {
    ? ? ? ? ? ? ? ? ? ? ? ? zipout.write(buffer, 0, len);
    ? ? ? ? ? ? ? ? ? ? }
    ? ? ? ? ? ? ? ? ? ? in.close();
    ? ? ? ? ? ? ? ? } else {
    ? ? ? ? ? ? ? ? ? ? while ((len = is.read(buffer)) != -1) {
    ? ? ? ? ? ? ? ? ? ? ? ? zipout.write(buffer, 0, len);
    ? ? ? ? ? ? ? ? ? ? }
    ? ? ? ? ? ? ? ? ? ? is.close();
    ? ? ? ? ? ? ? ? }
    ? ? ? ? ? ? }
    ? ? ? ? ? ? zipout.close();
    ? ? ? ? } catch (FileNotFoundException e) {
    ? ? ? ? ? ? e.printStackTrace();
    ? ? ? ? }
    ? ? }

    4.? ?WORD转换为PDF

    ? // word转化为PDF方法
    ? ? public static void WordToPDF(String startFile, String overFile) throws IOException {
    ? ? ? ? // 源文件目录
    ? ? ? ? File inputFile = new File(startFile);
    ? ? ? ? if (!inputFile.exists()) {
    ? ? ? ? ? ? System.out.println("源文件不存在!");
    ? ? ? ? ? ? return;
    ? ? ? ? }

    ? ? ? ? // 输出文件目录
    ? ? ? ? File outputFile = new File(overFile);
    ? ? ? ? if (!outputFile.getParentFile().exists()) {
    ? ? ? ? ? ? outputFile.getParentFile().exists();
    ? ? ? ? }

    ? ? ? ? // 调用openoffice服务线程
    ? ? ? ? /** 我把openOffice下载到了 C:/Program Files (x86)/下 ?,下面的写法自己修改编辑就可以**/


    ? ? ? ? // 连接openoffice服务
    ? ? ? ? OpenOfficeConnection connection = new SocketOpenOfficeConnection("127.0.0.1", 8100);
    ? ? ? ? connection.connect();

    ? ? ? ? // 转换
    ? ? ? ? DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
    ? ? ? ? converter.convert(inputFile, outputFile);

    ? ? ? ? // 关闭连接
    ? ? ? ? connection.disconnect();

    ? ? ? ? // 关闭进程
    // ? ? ? ?p.destroy();

    ? ? }

    4.添加水印、页眉、页脚等

    /**
    	 *	添加水印、页眉、页脚
    	 * @param fileName 源文件路径
    	 * @param savepath 目标文件路径
    	 * @param waterMarkName 文字水印
    	 * @param pageHeade 页眉
    	 * @param foot 页脚
    	 * @return
    	 */

    ? public static int addFooterAndWater(String fileName, String savepath,
    ? ? ? ? ? ? String waterMarkName, String pageHeade, String foot)
    ? ? {
    ? ? ? ? // 文档总页数
    ? ? ? ? int num = 0;

    ? ? ? ? Document document = new Document();
    ? ? ? ? try
    ? ? ? ? {
    ? ? ? ? ? ? PdfReader reader = new PdfReader(fileName);
    ? ? ? ? ? ? BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",
    ? ? ? ? ? ? ? ? ? ? BaseFont.EMBEDDED);

    ? ? ? ? ? ? num = reader.getNumberOfPages();
    ? ? ? ? ? ? PdfCopy copy = new PdfCopy(document, new FileOutputStream(savepath));
    ? ? ? ? ? ? document.open();
    ? ? ? ? ? ? for (int i = 0; i < num;)
    ? ? ? ? ? ? {
    ? ? ? ? ? ? ? ? PdfImportedPage page = copy.getImportedPage(reader, ++i);
    ? ? ? ? ? ? ? ? PageStamp stamp = copy.createPageStamp(page);
    ? ? ? ? ? ? ? ? Font f = new Font(base);

    ? ? ? ? ? ? ? ? // 添加页脚,左侧文字,右侧页码
    ? ? ? ? ? ? ? ? ColumnText.showTextAligned(stamp.getUnderContent(),
    ? ? ? ? ? ? ? ? ? ? ? ? Element.ALIGN_RIGHT,
    ? ? ? ? ? ? ? ? ? ? ? ? new Phrase(String.format("第 %d 页/共 %d 页", i, num), f),
    ? ? ? ? ? ? ? ? ? ? ? ? 550f, 28, 0);
    ? ? ? ? ? ? ? ? ColumnText.showTextAligned(stamp.getUnderContent(),
    ? ? ? ? ? ? ? ? ? ? ? ? Element.ALIGN_LEFT, new Phrase(foot, f), 50f, 28, 0);

    ? ? ? ? ? ? ? ? // 添加页眉 (文字页眉,居中)
    ? ? ? ? ? ? ? ? ColumnText.showTextAligned(stamp.getUnderContent(),
    ? ? ? ? ? ? ? ? ? ? ? ? Element.ALIGN_CENTER, new Phrase(pageHeade, f), 150f,
    ? ? ? ? ? ? ? ? ? ? ? ? 800, 0);
    ? ? ? ? ? ? ? ??
    ? ? ? ? ? ? ? ? // 页眉添加logo (图片页眉,居右)
    ? ? ? ? ? ? ? ? /*Image img = Image.getInstance("template/logo.png");// 选择图片
    ? ? ? ? ? ? ? ? img.setAlignment(1);
    ? ? ? ? ? ? ? ? img.scaleAbsolute(436 / 5, 96 / 5);// 控制图片大小
    ? ? ? ? ? ? ? ? img.setAbsolutePosition(450f, 800);// 控制图片位置
    ? ? ? ? ? ? ? ? stamp.getUnderContent().addImage(img);*/

    ? ? ? ? ? ? ? ? // 添加水印
    ? ? ? ? ? ? ? ? PdfContentByte under = stamp.getUnderContent();
    ? ? ? ? ? ? ? ? under.beginText();
    ? ? ? ? ? ? ? ? under.setColorFill(BaseColor.BLACK);
    ? ? ? ? ? ? ? ??
    ? ? ? ? ? ? ? ? // 字符越长,字体越小,设置字体
    ? ? ? ? ? ? ? ? int fontSize = getFontSize(waterMarkName);
    ? ? ? ? ? ? ? ? under.setFontAndSize(base, fontSize);

    ? ? ? ? ? ? ? ? // 设置水印文字字体倾斜 开始
    ? ? ? ? ? ? ? ? float pageWidth = reader.getPageSize(i).getWidth();
    ? ? ? ? ? ? ? ? float pageHeight = reader.getPageSize(i).getHeight();

    ? ? ? ? ? ? ? ? under.showTextAligned(Element.ALIGN_CENTER, waterMarkName,
    ? ? ? ? ? ? ? ? ? ? ? ? pageWidth / 2, pageHeight / 2, 60);// 水印文字成60度角倾斜,且页面居中展示

    ? ? ? ? ? ? ? ? // 字体设置结束
    ? ? ? ? ? ? ? ? under.endText();
    ? ? ? ? ? ? ? ? stamp.alterContents();
    ? ? ? ? ? ? ? ? copy.addPage(page);
    ? ? ? ? ? ? }
    ? ? ? ? }
    ? ? ? ? catch (Exception e)
    ? ? ? ? {
    ? ? ? ? ? ? e.printStackTrace();
    ? ? ? ? ? ? return -1;
    ? ? ? ? }
    ? ? ? ? finally
    ? ? ? ? {
    ? ? ? ? ? ? if (null != document)
    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? reader.close();
    ? ? ? ? ? ? ? ? document.close();
    ? ? ? ? ? ? }
    ? ? ? ? }
    ? ? ? ? System.out.println("pdf totalpages:" + num);
    ? ? ? ? return num;

    ? ? }
    ? ? /**
    ? ? ?* 根据水印文字长度计算获取字体大小
    ? ? ?* @param waterMarkName
    ? ? ?* @return
    ? ? ?*/
    ? ? private static int getFontSize(String waterMarkName){
    ? ? ? ? int fontSize = 80;
    ? ? ? ? if(null != waterMarkName && !"".equals(waterMarkName)){
    ? ? ? ? ? ? int length = waterMarkName.length();
    ? ? ? ? ? ? if(length <=26 && length >= 18){
    ? ? ? ? ? ? ? ? fontSize = 26;
    ? ? ? ? ? ? }else if(length <18 && length >= 8){
    ? ? ? ? ? ? ? ? fontSize = 40;
    ? ? ? ? ? ? }else if(length <8 && length >= 1){
    ? ? ? ? ? ? ? ? fontSize = 80;
    ? ? ? ? ? ? }else {
    ? ? ? ? ? ? ? ? fontSize = 16;
    ? ? ? ? ? ? }
    ? ? ? ? } ? ? ??
    ? ? ? ? return fontSize;
    ? ? }

    ?

    ?

    //经过本人测试,2.2.1的jodconverter包只能转换后缀doc格式的文件,不能转换docx的文件,有人说应是jodconverter版本不够,但博主当时下载最高版本后,其余方法又会报异常。有问题欢迎讨论,水印功能参考https://www.it610.com/article/3640077.htm

    cs