【SpringBoot】23 文件预览(kkFileView)

Gitee仓库

https://gitee.com/Lin_DH/system

介绍

文件预览功能是指在不打开或编辑文件的情况下,通过某种方式查看文件的内容、格式或者部分内容的功能。该功能通常用于文件管理系统、办公工具、在线教育平台、企业协作平台、电子邮件客户端等领域,能够提高用户体验,节省带宽和存储空间,并保护知识产权。
今天推荐一个用 SpringBoot 搭建的文档在线预览解决方案:kkFileView。

官网

https://kkfileview.keking.cn/zh-cn/index.html

运行项目

第一步:下载源码
https://github.com/kekingcn/kkFileView
在这里插入图片描述
第二步:用 IDEA 打开源码
第三步:配置 Maven
在这里插入图片描述
第四步:配置文件编码
在这里插入图片描述第五步:配置编译环境
在这里插入图片描述
第六步:双击 Ctrl 键,输入打包命令:mvn package
在这里插入图片描述
在这里插入图片描述
打包获得 linux 环境运行的 kkFileView-x.x.x.tar.gz 和 window 环境运行的 kkFileView-x.x.x.zip,解压 .zip 文件获得 kkFileView-x.x.x 文件。
在这里插入图片描述
第七步:运行 kkFileView-x.x.x 文件中 bin 目录的 startup.bat 文件。
在这里插入图片描述
浏览器访问 http://127.0.0.1:8012/,成功运行项目访问到页面。
在这里插入图片描述
第八步:获取 base64 cdn
https://www.jsdelivr.com/package/npm/js-base64
三种调用方式
1)普通文件下载url预览

<script type="text/javascript"src="https://cdn.jsdelivr.net/npm/js-base64@3.6.0/base64.min.js"></script>
varurl = 'http://127.0.0.1:8080/file/test_.txt'; //要预览文件的访问地址 
window.open('http://127.0.0.1:8012/onlinePreview?url='+encodeURIComponent(Base64.encode(url)));

2)http / https下载流 url 预览

<script type="text/javascript"src="https://cdn.jsdelivr.net/npm/js-base64@3.6.0/base64.min.js"></script>
varoriginUrl = 'http://127.0.0.1:8080/filedownload?fileId=1'; //要预览文件的访问地址 
varpreviewUrl = originUrl + '&fullfilename=test.txt';
window.open('http://127.0.0.1:8012/onlinePreview?url='+encodeURIComponent(Base64.encode(previewUrl)));

3)FTP方式

<script type="text/javascript"src="https://cdn.jsdelivr.net/npm/js-base64@3.6.0/base64.min.js"></script>
varurl = 'ftp://127.0.0.1/file/test.txt'; //要预览文件的访问地址 
window.open('http://127.0.0.1:8012/onlinePreview?url='+encodeURIComponent(Base64.encode(url)));

第九步:配置静态文件位置

application.yml

