当前位置 博文首页 > qq_31734611的博客:JAVA用word文档生成或转换成PDF文档,并支持
之前发布的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>
生成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>来控制遍历的开关?
?/**
? ? ?* @方法名称?
? ? ?* @功能描述 生成下载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();
? ? ? ? }
? ? }
?/**
? ? ?* @方法名称?
? ? ?* @功能描述 生成下载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();
? ? ? ? }
? ? }
? // 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();
? ? }
/**
* 添加水印、页眉、页脚
* @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