前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >springboot实战之office文档在线预览

springboot实战之office文档在线预览

作者头像
lyb-geek
发布2019-11-27 14:26:33
7.5K0
发布2019-11-27 14:26:33
举报
文章被收录于专栏:Linyb极客之路Linyb极客之路
前言

文档在线预览在企业级应用开发也算是比较常遇见的需求了,通常处理这方面的需求大致有如下的方案,

1、购买成熟的第三方产品

比如永中DCS,其产品介绍可以查看如下链接

http://dcs.yozosoft.com/help.html

在比如idocv,其产品介绍可以查看如下链接

https://www.idocv.com/docs.html

2、自研实现文档预览服务器

标题取得高大上,常用的方法基本上也是基于第三方类库进行实现

  • 比如flash的flexpaper将文档转换为swf格式,然后使用flash在网页中浏览
  • 在比如java可以使用jodConverter+openoffice/libreoffice

3、文档预览是选择成熟第三产品还是自研?

如果公司成本预算充足,建议使用第三方成熟的产品,俗话说术业有专攻,正常专门做这方面的产品,不管是在技术上还是运维上都会比较成熟可靠,如果成本有限,还是自研吧,实现一个简单版本的文档预览服务器还是比较容易,但就是可能会采坑比较多。这边的选择只是针对文档预览,而非所有技术、产品选择都按这样选择,毕竟很多时候的自研的成本远远大于购买第三方服务,要具体情况具体分析

下边以jodconverter+LibreOffice为例,来实现一个简单的文档预览。这边为啥选LibreOffice而不选OpenOffice,其原因可以参考如下如下文章

OpenOffice与LibreOffice,哪个更适合你 https://www.linuxdashen.com/openoffice%E4%B8%8Elibreoffice%EF%BC%8C%E5%93%AA%E4%B8%AA%E6%9B%B4%E9%80%82%E5%90%88%E4%BD%A0 Apache OpenOffice 与 LibreOffice 之间的抉择 https://yq.aliyun.com/articles/81336

技术产品选型,可以从产品官方文档入手,产品的更新迭代活跃度、社区活跃度、是否易用等维度来进行考量,总归一句话不管黑猫白猫,能抓住老鼠的猫就是好猫,能够满足需求就行

正文

实现流程

安装LibreOffice

1、window环境

可以通过下方链接下载,并按提示一步一步安装

https://zh-cn.libreoffice.org/download/download/

2、centos环境

代码语言:javascript
复制
#安装文件

    yum -y install libreoffice

    #安装中文包

    yum -y install libreoffice-langpack-zh-Han*

    #安装的目录在/usr/lib64/libreoffice

通过命令行测试LibreOffice

代码语言:javascript
复制
#centos
  /usr/bin/libreoffice  --invisible --convert-to pdf  <待转换的word路径> --outdir <生成的pdf路径>

  比如:/usr/bin/libreoffice  --invisible --convert-to pdf  test.txt --outdir abc


  # windows
  soffice.exe --headless --invisible --convert-to pdf test.txt --outdir d:\abc

代码实现

1、pom.xml

代码语言:javascript
复制
<!-- office预览相关-->
    <dependency>
      <groupId>org.jodconverter</groupId>
      <artifactId>jodconverter-core</artifactId>
    </dependency>
    <dependency>
      <groupId>org.jodconverter</groupId>
      <artifactId>jodconverter-local</artifactId>
    </dependency>
    <dependency>
      <groupId>org.jodconverter</groupId>
      <artifactId>jodconverter-spring-boot-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>org.jodconverter</groupId>
      <artifactId>jodconverter-online</artifactId>
    </dependency>
    <dependency>
      <groupId>org.libreoffice</groupId>
      <artifactId>ridl</artifactId>
    </dependency>

2、application.yml

代码语言:javascript
复制
jodconverter:
  local:
    enabled: true
    office-home: ${office.home}
    port-numbers: 8100,8101,8102
    max-tasks-per-process: 100
  store:
    path: ${store.path}

其中office.home和store.path,这两个属性一个是LibreOffice的安装路径,一个是LibreOffice转换后存放文档的路径,其中这两个属性的具体内容配置在pom.xml,内容如下

代码语言:javascript
复制
<profiles>
    <profile>
      <id>win</id>
      <properties>
        <office.home>D:/Program Files/LibreOffice</office.home>
        <store.path>D:/data/preview</store.path>
      </properties>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
    </profile>
    <profile>
      <id>linux</id>
      <properties>
        <office.home>/usr/lib64/libreoffice</office.home>
        <store.path>/data/preview</store.path>
      </properties>
      <activation>
        <activeByDefault>false</activeByDefault>
      </activation>
    </profile>
  </profiles>

通过maven的profile来指定环境,默认是window环境,如果要切换到linux环境,则打包是执行

mvn clean package -P linux

或者打包时,改下pom.xml,把默认环境切换为linux

3、转换文档的核心代码

代码语言:javascript
复制
@Service
@Slf4j
public class PreviewServiceImpl implements PreviewService {

  @Value("${jodconverter.store.path}")
  private String storePath;

