昨天写了下文件转PDF简易运用的短例,有人问我,他是前后端分离的,用流形式转PDF怎么转。其实这个对于图片来说比较简单,对于word、excel来说比较复杂一点,顺便补充下excel转PDF。

  本次讲解的案例是:前端我用thymeleaf搭配layui控件,用layui.upload的方式上传本地文件。

  简短补充下layui的使用,这个控件还是蛮好用的。

  首先去它的官网:https://www.layui.com/ 下载整个包

发票 xml 转 pdf java_发票 xml 转 pdf java

下载完后把他放到static目录下

发票 xml 转 pdf java_发票 xml 转 pdf java_02

接下来就是html中引用了,只需要引用一个css、一个js

th:href="@{/layui/css/layui.css}" rel="stylesheet">

发票 xml 转 pdf java_发票 xml 转 pdf java_03

发票 xml 转 pdf java_流文件pdf_04

上传文件的接口方法,该方法写入js中

layui.use('upload',function(){const $ = layui.jquery        , upload = layui.upload;    //拖拽上传    upload.render({elem: '#test10'        ,url: basePath +'/fileChange.json' //改成您自己的上传接口        ,accept: "file"        //,size: 1048576        ,progress: function (e, percent) {console.log(JSON.stringify(e));            console.log("进度:" + e + '%');        },done: function(res){const code = res.code;            const msg = res.msg;            if(code === "0000") {
                layer.msg('文件转PDF成功');            } else {
                layer.msg(msg);            }//layui.$('#uploadDemoView').removeClass('layui-hide').find('img').attr('src', res.files.file);            console.log(res)
        }
    });});

后端如何接收解析前端传过来的文件信息呢,我这里用的方式是解析request的信息,

MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;// 获取上传的文件MultipartFile multiFile = multipartRequest.getFile("file");

发票 xml 转 pdf java_java_05

文件流怎么获取呢:multiFile.getInputStream()

好了我们来对比一下图片流形式转PDF和图片路径转PDF的区别,看代码

/** * 图片转PDF(文件流形式) * @param multiFile * @param pdfOutPath * @return */private boolean pictureToPDF(MultipartFile multiFile, String pdfOutPath) {boolean changeResult = false;    Document doc = null;    try {
        FileOutputStream fos = new FileOutputStream(pdfOutPath);        doc = new Document(null, 0, 0, 0, 0);        // 写入PDF文档        PdfWriter.getInstance(doc, fos);        // 读取图片流        BufferedImage img = null;        // 实例化图片        Image image = null;        float newHeight = 0f, newWidth = 0f;        img = ImageIO.read(multiFile.getInputStream());        Map,Float> result = setImageWidthHeight(img.getWidth(), img.getHeight(),newWidth, newHeight);        newWidth = result.get("width");        newHeight = result.get("height");        doc.setPageSize(new Rectangle(newWidth,newHeight));        image = Image.getInstance(multiFile.getBytes());        image.scaleAbsolute(new Rectangle(newWidth,newHeight));        // 添加图片到文档        doc.newPage();        doc.open();        doc.add(image);        // 关闭文档        doc.close();        changeResult = true;        System.out.println("图片转PDF成功");    } catch (Exception e) {
        System.out.println("图片转PDF失败");        e.printStackTrace();    } finally {if(doc != null) doc.close();    }return  changeResult;}
/** * 图片转PDF(文件路径形式) * @param imagPath * @param pdfOutPath * @return */private boolean pictureToPDF(String imagPath, String pdfOutPath) {boolean changeResult = false;    try {
        FileOutputStream fos = new FileOutputStream(pdfOutPath);        Document doc = new Document(null, 0, 0, 0, 0);        // 写入PDF文档        PdfWriter.getInstance(doc, fos);        // 读取图片流        BufferedImage img = null;        // 实例化图片        Image image = null;        float newHeight = 0f, newWidth = 0f;        img = ImageIO.read(new File(imagPath));        Map,Float> result = setImageWidthHeight(img.getWidth(), img.getHeight(),newWidth, newHeight);        newWidth = result.get("width");        newHeight = result.get("height");        doc.setPageSize(new Rectangle(newWidth,newHeight));        image = Image.getInstance(imagPath);        image.scaleAbsolute(new Rectangle(newWidth,newHeight));        // 添加图片到文档        doc.newPage();        doc.open();        doc.add(image);        // 关闭文档        doc.close();        changeResult = true;        System.out.println("图片转PDF成功");    } catch (Exception e) {
        System.out.println("图片转PDF失败");        e.printStackTrace();    }return  changeResult;}

