基于 SpringBoot 支持任意文件在线预览功能
在现代Web应用中,文件的在线预览功能是一个非常重要的需求。通过在线预览,用户可以直接在浏览器中查看文件内容,无需下载到本地再打开。本文将详细介绍如何在SpringBoot项目中集成kkFileView,实现任意文件的在线预览功能。
kkFileView 是一款开源的文件在线预览工具,主要用于在Web应用中实现各种文件的在线预览功能。它基于Spring Boot进行开发,支持多种文件格式的预览,用户无需下载文件即可在浏览器中直接查看文件内容。
运行效果:
若想获取项目完整代码以及其他文章的项目源码,且在代码编写时遇到问题需要咨询交流,欢迎加入下方的知识星球。
kkFileView的主要特性:
-
多种文件格式支持:支持包括Office文档(Word、Excel、PowerPoint)、PDF、图片、文本文件、音视频文件等多种类型的文件预览。
-
高效的文件转换:利用Apache POI、PDFBox、Aspose等第三方库,实现文件的高效转换和预览。
-
集成简单:基于Spring Boot框架,提供了简单易用的API,方便与现有Spring Boot项目集成。
-
可定制性强:支持自定义预览模式,用户可以根据需求对预览效果进行个性化配置。
-
扩展性好:支持插件式扩展,可以轻松添加新的文件类型支持。
kkFileView支持的文件类型:
-
支持 doc, docx, xls, xlsx, xlsm, ppt, pptx, csv, tsv, dotm, xlt, xltm, dot, dotx,xlam, xla 等 Office 办公文档
-
支持 wps, dps, et, ett, wpt 等国产 WPS Office 办公文档
-
支持 odt, ods, ots, odp, otp, six, ott, fodt, fods 等OpenOffice、LibreOffice 办公文档
-
支持 vsd, vsdx 等 Visio 流程图文件
-
支持 wmf, emf 等 Windows 系统图像文件
-
支持 psd 等 Photoshop 软件模型文件
-
支持 pdf ,ofd, rtf 等文档
-
支持 xmind 软件模型文件
-
支持 bpmn 工作流文件
-
支持 eml 邮件文件
-
支持 epub 图书文档
-
支持 obj, 3ds, stl, ply, gltf, glb, off, 3dm, fbx, dae, wrl, 3mf, ifc, brep, step, iges, fcstd, bim 等 3D 模型文件
-
支持 dwg, dxf 等 CAD 模型文件
-
支持 txt, xml(渲染), md(渲染), java, php, py, js, css 等所有纯文本
-
支持 zip, rar, jar, tar, gzip, 7z 等压缩包
-
支持 jpg, jpeg, png, gif, bmp, ico, jfif, webp 等图片预览(翻转,缩放,镜像)
-
支持 tif, tiff 图信息模型文件
-
支持 tga 图像格式文件
-
支持 svg 矢量图像格式文件
-
支持 mp3,wav,mp4,flv 等音视频格式文件
-
支持 avi,mov,rm,webm,ts,rm,mkv,mpeg,ogg,mpg,rmvb,wmv,3gp,ts,swf 等视频格式转码预览
-
支持 dcm 等医疗数位影像预览
-
支持 drawio 绘图预览
kkFileView 安装
在开始 SpringBoot 项目之前,我们首先需要在服务器上安装 kkFileView。以下是详细的安装步骤:
-
下载 kkFileView 安装包
首先,使用
wget
命令直接下载 kkFileView 4.0.0 的安装包:wget https://kkfileview.keking.cn/kkFileView-4.0.0.tar.gz
2.解压安装包
下载完成后,使用以下命令解压安装包:
tar -zxvf kkFileView-4.0.0.tar.gz
3.修改配置文件
解压完成后,进入配置文件目录并修改
application.properties
配置文件:cd kkFileView-4.0.0/config vi application.properties
将配置文件中的
server.address
修改为你当前虚拟机的 IP 地址。4.启动 kkFileView
进入
bin
目录,执行启动脚本启动 kkFileView:cd kkFileView-4.0.0/bin sh startup.sh
启动后,可以通过以下命令查看日志,确认是否启动成功:
sh showlog.sh
如果日志中没有报错信息,则表示 kkFileView 已经成功启动。
项目结构
项目的基本结构如下:
├── src │ ├── main │ │ ├── java │ │ │ └── com.icoderoad.filepreview │ │ │ ├── controller │ │ │ │ └── FileController.java │ │ │ ├── config │ │ │ │ └── WebConfig.java │ │ │ ├── service │ │ │ │ └── FileService.java │ │ │ └── FilepreviewApplication.java │ │ ├── resources │ │ │ ├── templates │ │ │ │ └── upload.html │ │ │ │ └── preview.html │ │ │ └── application.yml │ └── pom.xml
引入依赖
首先,在 pom.xml
中添加kkFileView的依赖以及其他必要的依赖:
<dependencies>
<!-- Spring Boot 核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Thymeleaf 模板引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- 其他依赖 -->
</dependencies>
配置文件
在 application.yml
文件中,添加kkFileView相关配置:
server:
port: 8080
file-preview:
file-save-dir: /Users/icoderoad/code/java/filepreview/src/main/resources/uploadfile/ # 本地文件保存路径
base-url: http://localhost:8080/files # 文件的 HTTP 访问路径
后端代码实现
使用 WebMvcConfigurer
映射静态资源
你可以通过自定义 WebMvcConfigurer
来手动映射静态资源路径:
package com.icoderoad.filepreview.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
// 从配置文件中读取静态资源路径
@Value("${file-preview.file-save-dir}")
private String fileStoragePath;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 映射资源路径
registry.addResourceHandler("/files/**")
.addResourceLocations("file:" + fileStoragePath);
}
}
这样就可以通过 http://localhost:8080/files/example.txt
来访问文件了。
主应用程序类 (FilepreviewApplication.java
):
package com.icoderoad.filepreview;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class FilepreviewApplication {
public static void main(String[] args) {
SpringApplication.run(FilepreviewApplication.class, args);
}
}
文件服务类 (FileService.java
):
package com.icoderoad.filepreview.service;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@Service
public class FileService {
@Value("${file-preview.file-save-dir}")
private String fileSaveDir;
@Value("${file-preview.base-url}")
private String baseUrl;
public String saveFile(MultipartFile file) throws IOException {
// 创建文件保存路径
Path path = Paths.get(fileSaveDir, file.getOriginalFilename());
Files.write(path, file.getBytes());
// 生成文件的 HTTP URL
return baseUrl + "/" + file.getOriginalFilename();
}
}
文件预览控制器 (FileController.java
):
package com.icoderoad.filepreview.controller;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import com.icoderoad.filepreview.service.FileService;
@Controller
public class FileController {
@Autowired
private FileService fileService;
@GetMapping("/")
public String index(Model model) {
return "upload";
}
@PostMapping("/upload")
public ResponseEntity<Map<String, String>> handleFileUpload(@RequestParam("file") MultipartFile file) {
Map<String, String> response = new HashMap<>();
try {
if (file.isEmpty()) {
throw new IllegalArgumentException("上传的文件为空");
}
// 保存文件并获取 HTTP 访问路径
String fileUrl = fileService.saveFile(file);
response.put("fileUrl", fileUrl);
return ResponseEntity.ok(response);
} catch (IOException e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(Map.of("error", "文件上传失败"));
}
}
@GetMapping("/preview")
public String previewFile(@RequestParam("filePath") String filePath, Model model) {
// 将文件路径传递给前端页面
model.addAttribute("filePath", filePath);
return "preview";
}
}
前端页面
文件上传页面 (upload.html
):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文件上传</title>
<!-- Bootstrap CSS -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
padding-top: 20px;
}
.container {
max-width: 900px;
}
.upload-box {
border: 1px solid #ddd;
padding: 20px;
border-radius: 5px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.progress {
margin-top: 10px;
}
.alert {
display: none; /* 默认隐藏提示信息 */
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-12">
<h1 class="text-center">文件上传</h1>
<div class="upload-box">
<form id="uploadForm" enctype="multipart/form-data">
<div class="form-group">
<label for="fileInput">选择文件</label>
<input type="file" class="form-control-file" id="fileInput" name="file">
</div>
<button type="submit" class="btn btn-primary">上传</button>
</form>
<div class="progress mt-3">
<div id="progressBar" class="progress-bar" role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div id="uploadStatus" class="alert alert-success mt-3"></div>
<div id="uploadError" class="alert alert-danger mt-3"></div>
<div id="previewSection" class="mt-3" style="display: none;">
<button id="previewButton" class="btn btn-success">查看预览</button>
</div>
</div>
</div>
</div>
</div>
<!-- Bootstrap JS and dependencies -->
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.2/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<script>
$(document).ready(function() {
$('#uploadForm').on('submit', function(event) {
event.preventDefault(); // 防止默认提交
var formData = new FormData(this);
$.ajax({
url: '/upload', // 后端处理上传的接口
type: 'POST',
data: formData,
contentType: false,
processData: false,
xhr: function() {
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable) {
var percentComplete = Math.round((e.loaded / e.total) * 100);
$('#progressBar').css('width', percentComplete + '%');
$('#progressBar').attr('aria-valuenow', percentComplete);
}
}, false);
return xhr;
},
success: function(response) {
// 假设响应中包含文件的 URL
$('#uploadStatus').text('文件上传成功!').show();
$('#uploadError').hide();
$('#progressBar').css('width', '100%');
// 显示预览按钮
var fileUrl = response.fileUrl; // 从响应中获取文件 URL
console.log("fileUrl:", fileUrl);
$('#previewButton').data('file-url', fileUrl);
$('#previewSection').show();
},
error: function(xhr) {
$('#uploadError').text('文件上传失败!').show();
$('#uploadStatus').hide();
}
});
// 预览按钮点击事件
$('#previewButton').on('click', function() {
var fileUrl = $(this).data('file-url');
console.log("fileUrl:", fileUrl);
if (fileUrl) {
var previewUrl = 'http://localhost:8080/preview?filePath=' + encodeURIComponent(fileUrl);
window.open(previewUrl, '_blank');
}
});
});
});
</script>
</body>
</html>
文件预览页面 (preview.html
):
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>File Preview</title>
<!-- Bootstrap CSS -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
<script type="text/javascript">
function base64Encode(str) {
return btoa(unescape(encodeURIComponent(str)));
}
</script>
<style>
body {
padding-top: 20px;
}
.container {
max-width: 900px;
}
.preview-box {
border: 1px solid #ddd;
padding: 20px;
border-radius: 5px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.iframe-container {
position: relative;
padding-top: 56.25%; /* 16:9 aspect ratio */
height: 0;
overflow: hidden;
}
.iframe-container iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-12">
<h1 class="text-center">文件在线预览</h1>
<div class="preview-box">
<div class="iframe-container">
<!-- 使用 iframe 显示文件预览 -->
<script th:inline="javascript">
// 获取服务器传递的文件 HTTP 访问路径
var filePath = /*[[${filePath}]]*/ 'default.txt';
// 对文件路径进行 Base64 编码并进行 URL 编码
var encodedUrl =encodeURIComponent(base64Encode(filePath));
// 生成预览的 URL
var previewUrl = 'http://localhost:8012/onlinePreview?url=' + encodedUrl;
// 动态插入 iframe 用于文件预览
document.write('<iframe src="' + previewUrl + '" width="100%" height="600px"></iframe>');
</script>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
启动项目
完成上述步骤后,启动Spring Boot项目,访问 http://localhost:8080
,即可体验文件在线预览功能。
总结
通过本文的介绍,我们成功在Spring Boot项目中集成了kkFileView,实现了任意文件的在线预览功能。通过Spring Boot的简洁配置和kkFileView强大的文件解析能力,我们能够轻松地在Web应用中为用户提供优质的文件预览体验。