SpringBoot+Vue+kkFileView实现文档管理(文档上传、下载、在线预览)

 场景

SpringBoot+Vue+OpenOffice实现文档管理(文档上传、下载、在线预览):

SpringBoot+Vue+OpenOffice实现文档管理(文档上传、下载、在线预览)_霸道流氓气质的博客-CSDN博客_vue openoffice

上面在使用OpenOffice实现doc、excel、ppt等文档的管理和预览。

除此之外可用kkFileView实现包括且更多文档的预览。

kkFileView

kkFileView - 在线文件预览

kkFileView为文件文档在线预览解决方案,该项目使用流行的spring boot搭建,易上手和部署,

基本支持主流办公文档的在线预览,如doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,rar,图片,视频,音频等等。

gitee地址:

kkFileView: 使用spring boot打造文件文档在线预览项目解决方案,支持doc、docx、ppt、pptx、xls、xlsx、zip、rar、mp4、mp3以及众多类文本如txt、html、xml、java、properties、sql、js、md、json、conf、ini、vue、php、py、bat、gitignore等文件在线预览

kkFileView部署和SpringBoot接入指南

具体参考文档:

文档预览 - Gitee.com

这里是windows电脑,所以直接下载发行版本并解压运行即可

kkFileView 发行版 - Gitee.com

解压之后找到bin下bat,双击启动即可

启动成功之后访问:

http://127.0.0.1:8012/index

出现如下界面则成功

 

项目接入使用

当您的项目内需要预览文件时,只需要调用浏览器打开本项目的预览接口,并传入须要预览文件的url

                    var url = 'http://127.0.0.1:8080/file/test.txt'; //要预览文件的访问地址window.open('http://127.0.0.1:8012/onlinePreview?url='+encodeURIComponent(base64Encode(url)));

注:

博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主
关注公众号
霸道的程序猿
获取编程相关电子书、教程推送与免费下载。

实现

建表与后台SpringBoot代码生成

若依前后端分离版本地搭建开发环境并运行项目的教程:

若依前后端分离版手把手教你本地搭建环境并运行项目_霸道流氓气质的博客-CSDN博客_运行若依分离版

基于上面搭建起来架构的基础上。

设计数据库表

