基于 SpringBoot3.3 支持任意文件在线预览功能
基于 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
解压安装包
下载完成后,使用以下命令解压安装包:
tar -zxvf kkFileView-4.0.0.tar.gz
修改配置文件
解压完成后,进入配置文件目录并修改
application.properties
配置文件:cd kkFileView-4.0.0/config
vi application.properties将配置文件中的
server.address
修改为你当前虚拟机的 IP 地址。启动 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应用中为用户提供优质的文件预览体验。