两者区别不大,通过图片截图来更好的看一下,就是读取图片的时候一个是通过路径形式,一个是通过流形式;这是因为方法同时支持路径和流形式。

发票 xml 转 pdf java_流文件pdf_06

word和excel的方法目前就没有发现可以同时支持路径和流的,所以还是用老方法用路径比较合适。那么你可能会问,前后端分离怎么传文件路径过来,传过来的路径也解析不到呀。别急。听我慢慢道来

有好几种方法可以解决:

  1. 前端传输文件,后端request解析,解析出文件流同时转成文件报错到服务器磁盘(保存的时候可以的到文件路径)
  2. 讲文件传到通用的存储控件,比如说OSS服务器(这个要花钱买,鉴于小型开发者可能没有这个需求和必要,可以暂不考虑)

我是一般用第一种

//将文件保存到当前服务器磁盘InputStream inputStream = multiFile.getInputStream();String totalPath = fileSavePath + fileName;FileUtils.createFolder(fileSavePath);boolean result = FileUtils.saveFileByStream(inputStream, totalPath);
package jp.utils;import java.io.File;import java.io.FileOutputStream;import java.io.InputStream;/** * 文件处理工具类 */public class FileUtils {public static String createFolder(String path,String folderName) {
        File folder = new File(path+File.separator+folderName);        if(!folder.exists()) {
            folder.mkdirs();        }return folder.getAbsolutePath();    }public static void createFolder(String path) {
        File folder = new File(path);        if(!folder.exists()) {
            folder.mkdirs();        }
    }/**     * 获取文件后缀     * @param fileName     * @return     */    public static String getFileSuffix(String fileName) {int splitIndex = fileName.lastIndexOf(".");        return fileName.substring(splitIndex + 1);    }public static String getFileNameNoEx(String filename) {if ((filename != null) && (filename.length() > 0)) {int dot = filename.lastIndexOf('.');            if ((dot >-1) && (dot < (filename.length()))) {return filename.substring(0, dot);            }
        }return filename;    }/**     * 文件流保存到服务磁盘     * @param inputStream     * @param filePath     * @return     */    public static boolean saveFileByStream(InputStream inputStream, String filePath) {boolean result = false;        FileOutputStream fos = null;        try {
            fos = new FileOutputStream(filePath);            byte buffer[] = new byte[inputStream.available()];            int length = 0;            while((length = inputStream.read(buffer))>0){
                fos.write(buffer, 0, length);            }//关闭输入流            inputStream.close();            fos.close();            result = true;        } catch (Exception e) {
            e.printStackTrace();        } finally {try {if(fos != null) {
                    fos.close();                }if(inputStream !=null) {
                    inputStream.close();                }
            } catch (Exception e2) {
            }
        }return result;    }
}

下面废话不多少,我们看一下实际效果,最后我会贴上全部代码

点击文件上传或者拖拽,选择D盘的图片,(后端默认存到D:/root/deploy)

发票 xml 转 pdf java_Image_07

执行完,看一下效果

发票 xml 转 pdf java_Image_08

发票 xml 转 pdf java_发票 xml 转 pdf java_09


接下来演示excel

发票 xml 转 pdf java_Image_10

发票 xml 转 pdf java_spring_11

Excel写两页

发票 xml 转 pdf java_发票 xml 转 pdf java_12

发票 xml 转 pdf java_Image_13

发票 xml 转 pdf java_发票 xml 转 pdf java_14

发票 xml 转 pdf java_流文件pdf_15

是不是Excel也成功执行了。本来我也想搞一个ppt的,但是失败了,网上也没有找到解决的资料,只能放弃了,下次如果找到解决的话,我会补充的。

最后奉上完整的代码:此代码跟上一篇中的代码相比做了一些优化

前端html代码:

/span>html>lang="en" xmlns:th="http://www.thymeleaf.org">    charset="UTF-8">    name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">  th:href="@{/bootstrap/bootstrap-3.3.7/css/bootstrap.min.css}" rel="stylesheet" type="text/css" >  th:href="@{/layui/css/layui.css}" rel="stylesheet"> :inline="text">
 table{border-spacing: 10px 30px;}
tr {
display: block;
 /*将tr设置为块体元素*/
 margin: 3px 0;
 /*设置tr间距为2px*/
 }

td {
text-align: right;
 }

 .layui-tab-content {
height: 200vh;
 }



style="margin-top:3%;margin-left:1%;margin-right:2%;height: 250px;">  
   
 
    style="width: 33%; float: left">  
    
 
     class="layui-form-item" > class="layui-elem-field layui-field-title" style="margin-top: 30px;"> 文件转PDF   
     
 
      class="layui-upload-drag" id="test10"> class="layui-icon"> 
      
 
       class="layui-hide" id="uploadDemoView">  src="" alt="上传成功后渲染" style="max-width: 196px"> 