DROP TABLE IF EXISTS `bus_file_preview`;
CREATE TABLE `bus_file_preview`  (`id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '主键',`file_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '文件名',`preview_server_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '预览服务地址',`file_path` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '文件磁盘路径',`file_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '文件url',`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',`create_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '创建人',`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',`update_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '更新人',`remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '备注',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '文件上传与预览' ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;

表结构

使用若依自带代码生成工具生成代码,下面展示部分代码

实体类BusFilePreview

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;public class BusFilePreview extends BaseEntity
{private static final long serialVersionUID = 1L;/** 主键 */private Long id;/** 文件名 */@Excel(name = "文件名")private String fileName;/** 预览服务地址 */@Excel(name = "预览服务地址")private String previewServerUrl;/** 文件url */@Excel(name = "文件url")private String fileUrl;/** 文件磁盘路径 */@Excel(name = "文件磁盘路径")private String filePath;public void setId(Long id){this.id = id;}public Long getId(){return id;}public void setFileName(String fileName){this.fileName = fileName;}public String getFileName(){return fileName;}public void setPreviewServerUrl(String previewServerUrl){this.previewServerUrl = previewServerUrl;}public String getPreviewServerUrl(){return previewServerUrl;}public void setFileUrl(String fileUrl){this.fileUrl = fileUrl;}public String getFileUrl(){return fileUrl;}public void setFilePath(String filePath){this.filePath = filePath;}public String getFilePath(){return filePath;}@Overridepublic String toString() {return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE).append("id", getId()).append("fileName", getFileName()).append("previewServerUrl", getPreviewServerUrl()).append("fileUrl", getFileUrl()).append("createTime", getCreateTime()).append("createBy", getCreateBy()).append("updateTime", getUpdateTime()).append("updateBy", getUpdateBy()).append("remark", getRemark()).toString();}
}

文件上传功能实现

前端添加el-upload

    <!-- 添加或修改preview对话框 --><el-dialog :title="title" :visible.sync="open" width="35%" append-to-body><el-form ref="form" :model="form" :rules="rules" label-width="110px"><el-form-item label="文件名" prop="fileName"><el-inputv-model="form.fileName"placeholder="请输入文件名"disabled/></el-form-item><el-form-item label="附件" prop="photoPath"><el-upload:headers="headers":action="url":multiple="false":file-list="fileList":on-remove="fileRemove":on-success="uploadSuccess":on-error="uploadError":on-progress="uploadProgress":before-upload="beforeUpload":limit="1":on-exceed="beyond"><el-button size="small">上传<i class="el-icon-upload el-icon--right"></i></el-button><div class="el-upload__tip" style="color: red" slot="tip">提示:仅允许导入".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx",".pdf", ".mp3",".mp4",".wav"格式文件!</div></el-upload></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button type="primary" @click="submitForm">确 定</el-button><el-button @click="cancel">取 消</el-button></div></el-dialog>

并设置各回调事件,事件实现

    // 文件上传失败uploadError(err) {this.btnLoding = false;this.$message.error(res.msg);},// 上传中uploadProgress(e) {this.btnLoding = true;},// 文件上传之前beforeUpload(file) {const fileName = file.name;const fileType = fileName.substring(fileName.lastIndexOf("."));const whiteList = [".doc",".docx",".xls",".xlsx",".ppt",".pptx",".pdf",".mp3",".mp4",".wav",];//array.indexOf此方法判断数组中是否存在某个值,如果存在返回数组元素的下标,否则返回-1。if (whiteList.indexOf(fileType) === -1) {this.$message.error("只允许如下文件类型:" + whiteList.toString());return false;// 不处理} else {this.form.fileName = file.name;}},// 文件上传成功uploadSuccess(res, file, fileList) {this.form.previewServerUrl = res.previewServerUrl;this.form.fileUrl = res.fileUrl;this.form.filePath = res.filePath;this.btnLoding = false;this.fileList = fileList;this.$message(res.msg);},beyond(file, fileList) {this.$message({message: "最多上传一个文件",type: "warning",});},// 移除选择的文件fileRemove(file, fileList) {this.btnLoding = false;this.reset();this.fileList = [];},

重点关注文件上传之前的beforeUpload和文件上传成功的uploadSuccess

上传之前获取文件名和后缀名,然后判断是否为允许的文件类型,如果允许,获取文件名。

文件上传成功之后获取后台接口返回的文件预览服务地址和文件预览url以及磁盘路径三个参数。

其中文件预览服务地址指的是kkFileView的ip和端口号以及预览的url,比如这里是与后台服务放在了一起,

所以previewServerUrl为http://127.0.0.1:8012/onlinePreview?url=

文件预览url为调用kkFileView预览时传递的参数,比如

http://127.0.0.1:9090/profile/upload/2022/12/10/a28ffa19-9982-42d2-8766-1feb274c5bb7.doc

文件磁盘路径映射为网络url可以参考

SpringBoot中通过重写WebMvcConfigurer的方法配置静态资源映射实现图片上传后返回网络Url:

SpringBoot中通过重写WebMvcConfigurer的方法配置静态资源映射实现图片上传后返回网络Url_霸道流氓气质的博客-CSDN博客

这里后台将预览文件的网络url单独返回,是因为在前端进行预览时,需要对url参数进行base64编码

如果不进行编码预览会有问题,会提示

Illegal base64 character 3a

这点官网有说明

SpringBoot上传接口实现

代码实现

​@PostMapping("/uploadPreviewFile")public AjaxResult uploadPreviewFile(@Param("file") MultipartFile file) {AjaxResult ajaxResult = AjaxResult.success();try {//D:/ruoyi/uploadPath/upload/2022/12/10/String path = RuoYiConfig.getUploadPath() + "/" + DateUtils.datePath() + "/";FileUtils.check_folder(path);// 上传后的文件名称//423208ab-2171-4631-9e08-382c00aacc43.docString auth_file_name = UploadUtil.save_file_withAllow(file, path ,allowFiles);if (StringUtils.isEmpty(auth_file_name)){return AjaxResult.error(HttpStatus.BAD_REQUEST, "文件格式不合法");}ajaxResult.put("code", 200);ajaxResult.put("message", "成功");ajaxResult.put("fileName", auth_file_name);ajaxResult.put("filePath", path + auth_file_name);//serverConfig.getUrl()     http://127.0.0.1:9090//Constants.RESOURCE_PREFIX     /profile//RuoYiConfig.getUploadPathPre()  /upload//File.separator       ///DateUtils.datePath()   /2022/12/10//auth_file_name    a28ffa19-9982-42d2-8766-1feb274c5bb7.doc//url http://127.0.0.1:9090/profile/upload/2022/12/10/a28ffa19-9982-42d2-8766-1feb274c5bb7.docString fileUrl = serverConfig.getUrl()+ Constants.RESOURCE_PREFIX + RuoYiConfig.getUploadPathPre() + File.separator + DateUtils.datePath() + File.separator + auth_file_name;String previewServerUrl = Constants.HTTP + previewConfig.getServerIp() +":" +previewConfig.getServerPort() + Constants.PREVIEW_SERVER_URL;ajaxResult.put("previewServerUrl", previewServerUrl);ajaxResult.put("fileUrl", fileUrl);} catch (IOException e) {ajaxResult.put("code", 400);ajaxResult.put("message", "上传失败");e.printStackTrace();}return ajaxResult;}​

为方便更清晰的调试理解,这里在生成网络url时标注了每一步的参数

首先调用若依的工具类获取并检查文件上传目录,这里的RuoYiConfig.getUploadPath()配置的是D:/ruoyi/uploadPath

然后最终path的值为D:/ruoyi/uploadPath/upload/2022/12/10/

然后调用文件上传方法,这里新建了一个重载方法,传递了允许上传的文件类型,若依自带的方法该参数是写死的

 public static String save_file_withAllow(MultipartFile file, String path ,String[] allowFiles) throws IOException {String filename=file.getOriginalFilename();//后缀名校验String suffix = filename.substring(filename.indexOf("."));List<String> allowFileList = new ArrayList<>(Arrays.asList(allowFiles));if (!allowFileList.contains(suffix)){return null;}filename = UUID.randomUUID().toString() + suffix;File file_temp=new File(path,filename);if (!file_temp.getParentFile().exists()) {file_temp.getParentFile().mkdir();}if (file_temp.exists()) {file_temp.delete();}file_temp.createNewFile();file.transferTo(file_temp);return file_temp.getName();}

允许上传的格式需要声明

    /**允许上传的格式*/private static String[] allowFiles = {".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf",".mp3",".mp4",".wav"};

上传成功之后获取到文件的文件名,比如423208ab-2171-4631-9e08-382c00aacc43.doc

然后生成文件预览网络url

​//serverConfig.getUrl()     http://127.0.0.1:9090//Constants.RESOURCE_PREFIX     /profile//RuoYiConfig.getUploadPathPre()  /upload//File.separator       ///DateUtils.datePath()   /2022/12/10//auth_file_name    a28ffa19-9982-42d2-8766-1feb274c5bb7.doc//url http://127.0.0.1:9090/profile/upload/2022/12/10/a28ffa19-9982-42d2-8766-1feb274c5bb7.docString fileUrl = serverConfig.getUrl()+ Constants.RESOURCE_PREFIX + RuoYiConfig.getUploadPathPre() + File.separator + DateUtils.datePath() + File.separator + auth_file_name;​

这里的serverConfig是若依自带获取服务相关配置,其它的就是一些常量配置。

RuoYiConfig.getUploadPathPre() 是自己新增的获取上传路径的前缀

    /*** 获取上传路径前缀*/public static String getUploadPathPre(){return "/upload";}

最后返回kkFileView服务预览的ip和端口以及前缀

String previewServerUrl = Constants.HTTP + previewConfig.getServerIp() +":" +previewConfig.getServerPort() + Constants.PREVIEW_SERVER_URL;

这里将ip和端口写在配置文件中

#文件预览相关配置
preview:serverIp: 127.0.0.1serverPort: 8012

然后新增配置文件获取

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Component
@ConfigurationProperties(prefix = "preview")
public class PreviewConfig {private String serverIp;private String serverPort;public String getServerIp() {return serverIp;}public void setServerIp(String serverIp) {this.serverIp = serverIp;}public String getServerPort() {return serverPort;}public void setServerPort(String serverPort) {this.serverPort = serverPort;}
}

最终返回的previewServerUrl为

http://127.0.0.1:8012/onlinePreview?url=

上传成功之后,前端获取返回参数并赋值到form中,前端点击提交按钮时

    /** 提交按钮 */submitForm() {this.$refs["form"].validate((valid) => {if (valid) {if (this.form.id != null) {updatePreview(this.form).then((response) => {this.msgSuccess("修改成功");this.open = false;this.fileList = [];this.getList();});} else {addPreview(this.form).then((response) => {this.msgSuccess("新增成功");this.open = false;this.fileList = [];this.getList();});}}});},

将数据存储到数据库中。

文件上传效果实现

文件下载实现

前端下载按钮点击事件

    // 下载handleDownload(row) {var filePath = row.filePath;var fileName = row.fileName;var url =this.downloadUrl + "?filePath=" + filePath + "&fileName=" + fileName;const a = document.createElement("a");a.setAttribute("download", fileName);a.setAttribute("target", "_blank");a.setAttribute("href", url);a.click();},

获取文件磁盘路径和文件名,并传递参数

后台SpringBoot接口

    @GetMapping("download")@ApiOperation("下载")public void downloadFile(String filePath,String fileName, HttpServletResponse response) throws IOException {File file = new File(filePath);// 清空responseresponse.reset();// 设置response的Header 通知浏览器 已下载的方式打开文件 防止文本图片预览response.addHeader("Content-Disposition","attachment;filename=" + new String(fileName.getBytes("gbk"), "iso-8859-1")); // 转码之后下载的文件不会出现中文乱码response.addHeader("Content-Length", "" + file.length());// 以流的形式下载文件InputStream fis = new BufferedInputStream(new FileInputStream(filePath));byte[] buffer = new byte[fis.available()];fis.read(buffer);fis.close();OutputStream toClient = new BufferedOutputStream(response.getOutputStream());toClient.write(buffer);toClient.flush();toClient.close();}

文件下载效果

预览实现

前端点击预览的点击事件

    // 预览handlePreview(row) {var previewServerUrl = row.previewServerUrl;var fileUrl = row.fileUrl;//分别获取预览服务地址和预览参数的地址然后拼接//预览文件url地址需要使用Base64编码URLlet url =previewServerUrl + encodeURIComponent(Base64.encodeURI(fileUrl));window.open(url);},

注意这里获取预览服务地址和预览参数文件url,这里需要将文件url进行Base64编码

Vue中使用Base64编码

安装依赖

npm install --save js-base64

引入依赖

import { Base64 } from "js-base64";

调用编码方法

Base64.encodeURI(fileUrl)

预览效果

代码完整示例

前端Vue页面完整示例代码

<template><div class="app-container"><el-form:model="queryParams"ref="queryForm":inline="true"v-show="showSearch"label-width="68px"><el-form-item label="文件名" prop="fileName"><el-inputv-model="queryParams.fileName"placeholder="请输入文件名"clearablesize="small"@keyup.enter.native="handleQuery"/></el-form-item><el-form-item><el-buttontype="cyan"icon="el-icon-search"size="mini"@click="handleQuery">搜索</el-button><el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button></el-form-item></el-form><el-row :gutter="10" class="mb8"><el-col :span="1.5"><el-buttontype="primary"icon="el-icon-plus"size="mini"@click="handleAdd"v-hasPermi="['basicinfomanage:preview:add']">新增</el-button></el-col><el-col :span="1.5"><el-buttontype="success"icon="el-icon-edit"size="mini":disabled="single"@click="handleUpdate"v-hasPermi="['basicinfomanage:preview:edit']">修改</el-button></el-col><el-col :span="1.5"><el-buttontype="danger"icon="el-icon-delete"size="mini":disabled="multiple"@click="handleDelete"v-hasPermi="['basicinfomanage:preview:remove']">删除</el-button></el-col><right-toolbar:showSearch.sync="showSearch"@queryTable="getList"></right-toolbar></el-row><el-tablev-loading="loading":data="previewList"@selection-change="handleSelectionChange"><el-table-column type="selection" width="55" align="center" /><el-table-columnshow-overflow-tooltiplabel="文件名"align="center"prop="fileName"/><el-table-columnlabel="操作"align="center"class-name="small-padding fixed-width"width="200"><template slot-scope="scope"><el-buttonsize="mini"type="text"icon="el-icon-edit"@click="handleUpdate(scope.row)"v-hasPermi="['basicinfomanage:preview:edit']">修改</el-button><el-buttonsize="mini"type="text"icon="el-icon-edit"@click="handlePreview(scope.row)">预览</el-button><el-buttonsize="mini"type="text"icon="el-icon-edit"@click="handleDownload(scope.row)">下载</el-button><el-buttonsize="mini"type="text"icon="el-icon-delete"@click="handleDelete(scope.row)"v-hasPermi="['basicinfomanage:preview:remove']">删除</el-button></template></el-table-column></el-table><paginationv-show="total > 0":total="total":page.sync="queryParams.pageNum":limit.sync="queryParams.pageSize"@pagination="getList"/><!-- 添加或修改preview对话框 --><el-dialog :title="title" :visible.sync="open" width="35%" append-to-body><el-form ref="form" :model="form" :rules="rules" label-width="110px"><el-form-item label="文件名" prop="fileName"><el-inputv-model="form.fileName"placeholder="请输入文件名"disabled/></el-form-item><el-form-item label="附件" prop="photoPath"><el-upload:headers="headers":action="url":multiple="false":file-list="fileList":on-remove="fileRemove":on-success="uploadSuccess":on-error="uploadError":on-progress="uploadProgress":before-upload="beforeUpload":limit="1":on-exceed="beyond"><el-button size="small">上传<i class="el-icon-upload el-icon--right"></i></el-button><div class="el-upload__tip" style="color: red" slot="tip">提示:仅允许导入".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx",".pdf", ".mp3",".mp4",".wav"格式文件!</div></el-upload></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button type="primary" @click="submitForm">确 定</el-button><el-button @click="cancel">取 消</el-button></div></el-dialog></div>
</template><script>
import {listPreview,getPreview,delPreview,addPreview,updatePreview,
} from "@/api/basicinfomanage/preview";
import { getToken } from "@/utils/auth";
import { Base64 } from "js-base64";
export default {name: "Preview",data() {return {// 遮罩层loading: true,// 选中数组ids: [],// 非单个禁用single: true,// 非多个禁用multiple: true,// 显示搜索条件showSearch: true,// 总条数total: 0,// preview表格数据previewList: [],// 弹出层标题title: "",// 是否显示弹出层open: false,// 查询参数queryParams: {pageNum: 1,pageSize: 10,fileName: null,},// 表单参数form: {},// 表单校验rules: {fileName: [{required: true,message: "文件名称不能为空",trigger: "blur",},],},// 上传按钮闸口btnLoding: false,//  请求头headers: { Authorization: "Bearer" + " " + getToken() },// 上传地址url:process.env.VUE_APP_BASE_API +"/fzys/basicinfomanage/preview/uploadPreviewFile",// 下载地址downloadUrl:process.env.VUE_APP_BASE_API + "/fzys/basicinfomanage/preview/download",// 图片列表fileList: [],};},created() {this.getList();},methods: {/** 查询preview列表 */getList() {this.loading = true;listPreview(this.queryParams).then((response) => {this.previewList = response.rows;this.total = response.total;this.loading = false;});},// 取消按钮cancel() {this.open = false;this.reset();},// 表单重置reset() {this.form = {id: null,fileName: null,};this.resetForm("form");},/** 搜索按钮操作 */handleQuery() {this.queryParams.pageNum = 1;this.getList();},/** 重置按钮操作 */resetQuery() {this.resetForm("queryForm");this.handleQuery();},// 多选框选中数据handleSelectionChange(selection) {this.ids = selection.map((item) => item.id);this.single = selection.length !== 1;this.multiple = !selection.length;},/** 新增按钮操作 */handleAdd() {this.fileRemove();this.open = true;this.title = "添加文件";},/** 修改按钮操作 */handleUpdate(row) {this.reset();const id = row.id || this.ids;getPreview(id).then((response) => {this.form = response.data;this.open = true;this.title = "修改文件";});},// 预览handlePreview(row) {var previewServerUrl = row.previewServerUrl;var fileUrl = row.fileUrl;//分别获取预览服务地址和预览参数的地址然后拼接//预览文件url地址需要使用Base64编码URLlet url =previewServerUrl + encodeURIComponent(Base64.encodeURI(fileUrl));window.open(url);},// 下载handleDownload(row) {var filePath = row.filePath;var fileName = row.fileName;var url =this.downloadUrl + "?filePath=" + filePath + "&fileName=" + fileName;const a = document.createElement("a");a.setAttribute("download", fileName);a.setAttribute("target", "_blank");a.setAttribute("href", url);a.click();},/** 提交按钮 */submitForm() {this.$refs["form"].validate((valid) => {if (valid) {if (this.form.id != null) {updatePreview(this.form).then((response) => {this.msgSuccess("修改成功");this.open = false;this.fileList = [];this.getList();});} else {addPreview(this.form).then((response) => {this.msgSuccess("新增成功");this.open = false;this.fileList = [];this.getList();});}}});},/** 删除按钮操作 */handleDelete(row) {const ids = row.id || this.ids;this.$confirm('是否确认删除文件编号为"' + ids + '"的数据项?', "警告", {confirmButtonText: "确定",cancelButtonText: "取消",type: "warning",}).then(function () {return delPreview(ids);}).then(() => {this.getList();this.msgSuccess("删除成功");});},// 文件上传失败uploadError(err) {this.btnLoding = false;this.$message.error(res.msg);},// 上传中uploadProgress(e) {this.btnLoding = true;},// 文件上传之前beforeUpload(file) {const fileName = file.name;const fileType = fileName.substring(fileName.lastIndexOf("."));const whiteList = [".doc",".docx",".xls",".xlsx",".ppt",".pptx",".pdf",".mp3",".mp4",".wav",];//array.indexOf此方法判断数组中是否存在某个值,如果存在返回数组元素的下标,否则返回-1。if (whiteList.indexOf(fileType) === -1) {this.$message.error("只允许如下文件类型:" + whiteList.toString());return false;// 不处理} else {this.form.fileName = file.name;}},// 文件上传成功uploadSuccess(res, file, fileList) {this.form.previewServerUrl = res.previewServerUrl;this.form.fileUrl = res.fileUrl;this.form.filePath = res.filePath;this.btnLoding = false;this.fileList = fileList;this.$message(res.msg);},beyond(file, fileList) {this.$message({message: "最多上传一个文件",type: "warning",});},// 移除选择的文件fileRemove(file, fileList) {this.btnLoding = false;this.reset();this.fileList = [];},},
};
</script>

后台Controller完整代码

package com.ruoyi.web.controller.fzys.basicinfomannager;import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.fzys.basicinfomanage.BusFilePreview;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.UploadUtil;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.config.ServerConfig;
import com.ruoyi.fzys.service.basicinfomanageService.IBusFilePreviewService;
import com.ruoyi.system.utils.FileUtils;
import com.ruoyi.web.controller.fzys.config.PreviewConfig;
import io.swagger.annotations.ApiOperation;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;/*** previewController** @author ruoyi* @date 2021-10-29*/
@RestController
@RequestMapping("/fzys/basicinfomanage/preview")
public class BusFilePreviewController extends BaseController
{/**允许上传的格式*/private static String[] allowFiles = {".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf",".mp3",".mp4",".wav"};@Autowiredprivate ServerConfig serverConfig;@Autowiredprivate PreviewConfig previewConfig;@Autowiredprivate IBusFilePreviewService busFilePreviewService;@PostMapping("/uploadPreviewFile")public AjaxResult uploadPreviewFile(@Param("file") MultipartFile file) {AjaxResult ajaxResult = AjaxResult.success();try {String path = RuoYiConfig.getUploadPath() + "/" + DateUtils.datePath() + "/";FileUtils.check_folder(path);String auth_file_name = UploadUtil.save_file_withAllow(file, path ,allowFiles);if (StringUtils.isEmpty(auth_file_name)){return AjaxResult.error(HttpStatus.BAD_REQUEST, "文件格式不合法");}ajaxResult.put("code", 200);ajaxResult.put("message", "成功");ajaxResult.put("fileName", auth_file_name);ajaxResult.put("filePath", path + auth_file_name);String fileUrl = serverConfig.getUrl()+ Constants.RESOURCE_PREFIX + RuoYiConfig.getUploadPathPre() + File.separator + DateUtils.datePath() + File.separator + auth_file_name;String previewServerUrl = Constants.HTTP + previewConfig.getServerIp() +":" +previewConfig.getServerPort() + Constants.PREVIEW_SERVER_URL;ajaxResult.put("previewServerUrl", previewServerUrl);ajaxResult.put("fileUrl", fileUrl);} catch (IOException e) {ajaxResult.put("code", 400);ajaxResult.put("message", "上传失败");e.printStackTrace();}return ajaxResult;}/*** 下载文件* @param fileName* @param response* @throws IOException*/@GetMapping("download")@ApiOperation("下载")public void downloadFile(String filePath,String fileName, HttpServletResponse response) throws IOException {File file = new File(filePath);// 清空responseresponse.reset();// 设置response的Header 通知浏览器 已下载的方式打开文件 防止文本图片预览response.addHeader("Content-Disposition","attachment;filename=" + new String(fileName.getBytes("gbk"), "iso-8859-1")); // 转码之后下载的文件不会出现中文乱码response.addHeader("Content-Length", "" + file.length());// 以流的形式下载文件InputStream fis = new BufferedInputStream(new FileInputStream(filePath));byte[] buffer = new byte[fis.available()];fis.read(buffer);fis.close();OutputStream toClient = new BufferedOutputStream(response.getOutputStream());toClient.write(buffer);toClient.flush();toClient.close();}/*** 查询preview列表*/@GetMapping("/list")public TableDataInfo list(BusFilePreview busFilePreview){startPage();List<BusFilePreview> list = busFilePreviewService.selectBusFilePreviewList(busFilePreview);return getDataTable(list);}/*** 导出preview列表*/@Log(title = "preview", businessType = BusinessType.EXPORT)@PostMapping("/export")public void export(HttpServletResponse response, BusFilePreview busFilePreview) throws IOException{List<BusFilePreview> list = busFilePreviewService.selectBusFilePreviewList(busFilePreview);ExcelUtil<BusFilePreview> util = new ExcelUtil<BusFilePreview>(BusFilePreview.class);util.exportExcel(response, list, "preview");}/*** 获取preview详细信息*/@GetMapping(value = "/{id}")public AjaxResult getInfo(@PathVariable("id") Long id){return AjaxResult.success(busFilePreviewService.selectBusFilePreviewById(id));}/*** 新增preview*/@Log(title = "preview", businessType = BusinessType.INSERT)@PostMappingpublic AjaxResult add(@RequestBody BusFilePreview busFilePreview) throws IOException{if (StringUtils.isNull(busFilePreview.getFileName())) {AjaxResult.error("缺少文件名称");}return toAjax(busFilePreviewService.insertBusFilePreview(busFilePreview));}/*** 修改preview*/@Log(title = "preview", businessType = BusinessType.UPDATE)@PutMappingpublic AjaxResult edit(@RequestBody BusFilePreview busFilePreview){return toAjax(busFilePreviewService.updateBusFilePreview(busFilePreview));}/*** 删除preview*/@Log(title = "preview", businessType = BusinessType.DELETE)@DeleteMapping("/{ids}")public AjaxResult remove(@PathVariable Long[] ids){return toAjax(busFilePreviewService.deleteBusFilePreviewByIds(ids));}}

后台其他各层代码均为根据表结构代码生成。

问题

1、注意后台需要放开下载接口的鉴权

2、如果在预览时页面显示

Whitelabel Error Page

找到kkFileView目录下log下kkFileView.log文件查看具体报错

Illegal base64 character 3a

这是因为一开始没将预览文件url进行Base64编码导致。

3、上传文件时提示

Maximum upload size exceeded:nested exception is java.lang.lllegalStateException:

org.apache.tomcat.util.http.fileupload.FileSizeLimitExceeededException:

The fiel filed exceeds its maximum perrmitted size of xxx bytes

找到application.yml中修改如下配置

# Spring配置
spring:# 资源信息messages:# 国际化资源文件路径basename: i18n/messagesprofiles:active: druid# 文件上传servlet:multipart:# 单个文件大小max-file-size:  100MB# 设置总上传的文件大小max-request-size:  200MB

修改位置

完整示例代码下载地址:

https://download.csdn.net/download/BADAO_LIUMANG_QIZHI/88849140

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

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

相关文章

项目管理中的关键:进度管理

项目管理中&#xff0c;进度管理无疑占据了举足轻重的地位&#xff0c;它不仅关乎项目能否按时完成&#xff0c;更是衡量项目效率、成本控制及质量保障的重要标尺。 它要求管理者根据项目的总体目标&#xff0c;科学合理地制定项目进度计划&#xff0c;并在项目实施过程中进行…

AI写作|拆解小红书对标账号 只需简单手搓一个coze智能体(提示词+方法)

本文背景 我们都知道&#xff0c;要想在小红书上面搞到米&#xff0c;爆款笔记必不可少&#xff0c;平时我们也看过不少的关于如何制作爆款笔记的各种教程&#xff0c;但是抵不住太多太复杂&#xff0c;于是有没有一种办法能将这个工作交给AI来执行呢&#xff1f; 爆款笔记会涉…

《C++基础入门与实战进阶》专栏介绍

&#x1f680; 前言 本文是《C基础入门与实战进阶》专栏的说明贴&#xff08;点击链接&#xff0c;跳转到专栏主页&#xff0c;欢迎订阅&#xff0c;持续更新…&#xff09;。 专栏介绍&#xff1a;以多年的开发实战为基础&#xff0c;总结并讲解一些的C/C基础与项目实战进阶内…

Simulink仿真中出现“Output argument ‘y‘ is not assigned on some execution paths.”

在simulink中添加函数时&#xff0c;经常由于代码的不完全&#xff0c;导致在simulink仿真时经常会出现“Output argument y is not assigned on some execution paths. "的错误&#xff0c;这是由于在编写程序时&#xff0c;对于输出y的赋值没有考虑全面&#xff0c;如下…

Python酷库之旅-第三方库Pandas(055)

目录 一、用法精讲 206、pandas.Series.reset_index方法 206-1、语法 206-2、参数 206-3、功能 206-4、返回值 206-5、说明 206-6、用法 206-6-1、数据准备 206-6-2、代码示例 206-6-3、结果输出 207、pandas.Series.sample方法 207-1、语法 207-2、参数 207-3、…

Charles抓包工具系列文章(七)-- Rewrite工具的应用示例

一、背景 客户端通过域名访问后端服务,在api网关层,会判断path的前缀,默认/api开头的请求都转发至后端服务A。 当前缀是/assist/api开头,请求将转发至后端服务B(部署在192.168.80.226,便于测试对比) 在不改动kong网关配置的情况下,现需要把后者的请求转发至192.168.…

【基础篇】Docker 镜像管理 THREE

嘿&#xff0c;小伙伴们&#xff01;我是小竹笋&#xff0c;一名热爱创作的工程师。在上一篇文章中&#xff0c;我们探讨了 Docker 的架构与关键组件。今天&#xff0c;让我们一起深入了解一下 Docker 镜像管理的相关知识吧&#xff01; &#x1f4e6; 创建和管理镜像 镜像是…

IEEE计算智能学会深圳分会线上讲座 22-01期: 金耀初教授的科研经验分享

IEEE计算智能学会深圳分会线上讲座 22-01期: 金耀初教授的科研经验分享_哔哩哔哩_bilibili 非限定性定语从句&#xff0c;使用逗号和which、动名词搭配使用&#xff0c; 尽量避免使用被动语态。 obviously- 使用clearly,apparently感觉上更好。 In this study/work 后面的交…

C/C++文件IO常用函数总结

文章目录 1. 文件描述符2. 文件IO常用函数2.1打开文件&#xff1a;open2.2 关闭文件&#xff1a;close2.3 读写操作&#xff1a;read/write2.4 关于光标的操作&#xff1a;lseek 1. 文件描述符 文件描述符的本质是一个大于等于0的整数&#xff0c;在使用open函数打开文件时&am…

pychar安装、pychon安装、pycharm超过试用期30激活

如果pycharm超过试用期&#xff0c;可以双击vbs脚本重新激活 百度网盘&#xff1a; 链接: https://pan.baidu.com/s/1B-XyLOy3wjVWbJwuvZOHOw?pwdmsb6 提取码: msb6

【学术会议征稿】第六届经济管理与模型工程国际学术会议(ICEMME 2024)

第六届经济管理与模型工程国际学术会议&#xff08;ICEMME 2024&#xff09; 2024 6th International Conference on Economic Management and Model Engineering 第六届经济管理与模型工程国际学术会议&#xff08;ICEMME 2024&#xff09;将于2024年11月22-24日在中国大连…

Bugku-web-Flask_FileUpload

Bugku-web-Flask_FileUpload 查看源代码&#xff0c;提示用python返回结果 在file.jpg中写python代码 import os os.system(ls / )上传后查看源代码&#xff0c;找到flag文件夹 修改代码 import os os.system(cat /flag )

STM32的外部中断实现按键控制led灯亮灭(HAL库)

一&#xff1a;stm32外部中断概述 1&#xff1a;stm32的外部中断线 STM32的每个IO都可以作为外部中断输入。 STM32的中断控制器支持19个外部中断/事件请求&#xff1a; 线0~15&#xff1a;对应外部IO口的输入中断。 线16&#xff1a;连接到PVD输出。 线17&#xff1a;连接到R…

鸿蒙应用框架开发【首选项】 本地数据与文件

首选项 简介 本示例使用ohos.data.preferences接口&#xff0c;展示了使用首选项持久化存储数据的功能。 效果预览 使用说明 1.点击顶部titleBar的右侧切换按钮&#xff0c;弹出主题菜单&#xff0c;选择任意主题则切换相应的主题界面&#xff1b; 2.退出应用再重新进入&a…

智能合约中approve函数详解

场景 这段时间很多小伙伴加我、都咨询到了一个类似的业务场景、 如下&#xff1a; 1、第一步业务里面调用授权函数approve 、给指定address2、第二步是由授权的address调用transferFrom转移给指定的接受地址。 案例DEMO如下&#xff08;这里test2肯定是会执行失败的&#xff…

相机标定(Camera Calibration)

什么是 相机标定&#xff08;Camera Calibration&#xff09;&#xff1f; 相机标定&#xff08;CameraCalibration&#xff09;是确定相机内部参数&#xff08;如焦距、光学中心、畸变系数等&#xff09;和外部参数&#xff08;如相机在世界坐标系中的位置和姿态&#xff09;的…

Jackson常用注解详解

Hi &#x1f44b;, Im shy 有人见尘埃&#xff0c;有人见星辰 Jackson常用注解详解 文章目录 Jackson常用注解详解0. 引入依赖1. JsonProperty2. JsonIgnore3. JsonFormat4. JsonInclude5. JsonCreator6. JsonValue7. JsonIgnoreProperties结论 Jackson是Java生态系统中广泛…

【Canvas与艺术】三环莫比乌斯圈

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>三环莫比乌斯圈</title><style type"text/css"&g…

插单现象对PMC造成的影响有哪些?

插单&#xff0c;即在生产制造过程中&#xff0c;客户或其他部门临时增加订单&#xff0c;这一行为如同战场上的突袭&#xff0c;让生产与物料控制&#xff08;PMC&#xff09;部门措手不及&#xff0c;面临着前所未有的压力和挑战。那么&#xff0c;插单现象究竟对PMC造成了哪…

【MATLAB源码-第239期】基于matlab的孔雀优化算法(POA)机器人栅格路径规划,输出做短路径图和适应度曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 孔雀优化算法&#xff08;Peafowl Optimization Algorithm&#xff0c;简称POA&#xff09;以孔雀&#xff08;peafowl&#xff09;的求偶展示行为为灵感&#xff0c;通过模拟这一过程来解决复杂的优化问题。以下是对孔雀优化…