一、前言

之前写过一篇文章关于上传目录文件:uni-app系统目录文件上传(非只图片和视频)解决方案,这次来解决文件预览问题。

uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、H5、以及各种小程序(微信/支付宝/百度/头条/QQ/钉钉)等多个平台。在做业务系统时,不可避免会遇到文件在线预览的需求。这里的文件包括PDF、Word、Excel、PPT、图片等。而在线预览不是下载后再用本地软件或浏览器打开预览,而是直接通过文件流的形式查看。本方案主要解决在线预览问题,以及在uni-app开发过程中遇到一系列问题

如果有欠缺的地方,或者有更好的方案,还望各位码友多提意见,多多交流,文章最后可以加我。

文件预览,首先会想到pdf预览,前端做pdf预览,首先也会想到pdf.js,那我们就从pdf.js说起。

二、PDF预览

pdf.js开源地址和在线例子GithubOnline Demo

2.1 使用方法一

  • 下载插件包,下载地址

  • 解压,拷贝build和web目录到项目hybrid->html目录下,参考uni-app中web-view用法

  • 新建vue组件file-preview.vue

    • viewerUrl:前端本地viewer.html页面地址
    • fileUrl:文件流访问地址,参考《三、文件流服务
<view><web-view :src="allUrl">web-view>view>template><script>import globalConfig from '@/config'export default {  data() {return {viewerUrl: '/hybrid/html/web/viewer.html',// viewerUrl: globalConfig.baseUrl + '/pdf/web/viewer.html',    allUrl: ''   }  },  onLoad(options) {let fileUrl = encodeURIComponent(    globalConfig.baseUrl + '/api/attachment?name=' + options.name + '&url=' + options.url)this.allUrl = this.viewerUrl + '?file=' + fileUrl  } }script>
  • 效果

    • h5端 显示正常
    • Android端 显示模糊,并且中文显示不全,其中模糊问题是模拟器原因;但是中文显示问题是真,调试出现两个警告。第二个警告pdf.js默认不显示电子签章(数字签名)问题,查了很多资料也没解决,各位码友有遇到过并且解决了吗?
    • iOS端 出现跨域问题,并且调试出现无法访问pdf.js国际化文件
  • 解决 基于Android和iOS预览出现的各种问题,最根本原因是viewer.html文件放到前端导致加载资源文件丢失问题。针对这个问题,我就在想能不能直接放在spring后端作为静态资源访问文件呢?于是有了下面的方法。

2.2 使用方法二

  • 在基于spring mvc的后端代码中,将插件包的build和web文件夹放到webapp下面(新建pdf文件夹),spring boot架构的后端项目同理,放到静态资源目录

  • 在xml文件中配置静态文件访问

  • 修改前端组件file-preview.vue中的viewerUrl,其中globalConfig.baseUrl为代理后端地址的baseUrl。如Vue中proxyTablenginx代理

viewerUrl: globalConfig.baseUrl + '/pdf/web/viewer.html'
  • 修改后效果

    • iOS端
    • Android端 模糊是模拟器原因,在真机上测试通过

三、文件流服务

3.1 方法一:tomcat配置

配置tomcat的config目录下的server.xml,在最后的中间添加如下:

port=8090 文件访问服务端口docBase="/root/" 文件存储目录 服务器上文件会存储到/root/fileData/目录下 文件访问地址为:http://ip地址:8090/fileData/文件名

<Service name="fileData">  

    <Connector port="8090" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />    <Engine name="fileData" defaultHost="localhost">  

    <Host name="localhost" appBase="webapps"  unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">  

        <Context path="" docBase="/root/" debug="0" reloadable="false"/>      Host>      Engine>Service>

3.2 方法二:写代码获取服务器文件进行转换

直接上代码

读取目录文件,转换为二进制流前端组件file-preview.vue中fileUrl/api/attachment

核心代码

ios = new FileInputStream(sourceFile);os = response.getOutputStream();int read = 0;byte[] buffer = new byte[1024 * 1024];while ((read = ios.read(buffer)) != -1) {    os.write(buffer, 0, read);}os.flush();

完整代码

@RequestMapping(value = "/api/attachment", method = RequestMethod.GET)    public void getFileBytes(@RequestParam("name") String name, @RequestParam("url") String url, HttpServletRequest request, HttpServletResponse response) {        response.reset();        response.setContentType("application/octet-stream");        response.setCharacterEncoding("utf-8");        response.setHeader("Content-Disposition", "attachment;filename=" + name);

        AttachmentVO attachmentVO = new AttachmentVO();        FileInputStream ios = null;        OutputStream os = null;        try {            name = CharsetUtils.toUTF_8(name);            url = CharsetUtils.toUTF_8(url);

            attachmentVO.setUrl(url);            attachmentVO.setName(name);            File sourceFile = getDictionaryFile(attachmentVO, request);            if (null == sourceFile) {//                throw new HttpResponseException(300, "附件不存在!");                return;            }

            /**             * 判断文件类型             */            /* 获得文件名后缀 */            String ext = "";            if (!"".equals(url) && url.contains(".")) {                ext = url.substring(url.lastIndexOf(".") + 1, url.length()).toUpperCase();            }            /* 根据文件类型不同进行预览 */            /* 预览pdf */            if ("PDF".equals(ext)) {                response.setContentType("application/pdf");            }

            /**             * 将文件写入输出流,显示在界面上,实现预览效果             */            ios = new FileInputStream(sourceFile);            os = response.getOutputStream();            int read = 0;            byte[] buffer = new byte[1024 * 1024];            while ((read = ios.read(buffer)) != -1) {                os.write(buffer, 0, read);            }            os.flush();        } catch (Exception e) {            e.printStackTrace();            try {                if (null != ios) {                    ios.close();                }                if (null != os) {                    os.close();                }            } catch (IOException ex) {                ex.printStackTrace();            }        }    }

四、office文件(Word、Excel、PPT)预览

原理:搭建OpenOffice服务,将文件转换为pdf,在使用pdf.js预览

4.1 搭建openOffice服务

  • 下载Apache_OpenOffice

  • 解压

tar xzvfm Apache_OpenOffice_xxx.tar.gzcd zh-CN/RPMSrpm -ivh *rpm
  • 运行
# 127.0.0.1只能本机使用该服务/opt/openoffice4/program/soffice "-accept=socket,host=127.0.0.1,port=8100;urp;" -headless -nofirststartwizard &# 0.0.0.0远程ip能使用/opt/openoffice4/program/soffice "-accept=socket,host=0.0.0.0,port=8100;urp;" -headless -nofirststartwizard &

4.2 集成java

  • 在pom.xml添加jar包
<dependency>    <groupId>org.openofficegroupId>    <artifactId>juhartifactId>    <version>4.1.2version>dependency><dependency>    <groupId>org.openofficegroupId>    <artifactId>jurtartifactId>    <version>4.1.2version>dependency><dependency>    <groupId>org.openofficegroupId>    <artifactId>ridlartifactId>    <version>4.1.2version>dependency><dependency>    <groupId>org.openofficegroupId>    <artifactId>unoilartifactId>    <version>4.1.2version>dependency><dependency>    <groupId>com.artofsolvinggroupId>    <artifactId>jodconverterartifactId>    <version>2.2.2version>dependency>

注意:jodconverter需要单独下载2.2.2版本,之前的版本都不行,而且maven中央仓库没有2.2.2版本。然后再单独导入。下载地址:https://sourceforge.net/projects/jodconverter/files/

单独导入

mvn install:install-file -Dfile="jodconverter-2.2.2.jar" -DgroupId=com.artofsolving -DartifactId=jodconverter -Dversion=2.2.2 -Dpackaging=jar
  • 转换代码

核心代码

connection = new SocketOpenOfficeConnection(openofficeHost, openofficePort);connection.connect();DocumentConverter converter = new StreamOpenOfficeDocumentConverter(connection);converter.convert(sourceFile, pdfFile);

完整代码

/* 利用openOffice将office文件转换为pdf格式, 然后预览doc, docx, xls, xlsx, ppt, pptx */if ("DOC".equals(ext) || "DOCX".equals(ext) || "XLS".equals(ext) || "XLSX".equals(ext) || "PPT".equals(ext) || "PPTX".equals(ext)) {    /* filePath在数据库中是不带文件后缀的, 由于jodConverter必须要识别后缀,所以将服务器中的文件重命名为带后缀的文件 */    // File docFileWithExt = new File(filePath + "." + ext.toLowerCase()); //带后缀的文件    // docFile.renameTo(docFileWithExt);    /* 转换之后的文件名 */    String filePath = sourceFile.getPath();    File pdfFile;    if (filePath.contains(".")) {        pdfFile = new File(filePath.substring(0, filePath.lastIndexOf(".")) + ".pdf");    } else {        pdfFile = new File(filePath + ".pdf");    }

    /* 判断即将要转换的文件是否真实存在 */    if (sourceFile.exists()) {        /* 判断该文件是否已经被转换过,若已经转换则直接预览 */        if (!pdfFile.exists()) {            OpenOfficeConnection connection;            /* 打开OpenOffice连接 */            try {                connection = new SocketOpenOfficeConnection(openofficeHost, openofficePort);                connection.connect();            } catch (java.net.ConnectException e) {                log.warn("openOffice未连接,正在重新连接...");

                // 启动OpenOffice的服务                String command = openofficeInstallPath + "program/soffice -headless -accept=\"socket,host=127.0.0.1,port=8100;urp;\" -nofirststartwizard";                Runtime.getRuntime().exec(command);

                Thread.sleep(1000);

                connection = new SocketOpenOfficeConnection(8100);                connection.connect();

                log.warn("openOffice重新连接成功!!!");            }

            try {                // DocumentConverter converter = new OpenOfficeDocumentConverter(connection);                DocumentConverter converter = new StreamOpenOfficeDocumentConverter(connection);                converter.convert(sourceFile, pdfFile);                connection.disconnect();

//                            filePath = pdfFile.getPath(); // 文件转换之后的路径                sourceFile = pdfFile;                response.setContentType("application/pdf");            } catch (OpenOfficeException e) {                e.printStackTrace(); // 读取转换文件失败                log.info("读取转换文件失败!!!");                return;            } finally { // 发生exception时, connection不会自动切断, 程序会一直挂着                try {                    if (connection != null) {                        connection.disconnect();                    }                } catch (Exception e) {                    e.printStackTrace();                }            }        } else {//                        filePath = pdfFile.getPath(); // 文件已经转换过            sourceFile = pdfFile;            response.setContentType("application/pdf");        }    } else {        log.info("需要预览的文档在服务器中不存在!!!");        // 文件不存在,直接返回        return;    }}

五、图片预览

5.1 后端文件流

/* 预览图片 */if ("PNG".equals(ext) || "JPEG".equals(ext) || "JPG".equals(ext)) {    response.setContentType("image/jpeg");}/* 预览BMP格式的文件 */if ("BMP".equals(ext)) {    response.setContentType("image/bmp");}/* 预览GIF格式的文件 */if ("GIF".equals(ext)) {    response.setContentType("image/gif");}

5.2 前端预览

采用uni-app的uni.previewImage接口fileUrl:为文件流访问地址

// 预览图片uni.previewImage({  urls: [fileUrl],  longPressActions: {    itemList: ['发送给朋友', '保存图片', '收藏'],    success: function(data) {      console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片');    },    fail: function(err) {      console.log(err.errMsg);    }  }})

附:完整文件流代码

@RequestMapping(value = "/api/attachment", method = RequestMethod.GET)public void getFileBytes(@RequestParam("name") String name, @RequestParam("url") String url, HttpServletRequest request, HttpServletResponse response) {    response.reset();    // 解决IFrame拒绝的问题,无效//        response.setHeader("X-Frame-Options", "SAMEORIGIN");    response.setContentType("application/octet-stream");    response.setCharacterEncoding("utf-8");    response.setHeader("Content-Disposition", "attachment;filename=" + name);

    AttachmentVO attachmentVO = new AttachmentVO();    FileInputStream ios = null;    OutputStream os = null;    try {        name = CharsetUtils.toUTF_8(name);        url = CharsetUtils.toUTF_8(url);

        attachmentVO.setUrl(url);        attachmentVO.setName(name);        File sourceFile = getDictionaryFile(attachmentVO, request);        if (null == sourceFile) {//                throw new HttpResponseException(300, "附件不存在!");            return;        }

        /**          * 判断文件类型          */        /* 获得文件名后缀 */        String ext = "";        if (!"".equals(url) && url.contains(".")) {            ext = url.substring(url.lastIndexOf(".") + 1, url.length()).toUpperCase();        }        /* 根据文件类型不同进行预览 */        /* 预览图片 */        if ("PNG".equals(ext) || "JPEG".equals(ext) || "JPG".equals(ext)) {            response.setContentType("image/jpeg");        }        /* 预览BMP格式的文件 */        if ("BMP".equals(ext)) {            response.setContentType("image/bmp");        }        /* 预览GIF格式的文件 */        if ("GIF".equals(ext)) {            response.setContentType("image/gif");        }        /* 预览pdf */        if ("PDF".equals(ext)) {            response.setContentType("application/pdf");        }

        /* 利用openOffice将office文件转换为pdf格式, 然后预览doc, docx, xls, xlsx, ppt, pptx */        if ("DOC".equals(ext) || "DOCX".equals(ext) || "XLS".equals(ext) || "XLSX".equals(ext) || "PPT".equals(ext) || "PPTX".equals(ext)) {            /* filePath在数据库中是不带文件后缀的, 由于jodConverter必须要识别后缀,所以将服务器中的文件重命名为带后缀的文件 */            // File docFileWithExt = new File(filePath + "." + ext.toLowerCase()); //带后缀的文件            // docFile.renameTo(docFileWithExt);            /* 转换之后的文件名 */            String filePath = sourceFile.getPath();            File pdfFile;            if (filePath.contains(".")) {                pdfFile = new File(filePath.substring(0, filePath.lastIndexOf(".")) + ".pdf");            } else {                pdfFile = new File(filePath + ".pdf");            }

            /* 判断即将要转换的文件是否真实存在 */            if (sourceFile.exists()) {                /* 判断该文件是否已经被转换过,若已经转换则直接预览 */                if (!pdfFile.exists()) {                    OpenOfficeConnection connection;                    /* 打开OpenOffice连接 */                    try {                        connection = new SocketOpenOfficeConnection(openofficeHost, openofficePort);                        connection.connect();                    } catch (java.net.ConnectException e) {                        log.warn("openOffice未连接,正在重新连接...");

                        // 启动OpenOffice的服务                        String command = openofficeInstallPath + "program/soffice -headless -accept=\"socket,host=127.0.0.1,port=8100;urp;\" -nofirststartwizard";                        Runtime.getRuntime().exec(command);

                        Thread.sleep(1000);

                        connection = new SocketOpenOfficeConnection(8100);                        connection.connect();

                        log.warn("openOffice重新连接成功!!!");                    }

                    try {                        // DocumentConverter converter = new OpenOfficeDocumentConverter(connection);                        DocumentConverter converter = new StreamOpenOfficeDocumentConverter(connection);                        converter.convert(sourceFile, pdfFile);                        connection.disconnect();

//                            filePath = pdfFile.getPath(); // 文件转换之后的路径                        sourceFile = pdfFile;                        response.setContentType("application/pdf");                    } catch (OpenOfficeException e) {                        e.printStackTrace(); // 读取转换文件失败                        log.info("读取转换文件失败!!!");                        return;                    } finally { // 发生exception时, connection不会自动切断, 程序会一直挂着                        try {                            if (connection != null) {                                connection.disconnect();                            }                        } catch (Exception e) {                            e.printStackTrace();                        }                    }                } else {//                        filePath = pdfFile.getPath(); // 文件已经转换过                    sourceFile = pdfFile;                    response.setContentType("application/pdf");                }            } else {                log.info("需要预览的文档在服务器中不存在!!!");                // 文件不存在,直接返回                return;            }        }

        /**          * 将文件写入输出流,显示在界面上,实现预览效果          */        ios = new FileInputStream(sourceFile);        os = response.getOutputStream();        int read = 0;        byte[] buffer = new byte[1024 * 1024];        while ((read = ios.read(buffer)) != -1) {            os.write(buffer, 0, read);        }        os.flush();    } catch (Exception e) {        e.printStackTrace();        try {            if (null != ios) {                ios.close();            }            if (null != os) {                os.close();            }        } catch (IOException ex) {            ex.printStackTrace();        }    }}
赞助作者

doc文件在线预览 vue_跨平台(uniapp)文件在线预览解决方案相关推荐

  1. koa中上传文件到阿里云oss实现点击在线预览和下载

    比较好的在线预览的方法: 跳转一个新的页面,里面放一个iframe标签,或者object标签 <iframesrc="xxx"></iframe> < ...

  2. 文件在线预览功能(office文件)

    由于项目的功能需要看了一下文件预览的功能实现,主要是看office的word,excel,ppt这些的在线预览. 比较常见的是以下两种: 一.通过iframe直接引用微软提供的方法(最简单) < ...

  3. php+预览和下载pdf文件,vue实现在线预览pdf文件和下载(pdf.js)

    最近做项目遇到在线预览和下载pdf文件,试了多种pdf插件,例如jquery.media.js(ie无法直接浏览) 最后选择了pdf.js插件(兼容ie10及以上.谷歌.安卓,苹果) 强烈推荐改插件, ...

  4. pdf文件如何在安卓手机端不用下载在线预览

    由于H5手机端页面,苹果ios手机端支持在线预览,而安卓手机端不行. 解决方案: 使用pdf.js插件. 官网地址:https://mozilla.github.io/pdf.js/ 第一步:下载整个 ...

  5. 基于Web的文件管理系统,支持Office、WPS预览/编辑、在线解压缩、文件分享、文件加密、远程存储、远程文件推送、秒传、断点

    基于Web的文件管理系统,支持权限管理.历史版本管理.Office预览/编辑.WPS预览/编辑.在线解压缩.文件分享.文件加密.远程存储.远程文件推送.秒传.断点续传.智能搜索.文件备注.本地自动备份 ...

  6. html 在线预览pdf功能,html中在线预览pdf文件之pdf在线预览插件

    html中在线预览pdf文件之pdf在线预览插件 最近遇到一个需求,要在html页面查看pdf生成的pdf文件!javascript 翻来覆去找到两种办法 ,最后采用了jquery.media.js插 ...

  7. uni-app开发在线预览pdf(h5/app)

    本人亲测可用哦! 核心:pdf插件+web-view pdf插件获取地址 https://github.com/DonnaLh/-pdf-/tree/master 注意:这个链接里面的文件都是需要的哦 ...

  8. 跨平台Office文档预览原生插件,非腾讯X5,支持离线,稳定高可用

    引言 2023年4月13日零时起,腾讯浏览服务内核文档能力正式下线,要实现真正离线文档预览,于是有了这边文章. 前面写了多篇关于<跨平台文件在线预览解决方案>,不管使用pdf.js.Lib ...

  9. java预览openoffice_web使用openoffice实现在线预览office文档

    最近搞web项目,使用框架struts+spring+jpa实现,做到项目里面一个在线预览功能,试过无数的方法,最后得到了一个非常使用的方法,这方法也是我看过多篇博客的出来的,仅限参考. 效果图如下: ...

最新文章

  1. 以后版本网卡命名规则
  2. webstorm怎么跑项目_快讯!明年厦门中考体育项目定了!初三家长抽的!其他地市抽到啥?...
  3. 如何在Hibernate中维护表的历史记录
  4. 为提升效率,阿里取消周报制度?醒醒吧,自动化报表才是出路
  5. Xml+Xsl:内容与形式的完美分离
  6. python config方法_Python config.Configuration方法代码示例
  7. Requirement already satisfied
  8. 【计算机图形学】OpenGL递归实现光线追踪
  9. gossiping路由协议仿真
  10. 小坤二次元炫酷导航HTML源码
  11. qt5的configure选项说明(2)
  12. s/μs/ns/ps与Hz/KHz/MHz/GHz换算关系
  13. 《热浪球爱战》首映 周秀娜现场超低胸打排球
  14. 实验二实验结论实验总结与体会
  15. 利用Python爬虫获取招聘网站职位信息
  16. Markdown插入图片操作
  17. win10安装程序无法正常启动
  18. matlab删除行向量里面相同的数据
  19. pci总线协议学习笔记——PCI总线基本概念
  20. 开源文件文档在线预览项目解决方案kkFileView本地搭建运行与Docker部署运行

热门文章

  1. JavaScript学习(六十一)—json字符串的解析和JS 对象的序列化
  2. HBuilderX是什么
  3. Bitcoin是什么意思
  4. 有房贷的房子怎么卖?
  5. 这5条职场心机,句句真实,引发深思
  6. 电影里看到程序员一台电脑装2个显示屏,这样有什么优点?
  7. 12年的电脑,太卡了,有什么办法解决吗?
  8. LaTex ——P4 字体字号设置
  9. 排序算法(二)--选择排序法
  10. 用信号量实现进程互斥、同步、前驱关系