controller

package jp.controller.business;import jp.service.IFileHandleService;import jp.vo.ResultVo;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;@Controllerpublic class fileController {@Autowired    IFileHandleService fileHandleService;    /**     * 图片转换     * @param request     * @return     */    @RequestMapping(value = "/fileChange.json", produces = "application/json;charset=UTF-8", method = RequestMethod.POST)@ResponseBody    public ResultVo fileChangeMethod(HttpServletRequest request) {return fileHandleService.fileToPdf(request);    }
}

service 

package jp.service.impl;import com.itextpdf.text.Document;import com.itextpdf.text.Image;import com.itextpdf.text.Rectangle;import com.itextpdf.text.pdf.PdfWriter;import com.jacob.activeX.ActiveXComponent;import com.jacob.com.ComThread;import com.jacob.com.Dispatch;import com.jacob.com.Variant;import jp.service.IFileHandleService;import jp.utils.FileUtils;import jp.utils.PDFUtils;import jp.utils.ResultVoUtil;import jp.vo.ResultVo;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.env.Environment;import org.springframework.stereotype.Service;import org.springframework.web.multipart.MultipartFile;import org.springframework.web.multipart.MultipartHttpServletRequest;import javax.imageio.ImageIO;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.awt.image.BufferedImage;import java.io.*;import java.util.HashMap;import java.util.Map;@Servicepublic class FileHandleImpl implements IFileHandleService {private static final int regular_width = 842;    private static final int regular_height = 595;    private static final int vertical_regular_width = 595;    private static final int vertical_regular_height = 842;    static final int WORD_FORMAT_PDF = 17;    static final int PPT_FORMAT_PDF = 32;    static final int EXCEL_FORMAT_PDF = 0;    @Autowired    Environment env;    @Override    public ResultVo fileToPdf(HttpServletRequest request) {//yml中配置的文件保存路径(D:/root/deploy/)        String fileSavePath = env.getProperty("manager.save-path");        try {
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;            // 获取上传的文件            MultipartFile multiFile = multipartRequest.getFile("file");            assert multiFile != null;            String fileName = multiFile.getOriginalFilename();            String suffix = FileUtils.getFileSuffix(fileName);            String fileNameNoExt = FileUtils.getFileNameNoEx(fileName);            String contentType =  multiFile.getContentType();            String pdfOutPath = fileSavePath + fileNameNoExt + ".pdf";            if(contentType.contains("image/")) {boolean result = pictureToPDF(multiFile, pdfOutPath);                if(result) return ResultVoUtil.success();            } else {//将文件保存到当前服务启磁盘                InputStream inputStream = multiFile.getInputStream();                String totalPath = fileSavePath + fileName;                FileUtils.createFolder(fileSavePath);                boolean result = FileUtils.saveFileByStream(inputStream, totalPath);                if(!result) return ResultVoUtil.error("E111","文件保存到磁盘失败");                boolean changSuc = false;                if (suffix.equals("doc") || suffix.equals("docx") || suffix.equals("txt"))  {
                    changSuc = wordToPDF(totalPath, pdfOutPath);                } else if (suffix.equals("ppt") || suffix.equals("pptx")) {
                    changSuc = pptToPDF(totalPath, pdfOutPath);                } else if (suffix.equals("xls") || suffix.equals("xlsx")) {
                    changSuc = excelToPDF(totalPath, pdfOutPath);                } else {return ResultVoUtil.error("W111", "暂不支持该文件格式("+suffix+")转PDF");                }if(changSuc) return ResultVoUtil.success();            }
        } catch (Exception e) {
            e.printStackTrace();        }return ResultVoUtil.error("0001", "转换失败");    }/**     * 文件填充     * @param request     * @param response     * @return     */    @Override    public ResultVo fileFill(HttpServletRequest request, HttpServletResponse response) {
        String fileSavePath = env.getProperty("manager.save-path");        OutputStream os = null;        InputStream inputStream = null;        try {
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;            // 获取上传的文件            MultipartFile multiFile = multipartRequest.getFile("file");            assert multiFile != null;            String fileName = multiFile.getOriginalFilename();            String pdfOutPath = fileSavePath + fileName;            inputStream = multiFile.getInputStream();//            //这是直接输出到磁盘//            FileOutputStream outputStream = new FileOutputStream(pdfOutPath);            //直接输出            byte[] byt = new byte[inputStream.available()];            inputStream.read(byt);            Map, String> data = new HashMap<>();            data.put("username", "小明");            data.put("sex", "男");            data.put("like", "女");            //通过浏览器输出            response.reset();            response.setContentType("application/pdf");            response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes("gbk"), "iso8859-1"));            os = response.getOutputStream();            boolean result = PDFUtils.fillTemplate(os, byt, data);            System.out.println("填充成功");            response.getOutputStream().flush();            response.getOutputStream().close();            os.close();            inputStream.close();            if(result) return ResultVoUtil.success();        } catch (Exception e) {
            e.printStackTrace();        } finally {if(inputStream != null) {try {
                    inputStream.close();                    if(os != null)os.close();                } catch (IOException e) {
                    e.printStackTrace();                }
            }
        }return ResultVoUtil.error("0001", "PDF填充失败");    }/**     * 图片转PDF(文件流形式)     * @param multiFile     * @param pdfOutPath     * @return     */    private boolean pictureToPDF(MultipartFile multiFile, String pdfOutPath) {boolean changeResult = false;        Document doc = null;        try {
            FileOutputStream fos = new FileOutputStream(pdfOutPath);            doc = new Document(null, 0, 0, 0, 0);            // 写入PDF文档            PdfWriter.getInstance(doc, fos);            // 读取图片流            BufferedImage img = null;            // 实例化图片            Image image = null;            float newHeight = 0f, newWidth = 0f;            img = ImageIO.read(multiFile.getInputStream());            Map,Float> result = setImageWidthHeight(img.getWidth(), img.getHeight(),newWidth, newHeight);            newWidth = result.get("width");            newHeight = result.get("height");            doc.setPageSize(new Rectangle(newWidth,newHeight));            image = Image.getInstance(multiFile.getBytes());            image.scaleAbsolute(new Rectangle(newWidth,newHeight));            // 添加图片到文档            doc.newPage();            doc.open();            doc.add(image);            // 关闭文档            doc.close();            changeResult = true;            System.out.println("图片转PDF成功");        } catch (Exception e) {
            System.out.println("图片转PDF失败");            e.printStackTrace();        } finally {if(doc != null) doc.close();        }return  changeResult;    }/**     * 图片转PDF(文件路径形式)     * @param imagPath     * @param pdfOutPath     * @return     */    private boolean pictureToPDF(String imagPath, String pdfOutPath) {boolean changeResult = false;        try {
            FileOutputStream fos = new FileOutputStream(pdfOutPath);            Document doc = new Document(null, 0, 0, 0, 0);            // 写入PDF文档            PdfWriter.getInstance(doc, fos);            // 读取图片流            BufferedImage img = null;            // 实例化图片            Image image = null;            float newHeight = 0f, newWidth = 0f;            img = ImageIO.read(new File(imagPath));            Map,Float> result = setImageWidthHeight(img.getWidth(), img.getHeight(),newWidth, newHeight);            newWidth = result.get("width");            newHeight = result.get("height");            doc.setPageSize(new Rectangle(newWidth,newHeight));            image = Image.getInstance(imagPath);            image.scaleAbsolute(new Rectangle(newWidth,newHeight));            // 添加图片到文档            doc.newPage();            doc.open();            doc.add(image);            // 关闭文档            doc.close();            changeResult = true;            System.out.println("图片转PDF成功");        } catch (Exception e) {
            System.out.println("图片转PDF失败");            e.printStackTrace();        }return  changeResult;    }/**     * word转PDF     * @param docPath     * @param pdfOutPath     * @return     */    private boolean wordToPDF(String docPath, String pdfOutPath) {
        Boolean changeResult = false;        ActiveXComponent app = null;        try{//打开word应用程序            app = new ActiveXComponent("Word.Application");            //设置word不可见            app.setProperty("Visible", false);            //获得word中所有打开的文档,返回Documents对象            Dispatch docs = app.getProperty("Documents").toDispatch();            //调用Documents对象中Open方法打开文档,并返回打开的文档对象Document            Dispatch doc = Dispatch.call(docs,                    "Open",                    docPath,                    false,                    true            ).toDispatch();            //调用Document对象的SaveAs方法,将文档保存为pdf格式            Dispatch.call(doc,                    "ExportAsFixedFormat",                    pdfOutPath,                    WORD_FORMAT_PDF       //word保存为pdf格式宏,值为17            );            //关闭文档            Dispatch.call(doc, "Close",false);            System.out.println("doc文档转PDF成功");            changeResult = true;        } catch (Exception e) {
            System.out.println("doc文档转PDF失败");            e.printStackTrace();        } finally {if (app != null) {//关闭word应用程序                app.invoke("Quit", new Variant[0]);            }
        }//如果没有这句话,winword.exe进程将不会关闭        ComThread.Release();        return changeResult;    }/**     * Excel转PDF     * @param inputFile     * @param pdfOutPath     */    private boolean excelToPDF(String inputFile, String pdfOutPath) {boolean changeResult = false;        System.out.println("启动Excel...");        long start = System.currentTimeMillis();        ActiveXComponent app = null;        Dispatch excel = null;        try {// 创建一个excel对象            app = new ActiveXComponent("Excel.Application");            // 不可见打开excel            app.setProperty("Visible", new Variant(false));            // 获取文挡属性            Dispatch excels = app.getProperty("Workbooks").toDispatch();            // 调用Documents对象中Open方法打开文档,并返回打开的文档对象Document            excel = Dispatch.call(excels, "Open", inputFile).toDispatch();            System.out.println("打开文档..." + inputFile);            System.out.println("转换文档到PDF..." + pdfOutPath);            File toFile = new File(pdfOutPath);            if (toFile.exists()) {
                toFile.delete();            }// Excel不能调用SaveAs方法            Dispatch.call(excel, "ExportAsFixedFormat", EXCEL_FORMAT_PDF, pdfOutPath);            long end = System.currentTimeMillis();            System.out.println("转换完成..用时:" + (end - start) + "ms.");            changeResult = true;        } catch (Exception e) {
            System.out.println("========Error:文档转换失败:" + e.getMessage());        } finally {
            Dispatch.call(excel, "Close", false);            System.out.println("关闭文档");            if (app != null)
                app.invoke("Quit", new Variant[]{});        }//如果没有这句话,winword.exe进程将不会关闭        ComThread.Release();                return changeResult;    }/**     * ppt转PDF     * @param inputFile     * @param pdfFile     * @return     */    private boolean pptToPDF(String inputFile, String pdfFile) {boolean changeResult = false;                System.out.println("启动PPT...");        long start = System.currentTimeMillis();        ActiveXComponent app = null;        Dispatch ppt = null;        try {// 创建一个ppt对象            app = new ActiveXComponent("PowerPoint.Application");            // 不可见打开(PPT转换不运行隐藏,所以这里要注释掉)            // app.setProperty("Visible", new Variant(false));            // 获取文挡属性            Dispatch ppts = app.getProperty("Presentations").toDispatch();            // 调用Documents对象中Open方法打开文档,并返回打开的文档对象Document            ppt = Dispatch.call(ppts, "Open", inputFile, true, true, false).toDispatch();            System.out.println("打开文档..." + inputFile);            System.out.println("转换文档到PDF..." + pdfFile);            File tofile = new File(pdfFile);            if(tofile.exists()) {
                tofile.delete();            }
            Dispatch.call(ppt, "SaveAs", pdfFile, PPT_FORMAT_PDF);            long end = System.currentTimeMillis();            System.out.println("转换完成..用时:" + (end - start) + "ms.");            changeResult = true;        } catch (Exception e) {
            System.out.println("========Error:文档转换失败:" + e.getMessage());        } finally {
            Dispatch.call(ppt, "Close");            System.out.println("关闭文档");            if (app != null)
                app.invoke("Quit", new Variant[] {});        }//如果没有这句话,winword.exe进程将不会关闭        ComThread.Release();                return changeResult;    }/**     * 设置PDF的宽高     *     * @param width     * @param height     * @param newWidth     * @param newHeight     * @return     */    private Map, Float> setImageWidthHeight(float width, float height, float newWidth, float newHeight) {float res = width / height;        if (res >= 1) { //横向            if (width > regular_width) {
                newWidth = regular_width;                newHeight = (regular_width / width) * height;            } else if (height > regular_height) {
                newHeight = regular_height;                newWidth = (regular_height / height) * width;            } else {//如果都在范围内,不做任何操作                newWidth = width;                newHeight = height;            }
        } else {if (width > vertical_regular_width) {
                newWidth = vertical_regular_width;                newHeight = (vertical_regular_width / width) * height;            } else if (height > vertical_regular_height) {
                newHeight = vertical_regular_height;                newWidth = (vertical_regular_height / height) * width;            } else {//如果都在范围内,不做任何操作                newWidth = width;                newHeight = height;            }
        }
        Map, Float> result = new HashMap, Float>();        result.put("width", newWidth);        result.put("height", newHeight);        return result;    }
}

yml配置截图哈

发票 xml 转 pdf java_发票 xml 转 pdf java_16

以上就是整个讲解和内容补充了。

提前告诉你一下:明天不发文!!!