spring:mvc:static-path-pattern: /static/**

在 resources 目录下,新建 static 目录,image 目录,并放入文件。
在这里插入图片描述
第十步:放入 js-base64 文件
在 static 目录下,新建 js 目录,放入 js-base64-v3.6.0.js 文件。

js-base64-v3.6.0.js


//
// THIS FILE IS AUTOMATICALLY GENERATED! DO NOT EDIT BY HAND!
//
;(function(global, factory) {typeof exports === 'object' && typeof module !== 'undefined'? module.exports = factory(): typeof define === 'function' && define.amd? define(factory) :// cf. https://github.com/dankogai/js-base64/issues/119(function() {// existing version for noConflict()const _Base64 = global.Base64;const gBase64 = factory();gBase64.noConflict = () => {global.Base64 = _Base64;return gBase64;};if (global.Meteor) { // Meteor.jsBase64 = gBase64;}global.Base64 = gBase64;})();
}((typeof self !== 'undefined' ? self: typeof window !== 'undefined' ? window: typeof global !== 'undefined' ? global: this
), function() {'use strict';/***  base64.ts**  Licensed under the BSD 3-Clause License.*    http://opensource.org/licenses/BSD-3-Clause**  References:*    http://en.wikipedia.org/wiki/Base64** @author Dan Kogai (https://github.com/dankogai)*/
const version = '3.6.0';
/*** @deprecated use lowercase `version`.*/
const VERSION = version;
const _hasatob = typeof atob === 'function';
const _hasbtoa = typeof btoa === 'function';
const _hasBuffer = typeof Buffer === 'function';
const _TD = typeof TextDecoder === 'function' ? new TextDecoder() : undefined;
const _TE = typeof TextEncoder === 'function' ? new TextEncoder() : undefined;
const b64ch = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const b64chs = [...b64ch];
const b64tab = ((a) => {let tab = {};a.forEach((c, i) => tab[c] = i);return tab;
})(b64chs);
const b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
const _fromCC = String.fromCharCode.bind(String);
const _U8Afrom = typeof Uint8Array.from === 'function'? Uint8Array.from.bind(Uint8Array): (it, fn = (x) => x) => new Uint8Array(Array.prototype.slice.call(it, 0).map(fn));
const _mkUriSafe = (src) => src.replace(/[+\/]/g, (m0) => m0 == '+' ? '-' : '_').replace(/=+$/m, '');
const _tidyB64 = (s) => s.replace(/[^A-Za-z0-9\+\/]/g, '');
/*** polyfill version of `btoa`*/
const btoaPolyfill = (bin) => {// console.log('polyfilled');let u32, c0, c1, c2, asc = '';const pad = bin.length % 3;for (let i = 0; i < bin.length;) {if ((c0 = bin.charCodeAt(i++)) > 255 ||(c1 = bin.charCodeAt(i++)) > 255 ||(c2 = bin.charCodeAt(i++)) > 255)throw new TypeError('invalid character found');u32 = (c0 << 16) | (c1 << 8) | c2;asc += b64chs[u32 >> 18 & 63]+ b64chs[u32 >> 12 & 63]+ b64chs[u32 >> 6 & 63]+ b64chs[u32 & 63];}return pad ? asc.slice(0, pad - 3) + "===".substring(pad) : asc;
};
/*** does what `window.btoa` of web browsers do.* @param {String} bin binary string* @returns {string} Base64-encoded string*/
const _btoa = _hasbtoa ? (bin) => btoa(bin): _hasBuffer ? (bin) => Buffer.from(bin, 'binary').toString('base64'): btoaPolyfill;
const _fromUint8Array = _hasBuffer? (u8a) => Buffer.from(u8a).toString('base64'): (u8a) => {// cf. https://stackoverflow.com/questions/12710001/how-to-convert-uint8-array-to-base64-encoded-string/12713326#12713326const maxargs = 0x1000;let strs = [];for (let i = 0, l = u8a.length; i < l; i += maxargs) {strs.push(_fromCC.apply(null, u8a.subarray(i, i + maxargs)));}return _btoa(strs.join(''));};
/*** converts a Uint8Array to a Base64 string.* @param {boolean} [urlsafe] URL-and-filename-safe a la RFC4648 §5* @returns {string} Base64 string*/
const fromUint8Array = (u8a, urlsafe = false) => urlsafe ? _mkUriSafe(_fromUint8Array(u8a)) : _fromUint8Array(u8a);
// This trick is found broken https://github.com/dankogai/js-base64/issues/130
// const utob = (src: string) => unescape(encodeURIComponent(src));
// reverting good old fationed regexp
const cb_utob = (c) => {if (c.length < 2) {var cc = c.charCodeAt(0);return cc < 0x80 ? c: cc < 0x800 ? (_fromCC(0xc0 | (cc >>> 6))+ _fromCC(0x80 | (cc & 0x3f))): (_fromCC(0xe0 | ((cc >>> 12) & 0x0f))+ _fromCC(0x80 | ((cc >>> 6) & 0x3f))+ _fromCC(0x80 | (cc & 0x3f)));}else {var cc = 0x10000+ (c.charCodeAt(0) - 0xD800) * 0x400+ (c.charCodeAt(1) - 0xDC00);return (_fromCC(0xf0 | ((cc >>> 18) & 0x07))+ _fromCC(0x80 | ((cc >>> 12) & 0x3f))+ _fromCC(0x80 | ((cc >>> 6) & 0x3f))+ _fromCC(0x80 | (cc & 0x3f)));}
};
const re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;
/*** @deprecated should have been internal use only.* @param {string} src UTF-8 string* @returns {string} UTF-16 string*/
const utob = (u) => u.replace(re_utob, cb_utob);
//
const _encode = _hasBuffer? (s) => Buffer.from(s, 'utf8').toString('base64'): _TE? (s) => _fromUint8Array(_TE.encode(s)): (s) => _btoa(utob(s));
/*** converts a UTF-8-encoded string to a Base64 string.* @param {boolean} [urlsafe] if `true` make the result URL-safe* @returns {string} Base64 string*/
const encode = (src, urlsafe = false) => urlsafe? _mkUriSafe(_encode(src)): _encode(src);
/*** converts a UTF-8-encoded string to URL-safe Base64 RFC4648 §5.* @returns {string} Base64 string*/
const encodeURI = (src) => encode(src, true);
// This trick is found broken https://github.com/dankogai/js-base64/issues/130
// const btou = (src: string) => decodeURIComponent(escape(src));
// reverting good old fationed regexp
const re_btou = /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g;
const cb_btou = (cccc) => {switch (cccc.length) {case 4:var cp = ((0x07 & cccc.charCodeAt(0)) << 18)| ((0x3f & cccc.charCodeAt(1)) << 12)| ((0x3f & cccc.charCodeAt(2)) << 6)| (0x3f & cccc.charCodeAt(3)), offset = cp - 0x10000;return (_fromCC((offset >>> 10) + 0xD800)+ _fromCC((offset & 0x3FF) + 0xDC00));case 3:return _fromCC(((0x0f & cccc.charCodeAt(0)) << 12)| ((0x3f & cccc.charCodeAt(1)) << 6)| (0x3f & cccc.charCodeAt(2)));default:return _fromCC(((0x1f & cccc.charCodeAt(0)) << 6)| (0x3f & cccc.charCodeAt(1)));}
};
/*** @deprecated should have been internal use only.* @param {string} src UTF-16 string* @returns {string} UTF-8 string*/
const btou = (b) => b.replace(re_btou, cb_btou);
/*** polyfill version of `atob`*/
const atobPolyfill = (asc) => {// console.log('polyfilled');asc = asc.replace(/\s+/g, '');if (!b64re.test(asc))throw new TypeError('malformed base64.');asc += '=='.slice(2 - (asc.length & 3));let u24, bin = '', r1, r2;for (let i = 0; i < asc.length;) {u24 = b64tab[asc.charAt(i++)] << 18| b64tab[asc.charAt(i++)] << 12| (r1 = b64tab[asc.charAt(i++)]) << 6| (r2 = b64tab[asc.charAt(i++)]);bin += r1 === 64 ? _fromCC(u24 >> 16 & 255): r2 === 64 ? _fromCC(u24 >> 16 & 255, u24 >> 8 & 255): _fromCC(u24 >> 16 & 255, u24 >> 8 & 255, u24 & 255);}return bin;
};
/*** does what `window.atob` of web browsers do.* @param {String} asc Base64-encoded string* @returns {string} binary string*/
const _atob = _hasatob ? (asc) => atob(_tidyB64(asc)): _hasBuffer ? (asc) => Buffer.from(asc, 'base64').toString('binary'): atobPolyfill;
//
const _toUint8Array = _hasBuffer? (a) => _U8Afrom(Buffer.from(a, 'base64')): (a) => _U8Afrom(_atob(a), c => c.charCodeAt(0));
/*** converts a Base64 string to a Uint8Array.*/
const toUint8Array = (a) => _toUint8Array(_unURI(a));
//
const _decode = _hasBuffer? (a) => Buffer.from(a, 'base64').toString('utf8'): _TD? (a) => _TD.decode(_toUint8Array(a)): (a) => btou(_atob(a));
const _unURI = (a) => _tidyB64(a.replace(/[-_]/g, (m0) => m0 == '-' ? '+' : '/'));
/*** converts a Base64 string to a UTF-8 string.* @param {String} src Base64 string.  Both normal and URL-safe are supported* @returns {string} UTF-8 string*/
const decode = (src) => _decode(_unURI(src));
/*** check if a value is a valid Base64 string* @param {String} src a value to check*/
const isValid = (src) => {if (typeof src !== 'string')return false;const s = src.replace(/\s+/g, '').replace(/=+$/, '');return !/[^\s0-9a-zA-Z\+/]/.test(s) || !/[^\s0-9a-zA-Z\-_]/.test(s);
};
//
const _noEnum = (v) => {return {value: v, enumerable: false, writable: true, configurable: true};
};
/*** extend String.prototype with relevant methods*/
const extendString = function () {const _add = (name, body) => Object.defineProperty(String.prototype, name, _noEnum(body));_add('fromBase64', function () { return decode(this); });_add('toBase64', function (urlsafe) { return encode(this, urlsafe); });_add('toBase64URI', function () { return encode(this, true); });_add('toBase64URL', function () { return encode(this, true); });_add('toUint8Array', function () { return toUint8Array(this); });
};
/*** extend Uint8Array.prototype with relevant methods*/
const extendUint8Array = function () {const _add = (name, body) => Object.defineProperty(Uint8Array.prototype, name, _noEnum(body));_add('toBase64', function (urlsafe) { return fromUint8Array(this, urlsafe); });_add('toBase64URI', function () { return fromUint8Array(this, true); });_add('toBase64URL', function () { return fromUint8Array(this, true); });
};
/*** extend Builtin prototypes with relevant methods*/
const extendBuiltins = () => {extendString();extendUint8Array();
};
const gBase64 = {version: version,VERSION: VERSION,atob: _atob,atobPolyfill: atobPolyfill,btoa: _btoa,btoaPolyfill: btoaPolyfill,fromBase64: decode,toBase64: encode,encode: encode,encodeURI: encodeURI,encodeURL: encodeURI,utob: utob,btou: btou,decode: decode,isValid: isValid,fromUint8Array: fromUint8Array,toUint8Array: toUint8Array,extendString: extendString,extendUint8Array: extendUint8Array,extendBuiltins: extendBuiltins,
};//// export Base64 to the namespace//// ES5 is yet to have Object.assign() that may make transpilers unhappy.// gBase64.Base64 = Object.assign({}, gBase64);gBase64.Base64 = {};Object.keys(gBase64).forEach(k => gBase64.Base64[k] = gBase64[k]);return gBase64;
}));

