1. 简介
在日常开发中,经常会遇到需要预览附件的需求,如果附件类型为图片、文本、PDF或者网页文件,则直接可以在浏览器预览;如果附件类型为Word、Excel、PPT等文件,则需要通过工具转换为PDF后在浏览器预览。
本博客使用LibreOffice和Hutool实现文件预览简单示例。
LibreOffice官网:https://zh-cn.libreoffice.org/
2. 安装Libreoffice
- Windows安装
- 下载介质:https://zh-cn.libreoffice.org/download/libreoffice/
- 安装时依次点击下一步即可(注意记录安装目录,在项目配置文件中需要配置)
- Linux安装
- yum安装
yum -y install libreoffice # 安装后的目录为:/usr/lib64/libreoffice
- 乱码问题
# 上传Windows的C:\Windows\Fonts目录中的字体到Linux的/usr/share/fonts/windows目录 # 执行授权 chmod 644 /usr/share/fonts/windows/* && fc-cache -fv
- 官网安装手册https://zh-cn.libreoffice.org/get-help/install-howto/
3. 示例代码
- 创建工程
- 修改pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.c3stones</groupId>
<artifactId>spring-boot-libreoffice-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-libreoffice-demo</name>
<description>Spring Boot Libreoffice Demo</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>org.jodconverter</groupId>
<artifactId>jodconverter-spring-boot-starter</artifactId>
<version>4.4.2</version>
</dependency>
<dependency>
<groupId>org.jodconverter</groupId>
<artifactId>jodconverter-local</artifactId>
<version>4.4.2</version>
</dependency>
<dependency>
<groupId>org.jodconverter</groupId>
<artifactId>jodconverter-core</artifactId>
<version>4.4.2</version>
</dependency>
<dependency>
<groupId>org.libreoffice</groupId>
<artifactId>ridl</artifactId>
<version>7.2.0</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.13</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 创建配置文件application.yml
server:
port: 8080
spring:
thymeleaf:
prefix: classpath:/view/
suffix: .html
encoding: UTF-8
servlet:
content-type: text/html
cache: false
servlet:
multipart:
max-file-size: 50MB
max-request-size: 50MB
# 附件预览
jodconverter:
local:
enabled: true
# # 设置LibreOffice目录
officeHome: D:\LibreOffice
# # CentOS 下安装 LibreOffice:
# # 1、安装:yum -y install libreoffice
# # 2、配置:officeHome: /usr/lib64/libreoffice
# # Linux 中文字体乱码解决:
# # 1、上传 C:\Windows\Fonts 下的字体到 /usr/share/fonts/windows 目录
# # 2、执行命令: chmod 644 /usr/share/fonts/windows/* && fc-cache -fv
# # 监听端口,开启多个LibreOffice进程,每个端口对应一个进程
# portNumbers: 8100,8101,8102
portNumbers: 2002
# # LibreOffice进程重启前的最大进程数
maxTasksPerProcess: 10
# # 任务在转换队列中的最大生存时间,默认30s
taskQueueTimeout: 30
- 创建Controller
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.servlet.http.HttpServletResponse;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.jodconverter.core.DocumentConverter;
import org.jodconverter.core.office.OfficeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
/**
* 附件预览Controller
*
* @author CL
*
*/
@Controller
@RequestMapping(value = "/file")
public class FilePreviewController {
private static final Logger log = LoggerFactory.getLogger(FilePreviewController.class);
@Autowired
private DocumentConverter documentConverter;
/**
* 跳转到附件预览和下载页面
*
* @return
*/
@RequestMapping(value = "")
public String index() {
return "fileIndex";
}
/**
* 附件预览
*
* @param file 附件
* @param response
*/
@RequestMapping(value = "/preview")
@ResponseBody
public void preview(MultipartFile file, HttpServletResponse response) {
if (file == null) {
return;
}
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = file.getInputStream();
outputStream = response.getOutputStream();
String fileName = file.getOriginalFilename();
if (StrUtil.endWithAnyIgnoreCase(fileName, ".doc", ".docx", ".xls", ".xlsx", ".csv", ".ppt", ".pptx")) {
// 转为PDF
documentConverter.convert(inputStream).to(outputStream)
.as(documentConverter.getFormatRegistry().getFormatByExtension("pdf")).execute();
} else if (StrUtil.endWithAnyIgnoreCase(fileName, ".pdf", ".txt", ".xml", ".md", ".json", ".html", ".htm",
".gif", ".jpg", ".jpeg", ".png", ".ico", ".bmp")) {
IoUtil.copy(inputStream, outputStream);
} else {
outputStream.write("暂不支持预览此类型附件".getBytes());
}
} catch (IORuntimeException e) {
log.error("附件预览IO运行异常:{}", e.getMessage());
} catch (IOException e) {
log.error("附件预览IO异常:{}", e.getMessage());
} catch (OfficeException e) {
log.error("附件预览Office异常:{}", e.getMessage());
} finally {
IOUtils.closeQuietly(inputStream);
}
IoUtil.writeUtf8(outputStream, true);
}
}
- 创建附件预览示例页面
在resources下新建目录view,在view目录下新建页面:fileIndex.html
。
<html>
<head>
<title>附件预览和下载</title>
</head>
<body>
<h5>支持附件类型为:.doc, .docx, .xls, .xlsx, .csv, .ppt, .pptx, .pdf, .txt, .xml, .md, .json, .gif, .jpg, .jpeg, .png, .ico, .bmp</h5>
<form id="fileForm" action="" method="post" enctype="multipart/form-data">
<i style="color: red">*</i> 上传附件:<input id="file" name="file" type="file" /><br/>
</form>
<button onclick="preview()">预览</button>
</body>
</html>
<script>
// 预览方法
function preview() {
// 检查是否为空和大小限制
var file = document.getElementById('file').files[0];
if (!file) {
alert("附件不能为空");
return;
}
var fileSize = file.size;
if (fileSize > 50 * 1024 * 1024) {
alert("最大支持附件大小为 50MB");
return;
}
// 提交表单
var fileForm = document.getElementById('fileForm');
fileForm.action = "[[@{/}]]file/preview";
fileForm.submit();
}
</script>
- 创建启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 启动类
*
* @author CL
*
*/
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4. 测试
- 启动项目
- 浏览器访问:http://127.0.0.1:8080/file
- 测试预览图片
- 测试预览文本
- 测试预览Word文件
- 测试预览PPT文件
- 测试预览PDF