  @Autowired
  private DocumentConverter documentConverter;

  @Override
  public FileConvertResultDTO convertFile2pdf(File sourceFile,String fileExt) {
    FileConvertResultDTO fileConvertResultDTO = new FileConvertResultDTO();
    try {
      fileExt = fileExt.toLowerCase();
      String fileName = FileUtil.getWithoutExtension(sourceFile.getName());
      String targetFileExt = getTargetFileExt(fileExt);
      File targetFile = new File(storePath+ FileUtil.SLASH_ONE + fileName + FileUtil.DOT + targetFileExt);
      documentConverter.convert(sourceFile).as(DefaultDocumentFormatRegistry.getFormatByExtension(fileExt))
          .to(targetFile).as(DefaultDocumentFormatRegistry.getFormatByExtension(targetFileExt)).execute();
      fileConvertResultDTO.setStatus("success");
      fileConvertResultDTO.setTargetFileName(targetFile.getName());
    } catch (OfficeException e) {
      log.error("convertFile2pdf error : " + e.getMessage(),e);
      fileConvertResultDTO.setStatus("fail");
    }
    return fileConvertResultDTO;

  }

  @Override
  public FileConvertResultDTO convertInputStream2pdf(InputStream in, String fileName, String fileExt) {
    FileConvertResultDTO fileConvertResultDTO = new FileConvertResultDTO();
    try {
      fileExt = fileExt.toLowerCase();
      fileName = FileUtil.getWithoutExtension(fileName);
      String targetFileExt = getTargetFileExt(fileExt);
      File targetFile = new File(storePath+ FileUtil.SLASH_ONE + fileName + FileUtil.DOT + targetFileExt);
      documentConverter.convert(in).as(DefaultDocumentFormatRegistry.getFormatByExtension(fileExt))
          .to(targetFile).as(DefaultDocumentFormatRegistry.getFormatByExtension(targetFileExt)).execute();
      fileConvertResultDTO.setStatus("success");
      fileConvertResultDTO.setTargetFileName(targetFile.getName());
    } catch (OfficeException e) {
      log.error("convertInputStream2pdf error : " + e.getMessage(),e);
      fileConvertResultDTO.setStatus("fail");
    }
    return fileConvertResultDTO;
  }

  /**
   * 获取想要转换的格式类型
   * @return
   */
  private String getTargetFileExt(String originFileExt){
     if(Constants.fileType2Htmls.contains(originFileExt)){
       return FileUtil.HTML;
     }
     return FileUtil.PDF;
  }

  @PostConstruct
  private void init(){
    File targetDir = new File(storePath);
    if(!targetDir.exists()){
      targetDir.mkdirs();
    }
  }
}

4、拉取office服务器文档代码

代码语言:javascript
复制
@GetMapping(value="/readFile")
  public ResponseEntity<byte[]> readFile(String fileName){
    if(StringUtils.isBlank(fileName)){
      log.warn("fileName is blank");
      return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
    }

    String fileExt = FileUtil.getExtension(fileName);
    if(StringUtils.isBlank(fileExt)){
      fileName = fileName + FileUtil.PDF;
    }
    String filePath = storePath + FileUtil.SLASH_ONE + fileName;
    File file = new File(filePath);


    if(!file.exists()){
        log.warn("fileName:{} is not found",fileName);
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }

    try {
      //判断文件类型
      String mimeType = URLConnection.guessContentTypeFromName(file.getName());
      if(mimeType == null) {
        mimeType = "application/octet-stream";
      }
      response.setContentType(mimeType);

      //设置文件响应大小
      response.setContentLengthLong(file.length());

      byte[] bytes = FileUtil.readFileToByteArray(file);
      response.getOutputStream().write(bytes);
      return new ResponseEntity<>(bytes,HttpStatus.OK);
    } catch (IOException e) {
      log.error("readFile error:"+e.getMessage(),e);
    }
    return new ResponseEntity<>(HttpStatus.EXPECTATION_FAILED);

  }

5、测试验证

测试步骤按上方的流程图来测试 a、上传文档

b、点击确定按钮,进行跳转预览

参考文档

https://www.libreofficechina.org/

文档在线预览方案

https://blog.csdn.net/xiaqingxue930914/article/details/81121581

SpringBoot使用LibreOffice转换PDF

https://segmentfault.com/a/1190000015129654

总结

java版的office文档预览,本质上就利用jodconverter去连接openoffice或libreoffice服务,相当于我们自己实现的office服务器本质上算是一个openoffice或libreoffice代理服务器。在实现过程中,当excel转换pdf时,会存在一些坑点,比如excel的列的宽度大的时候生成的pdf会自动换行,有多个sheet页的时候默认也只能生成出来一个。解决的方案是,当遇到文档类型为excel时,就不要转换为pdf格式,而是转换为html格式

demo链接

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-office-preview

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-11-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linyb极客之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 正文
    • 实现流程
      • 安装LibreOffice
        • 通过命令行测试LibreOffice
          • 代码实现
            • 参考文档
              • 总结
                • demo链接
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档