第十一步:编写文件预览页面

filePreview.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head lang="en"><meta charset="UTF-8" /><title>文件预览页面</title><script type="text/javascript" th:src="@{../static/js/js-base64-v3.6.0.js}"></script>
</head><body>
<h1>文件预览页面</h1>
<button th:onclick="'previewFile();'">预览</button>
</body><script th:inline="javascript">function previewFile () {const domain = "http://127.0.0.1";const fileUrl = domain + ":8888/static/image/Avatar.jpg";//const fileUrl = domain + ":8888/static/js/js-base64-v3.6.0.js";const url = domain + ":8012/onlinePreview?url=" + encodeURIComponent(Base64.encode(fileUrl));window.open(url);}
</script></html>

第十二步:编写文件访问类

FileController.java

/*** @author DUHAOLIN* @date 2024/10/15*/
@Controller
public class FileController {@GetMapping("filePreview")public String filePreview() {return "filePreview";}}

效果图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/16198.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

PC提取微信语音

首先&#xff0c;多选需要转存的语音信息——点击下方正方体图标收藏——打开收藏界面&#xff0c;找到语音文件打开——点击界面上放3个小点&#xff0c;选择转存为笔记。 然后&#xff0c;打开电脑端微信&#xff0c;点击左侧收藏图标&#xff0c;找到保存的语音文件打开&am…

STM32 ADC --- 单通道采样

STM32 ADC — 单通道采样 文章目录 STM32 ADC --- 单通道采样cubeMX配置代码修改&#xff1a;应用 使用cubeMX生成HAL工程 需求&#xff1a;有多个通道需要进行ADC采样&#xff0c;实现每次采样只采样一个通道&#xff0c;且可以随时采样不同通道的功能。 cubeMX配置 这里我们…

力扣 LeetCode 150. 逆波兰表达式求值(Day5:栈与队列)

解题思路&#xff1a; 逆波兰表达式就是从二叉树的后序遍历得来的&#xff08;左右根&#xff09;&#xff0c;因此计算机直接按顺序取出表达式中元素进行运算即可&#xff0c;无需考虑括号的运算顺序&#xff0c;加快运算速度 对于&#xff08;12&#xff09;x&#xff08;3…

交通路口智能监测平台实现

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;编程探索专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年11月15日8点12分 神秘男子影, 秘而不宣藏。 泣意深不见, 男子自持重, 子夜独自沉。 论文链接 点击开启你的论文编程之旅h…

Redis 持久化机制 RDB 和 AOF 区别

Redis 是一个开源的内存数据结构存储系统&#xff0c;广泛应用于缓存、会话存储、实时分析等场景。虽然 Redis 本质上是内存数据库&#xff0c;但它支持持久化机制&#xff0c;将数据保存在磁盘中以防止数据丢失。在 Redis 中&#xff0c;主要有两种持久化机制&#xff1a;RDB(…

uniapp动态获取练习题的内容选项和最终选择的结果

里面的练习题题目和选项都是动态获取的&#xff0c;提交的时候结果是多个单选题最终选择的值&#xff0c;重点是给单选组标签上加上change事件&#xff0c;多选通用&#xff0c;change事件内加一个回调&#xff0c;代码示例如下&#xff1a; <template> <view class&…

联想 ThinkPad的高级键盘功能

前言&#xff1a; 用好键盘是程序员最需要花时间了解的。 联想ThinkPAD的高级键盘功能和windows的键盘功能是不一样的。学习一下&#xff0c;给自己的工作&#xff0c;编程带来很大的的提高。花时间是有意义的。 调出设置&#xff1a; 1 先是键盘管理&#xff1a; 这里&#…

红黑树

目录 红黑树 红黑树的概念 红黑树的性质 红黑树节点的定义 插入的代码实现 情况一 情况二 uncle不存在 uncle存在且为黑单旋 情况三 uncle存在且为黑的双旋情况 情况二和情况三的总代码 以上是父亲在爷爷左边的情况,右边的情况也类似 左旋代码 右旋代码 红黑树…

MySQL进阶-索引的组合索引

练习题目 题目链接难度SQL进阶-索引的组合索引★★★☆☆ SQL思路 SQL进阶-索引的组合索引 初始化数据 drop table if exists user_profile; CREATE TABLE user_profile ( id int NOT NULL, device_id int NOT NULL, gender varchar(14) NOT NULL, age int , university va…

适用比亚迪汽车生产线的RFID高频读写器

随着人工智能和物联网技术的发展&#xff0c;汽车产线正朝着高度自动化和智能化的方向发展&#xff0c;许多汽车制造商选择将RFID技术应用在其生产线上&#xff0c;以提高生产效率、降低劳动强度。例如比亚迪等汽车生产线上已经广泛应用RFID技术。 健永科技利用自身的研发能力…

用Python实现中国象棋(详细教程 | 附代码)

创建一个完整的中国象棋游戏是一个复杂的项目&#xff0c;涉及到游戏规则、用户界面、AI算法等多个方面。在这里&#xff0c;我将提供一个更完整的Python代码示例&#xff0c;包括基本的棋盘、棋子移动规则和简单的用户交互。但请注意&#xff0c;这仍然是一个简化的版本&#…

力扣-Mysql-3308- 寻找表现最佳的司机(中等)

一、题目来源 3308. 寻找表现最佳的司机 - 力扣&#xff08;LeetCode&#xff09; 二、数据表结构 表&#xff1a;Drivers ----------------------- | Column Name | Type | ----------------------- | driver_id | int | | name | varchar | | age …

LeetCode 209.长度最小的子数组

209.长度最小的子数组 思路&#x1f9d0;&#xff1a; 该题可以用滑动窗口进行解答&#xff0c;滑动窗口的意思是&#xff0c;我们判断一段区间的情况&#xff0c;再根据不同情况进行区间的更新。 这里要求满足总和大于等于target的子数组&#xff0c;那么我们可以用两个指针当…

国网山东电力生产检修建设基地绿色低碳智慧用能项目获创新创意劳动竞赛一等奖

原标题&#xff1a;深化开展“供电能效服务”&#xff0c;全力推动全社会能效提升&#xff0c;国网山东电力生产检修建设基地绿色低碳智慧用能项目获得全省智慧综合能源服务项目创新创意劳动竞赛一等奖 11月14日,由山东省发展和改革委员会、山东省总工会、山东省能源局主办,山…

AIHub: 模型和数据集的私有云存储库

AIStor 的最新功能之一是广受欢迎的开源项目 Hugging Face 的私有云版本。这篇文章详细介绍了 AIStor 的 AIHub 如何有效地创建一个完全由企业控制的 API 兼容的私有云版本的 Hugging Face。在我们开始之前&#xff0c;介绍 Hugging Face 是有意义的。Hugging Face 是面向 AI 工…

【SAP FICO】财务三大报表_2-进阶(现金流量表-数据表结构、取数逻辑)

系列文章目录 文章目录 系列文章目录前言一、现金流量表二、现金流量表的数据表结构1、核心数据表2、内部数据结构 三、现金流量表的取数逻辑1、获取用户输入2、获取数据3、处理数据 总结 前言 承接上篇财务三大报表_2-进阶&#xff08;利润表-数据表结构、取数逻辑&#xff0…

【人工智能】深入解析!三种实现ChatGPT打字机效果的最佳方案

在当今AI快速发展的时代&#xff0c;ChatGPT 凭借其强大的自然语言处理能力&#xff0c;已经成为众多开发者和企业的首选工具。然而&#xff0c;如何在前端页面中实现类似于ChatGPT的打字机效果&#xff0c;以提升用户交互体验&#xff0c;成为了一个广受关注的话题。今天&…

C++:继承

一、什么是继承&#xff1f; 概念&#xff1a; 在我们认识模板之后&#xff0c;模板是写与类型无关的代码&#xff0c;是一种复用方法。今天讲解的是继承&#xff0c;继承也是代码复用的方法&#xff0c;是在原有的基础上进行增加新的类。由此继承体现了面向对象的层次结构&a…

Java版本Spring Cloud+SpringBoot b2b2c:Java商城实现一件代发设置及多商家直播带货商城搭建

一、产品简介 我们的JAVA版多商家入驻直播带货商城系统是一款全*面的电子商务平台&#xff0c;它允许商家和消费者在一个集成的环境中进行互动。系统采用先进的JAVA语言开发&#xff0c;提供多商家入驻、直播带货、B2B2C等多种功能&#xff0c;帮助用户实现线上线下的无缝对接…

【Linux】进程

目录 谈谈硬件冯诺依曼体系结构数据流向 谈谈软件(操作系统)什么是操作系统&#xff1f;为什么需要操作系统&#xff1f;操作系统如何管理&#xff1f; 谈谈进程管理进程PCB查看进程ps ajxprockill -9 PID 系统调用getpid()getppid()fork() 进程状态linux下的进程状态RSDT/tXZ …