SpringBoot+Vue+OpenOffice实现文档管理(文档上传、下载、在线预览)
場景
SpringBoot集成OpenOffice實現doc文檔轉html:
SpringBoot集成OpenOffice實現doc文檔轉html_BADAO_LIUMANG_QIZHI的博客-CSDN博客
在上面初步使用了OpenOffice之后,怎樣實現文檔管理,文檔上傳、下載、在線預覽等。
首先OpenOffice的下載安裝與啟動服務參照上文,不再復述。
注:
博客:
BADAO_LIUMANG_QIZHI的博客_霸道流氓氣質_CSDN博客
關注公眾號
霸道的程序猿
獲取編程相關電子書、教程推送與免費下載。
實現
1、搭建SpringBoot+Vue前后端分離項目
若依前后端分離版本地搭建開發環境并運行項目的教程:
若依前后端分離版手把手教你本地搭建環境并運行項目_BADAO_LIUMANG_QIZHI的博客-CSDN博客
2、設計表
數據庫語句為
DROP TABLE IF EXISTS `bus_file_preview`; CREATE TABLE `bus_file_preview`? (`id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '主鍵',`fileName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '原文件名(上傳前文件名)',`fileType` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '文件后綴(.xls;.xlsx;.ppt;.doc;.docx;.pptx)',`uploadPath` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '上傳后文件路徑',`uploadFileName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '上傳后文件名',`pdfPath` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '轉換pdf路徑',`pdfName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '轉換pdf文件名',`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 '備注',`preview_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '預覽URL',PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 21 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '文件上傳與預覽' ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;依照此表生成前后端代碼,然后修改代碼。
3、文件上傳實現
前端按鈕
??????? <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"accept=".doc,.docx,.xls,.ppt,.xlsx,.pptx"><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、.ppt、.xlsx、.pptx”格式文件!</div></el-upload></el-form-item>調用的各方法
??? // 文件上傳失敗uploadError(err) {this.btnLoding = false;this.$message.error(res.msg);},// 上傳中uploadProgress(e) {this.btnLoding = true;},// 文件上傳之前beforeUpload(file) {console.log(file, "上傳之前");const fileName = file.name;const fileType = fileName.substring(fileName.lastIndexOf("."));if (fileType === ".doc" ||fileType === ".docx" ||fileType === ".xls" ||fileType === ".ppt" ||fileType === ".pptx" ||fileType === ".xlsx") {this.form.filename = file.name;// 不處理} else {this.$message.error("請上傳正確的文件類型,.doc,.docx,.xls,.ppt,.xlsx,.pptx,");return false;}},// 文件上傳成功uploadSuccess(res, file, fileList) {this.form.uploadpath = res.uploadpath;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 = [];},對應后臺SpingBoot通用上傳接口
這里做了修改,使其能返回磁盤路徑
??? /*** 通用上傳請求返回磁盤路徑*/@PostMapping("/common/uploadWithAbsolutePath")public AjaxResult uploadFileWithAbsolutePath(MultipartFile file) throws Exception{try{// 上傳文件路徑String filePath = RuoYiConfig.getUploadPath();// 上傳并返回新文件名稱String fileName = FileUploadUtils.uploadWithAbsolutePath(filePath, file);AjaxResult ajax = AjaxResult.success();ajax.put("uploadpath", filePath+ File.separator+fileName);return ajax;}catch (Exception e){return AjaxResult.error(e.getMessage());}}調用的方法uploadWithAbsolutePath實現
??? public static final String uploadWithAbsolutePath(String baseDir, MultipartFile file) throws IOException{try{return uploadWithAbsolutePath(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);}catch (Exception e){throw new IOException(e.getMessage(), e);}}其中又調用的uploadWithAbsolutePath方法實現
??? public static final String uploadWithAbsolutePath(String baseDir, MultipartFile file, String[] allowedExtension)throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,InvalidExtensionException{int fileNamelength = file.getOriginalFilename().length();if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH){throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);}assertAllowed(file, allowedExtension);String fileName = extractFilename(file);File desc = getAbsoluteFile(baseDir, fileName);file.transferTo(desc);return fileName;}其他的若依框架原來的方法。
上傳效果
4、預覽實現
上傳之后的文件轉換成pdf的實現,在提交按鈕時調用后臺就接口
??? /** 提交按鈕 */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();});}}});},首先是新增接口
??? /*** 新增preview*/@Log(title = "preview", businessType = BusinessType.INSERT)@PostMappingpublic AjaxResult add(@RequestBody BusFilePreview busFilePreview) throws IOException{if (StringUtils.isNull(busFilePreview.getFilename())) {AjaxResult.error("缺少文件名稱");}if (StringUtils.isNull(busFilePreview.getUploadpath())) {AjaxResult.error("缺少上傳文件路徑");}String substringAfter = StringUtils.substringAfter(busFilePreview.getUploadpath(), ".");String upName = StringUtils.substringAfterLast(busFilePreview.getUploadpath(), "/");busFilePreview.setUploadfilename(upName);busFilePreview.setFiletype(substringAfter); //類型if ("pdf".equals(substringAfter)){FilePdfUtils.copyFile(busFilePreview.getUploadpath(), RuoYiConfig.getProfile());String pdfName = StringUtils.substringAfterLast(busFilePreview.getUploadpath(), "/");busFilePreview.setPdfpath(RuoYiConfig.getProfile()+ "/" + pdfName);busFilePreview.setPdfname(pdfName);return? toAjax(busFilePreviewService.insertBusFilePreview(busFilePreview));}File file = new File(busFilePreview.getUploadpath());FileInputStream fileInputStream = new FileInputStream(file);String htmFileName = FilePdfUtils.file2pdf(fileInputStream, substringAfter,RuoYiConfig.getProfile());String pdfPath = RuoYiConfig.getProfile()+ "/" + htmFileName;busFilePreview.setPdfpath(pdfPath);String pdfName = StringUtils.substringAfterLast(pdfPath, "/");busFilePreview.setPdfname(pdfName);String previewUrl = serverConfig.getUrl()+ Constants.RESOURCE_PREFIX+File.separator+htmFileName;busFilePreview.setPreviewUrl(previewUrl);return toAjax(busFilePreviewService.insertBusFilePreview(busFilePreview));}這里調用了工具類中FilePdfUtils的file2pdf方法,并且將轉換后的pdf的路徑拼接成靜態資源映射后的路徑返回給前端。
關于靜態資源映射可以參考如下
SpringBoot中通過重寫WebMvcConfigurer的方法配置靜態資源映射實現圖片上傳后返回網絡Url:
SpringBoot中通過重寫WebMvcConfigurer的方法配置靜態資源映射實現圖片上傳后返回網絡Url_BADAO_LIUMANG_QIZHI的博客-CSDN博客
5、FilePdfUtils工具類實現
package com.ruoyi.common.utils.pdf;import com.artofsolving.jodconverter.DocumentConverter; import com.artofsolving.jodconverter.openoffice.connection.OpenOfficeConnection; import com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection; import com.artofsolving.jodconverter.openoffice.converter.StreamOpenOfficeDocumentConverter; import com.ruoyi.common.utils.StringUtils;import java.io.*; import java.net.ConnectException; import java.text.SimpleDateFormat; import java.util.Date;public class FilePdfUtils {/*** 轉換文件成pdf** @param fromFileInputStream:* @throws IOException*/public static String file2pdf(InputStream fromFileInputStream, String type,String pdfPath) throws IOException {Date date = new Date();SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");String timesuffix = sdf.format(date);String docFileName = null;String htmFileName = null;if("doc".equals(type)){docFileName = "doc_" + timesuffix + ".doc";htmFileName = "doc_" + timesuffix + ".pdf";}else if("docx".equals(type)){docFileName = "docx_" + timesuffix + ".docx";htmFileName = "docx_" + timesuffix + ".pdf";}else if("xls".equals(type)){docFileName = "xls_" + timesuffix + ".xls";htmFileName = "xls_" + timesuffix + ".pdf";}else if("ppt".equals(type)){docFileName = "ppt_" + timesuffix + ".ppt";htmFileName = "ppt_" + timesuffix + ".pdf";}else if("xlsx".equals(type)){docFileName = "xlsx_" + timesuffix + ".xlsx";htmFileName = "xlsx_" + timesuffix + ".pdf";}else if("pptx".equals(type)){docFileName = "pptx_" + timesuffix + ".pptx";htmFileName = "pptx_" + timesuffix + ".pdf";}else{return null;}check_folder(pdfPath);File htmlOutputFile = new File(pdfPath + File.separatorChar + htmFileName);File docInputFile = new File(pdfPath + File.separatorChar + docFileName);if (htmlOutputFile.exists())htmlOutputFile.delete();htmlOutputFile.createNewFile();if (docInputFile.exists())docInputFile.delete();docInputFile.createNewFile();/*** 由fromFileInputStream構建輸入文件*/try {OutputStream os = new FileOutputStream(docInputFile);int bytesRead = 0;byte[] buffer = new byte[1024 * 8];while ((bytesRead = fromFileInputStream.read(buffer)) != -1) {os.write(buffer, 0, bytesRead);}os.close();fromFileInputStream.close();} catch (IOException e) {}OpenOfficeConnection connection = new SocketOpenOfficeConnection(8100);try {connection.connect();} catch (ConnectException e) {System.err.println("文件轉換出錯,請檢查OpenOffice服務是否啟動。");}DocumentConverter converter = new StreamOpenOfficeDocumentConverter(connection);converter.convert(docInputFile, htmlOutputFile);connection.disconnect();// 轉換完之后刪除word文件docInputFile.delete();System.out.println(htmFileName);return htmFileName;}public static void check_folder(String path) {File dir = new File(path);// 判斷文件夾是否存在if (dir.isDirectory()) {} else {dir.mkdirs();}}public static void copyFile(String oldPath, String newPath) throws IOException {File oldFile = new File(oldPath);//獲取舊的文件File對象File file = new File(newPath + oldFile.separator + StringUtils.substringAfterLast(oldPath, "/"));? //獲取新的文件File對象并生成文件FileInputStream in = new FileInputStream(oldFile);? //FileOutputStream out = new FileOutputStream(file);byte[] buffer=new byte[2097152];int readByte = 0;//讀取舊文件的流寫入新文件里while((readByte = in.read(buffer)) != -1){out.write(buffer, 0, readByte);}in.close();out.close();}}注意這里的連接openOffice的服務的端口要對應并且確保openOffice已經啟動
?然后工具類FilePdfUtils是在common模塊下,所以后臺需要在此模塊下pom文件中添加依賴
??????? <dependency><groupId>com.artofsolving</groupId><artifactId>jodconverter</artifactId><version>2.2.1</version></dependency>添加位置
注意這里的版本為2.2.1,Maven中央倉庫中此為最高版本
這里在調用工具類轉換文件時,如果文件類型為docx、pptx、xlsx時會報錯提示
unknown document format for file ....docx
這是因為2.2.1的能轉換doc ,但2.2.2才能轉換docx,如果你用2.2.1的jar包,轉換2.2.2的docx文檔就會出錯
除了不加載Maven中央倉庫的2.1的依賴之外,還可以重寫DocumentFormatRegistry接口的getFormatByFileExtension方法
注意包名一致
package com.artofsolving.jodconverter;import java.util.ArrayList; import java.util.Iterator; import java.util.List;/*** @ClassName: online* @description: 重寫 BasicDocumentFormatRegistry 文檔格式* @Author: yandongfa* @Data: 2020-03-24 19:47* @Version: 1.0**/ public class BasicDocumentFormatRegistry implements DocumentFormatRegistry {private List/* <DocumentFormat> */ documentFormats = new ArrayList();public void addDocumentFormat(DocumentFormat documentFormat) {documentFormats.add(documentFormat);}protected List/* <DocumentFormat> */ getDocumentFormats() {return documentFormats;}/*** @param extension*??????????? the file extension* @return the DocumentFormat for this extension, or null if the extension*???????? is not mapped*/public DocumentFormat getFormatByFileExtension(String extension) {if (extension == null) {return null;}//new DefaultDocumentFormatRegistry();//將文件名后綴統一轉化if (extension.indexOf("doc") >= 0) {extension = "doc";}if (extension.indexOf("ppt") >= 0) {extension = "ppt";}if (extension.indexOf("xls") >= 0) {extension = "xls";}String lowerExtension = extension.toLowerCase();for (Iterator it = documentFormats.iterator(); it.hasNext();) {DocumentFormat format = (DocumentFormat) it.next();if (format.getFileExtension().equals(lowerExtension)) {return format;}}return null;}public DocumentFormat getFormatByMimeType(String mimeType) {for (Iterator it = documentFormats.iterator(); it.hasNext();) {DocumentFormat format = (DocumentFormat) it.next();if (format.getMimeType().equals(mimeType)) {return format;}}return null;} }6、在線預覽實現
????????? <el-buttonsize="mini"type="text"icon="el-icon-edit"@click="handlePreview(scope.row)">預覽</el-button>調用js方法
??? // 預覽handlePreview(row) {let url = row.previewUrl;window.open(url);},這里直接打開url這個字段對應的地址即可,url是在進行文件轉換成pdf時生成的映射的服務器上的url
String previewUrl = serverConfig.getUrl()+ Constants.RESOURCE_PREFIX+File.separator+htmFileName;注意這里的預覽地址如果有攔截,讓在后臺配置中放開白名單。
7、文件下載實現
??? // 下載handleDownload(row) {const baseURL = process.env.VUE_APP_BASE_APIwindow.location.href = baseURL + "/common/download/resourceeasy?resource=" + encodeURI(row.uploadpath);},這里直接修改后臺的下載本地資源的通用下載方法
????@GetMapping("/common/download/resourceeasy")public void resourceDownloadEasy(String resource, HttpServletRequest request, HttpServletResponse response)throws Exception{try{if (!FileUtils.checkAllowDownload(resource)){throw new Exception(StringUtils.format("資源文件({})非法,不允許下載。 ", resource));}response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);FileUtils.setAttachmentResponseHeader(response, resource);FileUtils.writeBytes(resource, response.getOutputStream());}catch (Exception e){log.error("下載文件失敗", e);}}下載效果
8、各層完整代碼
前端完整代碼
<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-button type="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-columnshow-overflow-tooltiplabel="上傳后文件路徑"align="center"prop="uploadpath"/><el-table-columnshow-overflow-tooltiplabel="轉換pdf路徑"align="center"prop="pdfpath"width="400"/><el-table-columnshow-overflow-tooltiplabel="預覽地址"align="center"prop="previewUrl"width="400"/><el-table-column show-overflow-tooltip label="備注" align="center" prop="remark" /><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-input v-model="form.filename" placeholder="請輸入文件名" disabled /></el-form-item><el-form-item label="上傳后文件路徑" prop="uploadpath"><el-input v-model="form.uploadpath" placeholder="請輸入上傳后文件名" disabled /></el-form-item><el-form-item label="備注" prop="remark"><el-input v-model="form.remark" placeholder="請輸入備注"? /></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"accept=".doc,.docx,.xls,.ppt,.xlsx,.pptx"><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、.ppt、.xlsx、.pptx”格式文件!</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/system/preview"; import { getToken } from "@/utils/auth";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,filetype: null,uploadpath: null,pdfpath: null,pdfname: null,},// 表單參數form: {},// 表單校驗rules: {filename: [{required: true,message: "文件名稱不能為空",trigger: "blur",},],},// 上傳按鈕閘口btnLoding: false,//? 請求頭headers: { Authorization: "Bearer" + " " + getToken() },// 上傳地址url: process.env.VUE_APP_BASE_API + "/common/uploadWithAbsolutePath",// 圖片列表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,uploadpath: 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) {let url = row.previewUrl;window.open(url);},// 下載handleDownload(row) {const baseURL = process.env.VUE_APP_BASE_APIwindow.location.href = baseURL + "/common/download/resourceeasy?resource=" + encodeURI(row.uploadpath);},/** 提交按鈕 */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) {console.log(file, "上傳之前");const fileName = file.name;const fileType = fileName.substring(fileName.lastIndexOf("."));if (fileType === ".doc" ||fileType === ".docx" ||fileType === ".xls" ||fileType === ".ppt" ||fileType === ".pptx" ||fileType === ".xlsx") {this.form.filename = file.name;// 不處理} else {this.$message.error("請上傳正確的文件類型,.doc,.docx,.xls,.ppt,.xlsx,.pptx,");return false;}},// 文件上傳成功uploadSuccess(res, file, fileList) {this.form.uploadpath = res.uploadpath;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>前端js代碼
? import request from '@/utils/request'// 查詢preview列表 export function listPreview(query) {return request({url: '/system/preview/list',method: 'get',params: query}) }// 查詢preview詳細 export function getPreview(id) {return request({url: '/system/preview/' + id,method: 'get'}) }// 新增preview export function addPreview(data) {return request({url: '/system/preview',method: 'post',data: data}) }// 修改preview export function updatePreview(data) {return request({url: '/system/preview',method: 'put',data: data}) }// 刪除preview export function delPreview(id) {return request({url: '/system/preview/' + id,method: 'delete'}) }?后臺實體類
package com.ruoyi.system.domain;import com.ruoyi.common.annotation.Excel; import com.ruoyi.common.core.domain.BaseEntity; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle;public class BusFilePreview extends BaseEntity {private static final long serialVersionUID = 1L;/** 主鍵 */private Long id;/** 原文件名(上傳前文件名) */@Excel(name = "原文件名", readConverterExp = "上傳前文件名")private String filename;/** 文件后綴(.xls;.xlsx;.ppt;.doc;.docx;.pptx) */@Excel(name = "文件后綴", readConverterExp = ".=xls;.xlsx;.ppt;.doc;.docx;.pptx")private String filetype;/** 上傳后文件路徑 */@Excel(name = "上傳后文件路徑")private String uploadpath;/** 上傳后文件名 */@Excel(name = "上傳后文件名")private String uploadfilename;/** 轉換pdf路徑 */@Excel(name = "轉換pdf路徑")private String pdfpath;/** 轉換pdf文件名 */@Excel(name = "轉換pdf文件名")private String pdfname;/** 預覽地址 */@Excel(name = "預覽地址")private String previewUrl;public String getPreviewUrl() {return previewUrl;}public void setPreviewUrl(String previewUrl) {this.previewUrl = previewUrl;}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 setFiletype(String filetype){this.filetype = filetype;}public String getFiletype(){return filetype;}public void setUploadpath(String uploadpath){this.uploadpath = uploadpath;}public String getUploadpath(){return uploadpath;}public void setUploadfilename(String uploadfilename){this.uploadfilename = uploadfilename;}public String getUploadfilename(){return uploadfilename;}public void setPdfpath(String pdfpath){this.pdfpath = pdfpath;}public String getPdfpath(){return pdfpath;}public void setPdfname(String pdfname){this.pdfname = pdfname;}public String getPdfname(){return pdfname;}@Overridepublic String toString() {return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).append("id", getId()).append("filename", getFilename()).append("filetype", getFiletype()).append("uploadpath", getUploadpath()).append("uploadfilename", getUploadfilename()).append("pdfpath", getPdfpath()).append("pdfname", getPdfname()).append("createTime", getCreateTime()).append("createBy", getCreateBy()).append("updateTime", getUpdateTime()).append("updateBy", getUpdateBy()).append("remark", getRemark()).toString();} }后臺mapper.xml
? <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ruoyi.system.mapper.BusFilePreviewMapper"><resultMap type="BusFilePreview" id="BusFilePreviewResult"><result property="id"??? column="id"??? /><result property="filename"??? column="fileName"??? /><result property="filetype"??? column="fileType"??? /><result property="uploadpath"??? column="uploadPath"??? /><result property="uploadfilename"??? column="uploadFileName"??? /><result property="pdfpath"??? column="pdfPath"??? /><result property="pdfname"??? column="pdfName"??? /><result property="createTime"??? column="create_time"??? /><result property="createBy"??? column="create_by"??? /><result property="updateTime"??? column="update_time"??? /><result property="updateBy"??? column="update_by"??? /><result property="remark"??? column="remark"??? /><result property="previewUrl"??? column="preview_url"??? /></resultMap><sql id="selectBusFilePreviewVo">select id, fileName, fileType, uploadPath, uploadFileName, pdfPath, pdfName, create_time, create_by, update_time, update_by, remark ,preview_url from bus_file_preview</sql><select id="selectBusFilePreviewList" parameterType="BusFilePreview" resultMap="BusFilePreviewResult"><include refid="selectBusFilePreviewVo"/><where><if test="filename != null? and filename != ''"> and fileName like concat('%', #{filename}, '%')</if><if test="filetype != null? and filetype != ''"> and fileType = #{filetype}</if><if test="uploadpath != null? and uploadpath != ''"> and uploadPath = #{uploadpath}</if><if test="uploadfilename != null? and uploadfilename != ''"> and uploadFileName like concat('%', #{uploadfilename}, '%')</if><if test="pdfpath != null? and pdfpath != ''"> and pdfPath = #{pdfpath}</if><if test="pdfname != null? and pdfname != ''"> and pdfName like concat('%', #{pdfname}, '%')</if></where></select><select id="selectBusFilePreviewById" parameterType="Long" resultMap="BusFilePreviewResult"><include refid="selectBusFilePreviewVo"/>where id = #{id}</select><insert id="insertBusFilePreview" parameterType="BusFilePreview" useGeneratedKeys="true" keyProperty="id">insert into bus_file_preview<trim prefix="(" suffix=")" suffixOverrides=","><if test="filename != null">fileName,</if><if test="filetype != null">fileType,</if><if test="uploadpath != null">uploadPath,</if><if test="uploadfilename != null">uploadFileName,</if><if test="pdfpath != null">pdfPath,</if><if test="pdfname != null">pdfName,</if><if test="createTime != null">create_time,</if><if test="createBy != null">create_by,</if><if test="updateTime != null">update_time,</if><if test="updateBy != null">update_by,</if><if test="remark != null">remark,</if><if test="previewUrl != null">preview_url,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="filename != null">#{filename},</if><if test="filetype != null">#{filetype},</if><if test="uploadpath != null">#{uploadpath},</if><if test="uploadfilename != null">#{uploadfilename},</if><if test="pdfpath != null">#{pdfpath},</if><if test="pdfname != null">#{pdfname},</if><if test="createTime != null">#{createTime},</if><if test="createBy != null">#{createBy},</if><if test="updateTime != null">#{updateTime},</if><if test="updateBy != null">#{updateBy},</if><if test="remark != null">#{remark},</if><if test="previewUrl != null">#{previewUrl},</if></trim></insert><update id="updateBusFilePreview" parameterType="BusFilePreview">update bus_file_preview<trim prefix="SET" suffixOverrides=","><if test="filename != null">fileName = #{filename},</if><if test="filetype != null">fileType = #{filetype},</if><if test="uploadpath != null">uploadPath = #{uploadpath},</if><if test="uploadfilename != null">uploadFileName = #{uploadfilename},</if><if test="pdfpath != null">pdfPath = #{pdfpath},</if><if test="pdfname != null">pdfName = #{pdfname},</if><if test="createTime != null">create_time = #{createTime},</if><if test="createBy != null">create_by = #{createBy},</if><if test="updateTime != null">update_time = #{updateTime},</if><if test="updateBy != null">update_by = #{updateBy},</if><if test="remark != null">remark = #{remark},</if><if test="previewUrl != null">preview_url = #{previewUrl},</if></trim>where id = #{id}</update><delete id="deleteBusFilePreviewById" parameterType="Long">delete from bus_file_preview where id = #{id}</delete><delete id="deleteBusFilePreviewByIds" parameterType="String">delete from bus_file_preview where id in<foreach item="id" collection="array" open="(" separator="," close=")">#{id}</foreach></delete></mapper>?后臺mapper接口
package com.ruoyi.system.mapper;import com.ruoyi.system.domain.BusFilePreview;import java.util.List;/*** previewMapper接口** @author ruoyi* @date 2021-10-29*/ public interface BusFilePreviewMapper {/*** 查詢preview** @param id previewID* @return preview*/public BusFilePreview selectBusFilePreviewById(Long id);/*** 查詢preview列表** @param busFilePreview preview* @return preview集合*/public List<BusFilePreview> selectBusFilePreviewList(BusFilePreview busFilePreview);/*** 新增preview** @param busFilePreview preview* @return 結果*/public int insertBusFilePreview(BusFilePreview busFilePreview);/*** 修改preview** @param busFilePreview preview* @return 結果*/public int updateBusFilePreview(BusFilePreview busFilePreview);/*** 刪除preview** @param id previewID* @return 結果*/public int deleteBusFilePreviewById(Long id);/*** 批量刪除preview** @param ids 需要刪除的數據ID* @return 結果*/public int deleteBusFilePreviewByIds(Long[] ids); }后臺service接口
package com.ruoyi.system.service;import com.ruoyi.system.domain.BusFilePreview;import java.util.List;/*** previewService接口** @author ruoyi* @date 2021-10-29*/ public interface IBusFilePreviewService {/*** 查詢preview** @param id previewID* @return preview*/public BusFilePreview selectBusFilePreviewById(Long id);/*** 查詢preview列表** @param busFilePreview preview* @return preview集合*/public List<BusFilePreview> selectBusFilePreviewList(BusFilePreview busFilePreview);/*** 新增preview** @param busFilePreview preview* @return 結果*/public int insertBusFilePreview(BusFilePreview busFilePreview);/*** 修改preview** @param busFilePreview preview* @return 結果*/public int updateBusFilePreview(BusFilePreview busFilePreview);/*** 批量刪除preview** @param ids 需要刪除的previewID* @return 結果*/public int deleteBusFilePreviewByIds(Long[] ids);/*** 刪除preview信息** @param id previewID* @return 結果*/public int deleteBusFilePreviewById(Long id); }后臺serviceImpl
package com.ruoyi.system.service.impl;import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.system.domain.BusFilePreview; import com.ruoyi.system.mapper.BusFilePreviewMapper; import com.ruoyi.system.service.IBusFilePreviewService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;import java.util.List;/*** previewService業務層處理** @author ruoyi* @date 2021-10-29*/ @Service public class BusFilePreviewServiceImpl implements IBusFilePreviewService {@Autowiredprivate BusFilePreviewMapper busFilePreviewMapper;/*** 查詢preview** @param id previewID* @return preview*/@Overridepublic BusFilePreview selectBusFilePreviewById(Long id){return busFilePreviewMapper.selectBusFilePreviewById(id);}/*** 查詢preview列表** @param busFilePreview preview* @return preview*/@Overridepublic List<BusFilePreview> selectBusFilePreviewList(BusFilePreview busFilePreview){return busFilePreviewMapper.selectBusFilePreviewList(busFilePreview);}/*** 新增preview** @param busFilePreview preview* @return 結果*/@Overridepublic int insertBusFilePreview(BusFilePreview busFilePreview){busFilePreview.setCreateTime(DateUtils.getNowDate());busFilePreview.setCreateBy(String.valueOf(SecurityUtils.getUsername()));// 創建人return busFilePreviewMapper.insertBusFilePreview(busFilePreview);}/*** 修改preview** @param busFilePreview preview* @return 結果*/@Overridepublic int updateBusFilePreview(BusFilePreview busFilePreview){busFilePreview.setUpdateTime(DateUtils.getNowDate());busFilePreview.setUpdateBy(String.valueOf(SecurityUtils.getUsername()));// 創建人return busFilePreviewMapper.updateBusFilePreview(busFilePreview);}/*** 批量刪除preview** @param ids 需要刪除的previewID* @return 結果*/@Overridepublic int deleteBusFilePreviewByIds(Long[] ids){return busFilePreviewMapper.deleteBusFilePreviewByIds(ids);}/*** 刪除preview信息** @param id previewID* @return 結果*/@Overridepublic int deleteBusFilePreviewById(Long id){return busFilePreviewMapper.deleteBusFilePreviewById(id);} }后臺Controller
package com.ruoyi.web.controller.system;import com.ruoyi.common.annotation.Log; import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.pdf.FilePdfUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.config.ServerConfig; import com.ruoyi.system.domain.BusFilePreview; import com.ruoyi.system.service.IBusFilePreviewService; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.List;/*** previewController** @author ruoyi* @date 2021-10-29*/ @RestController @RequestMapping("/system/preview") public class BusFilePreviewController extends BaseController {@Autowiredprivate IBusFilePreviewService busFilePreviewService;@Autowiredprivate ServerConfig serverConfig;/*** 查詢preview列表*/@GetMapping("/list")public TableDataInfo list(BusFilePreview busFilePreview){startPage();List<BusFilePreview> list = busFilePreviewService.selectBusFilePreviewList(busFilePreview);return getDataTable(list);}/*** 獲取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("缺少文件名稱");}if (StringUtils.isNull(busFilePreview.getUploadpath())) {AjaxResult.error("缺少上傳文件路徑");}String substringAfter = StringUtils.substringAfter(busFilePreview.getUploadpath(), ".");String upName = StringUtils.substringAfterLast(busFilePreview.getUploadpath(), "/");busFilePreview.setUploadfilename(upName);busFilePreview.setFiletype(substringAfter); //類型if ("pdf".equals(substringAfter)){FilePdfUtils.copyFile(busFilePreview.getUploadpath(), RuoYiConfig.getProfile());String pdfName = StringUtils.substringAfterLast(busFilePreview.getUploadpath(), "/");busFilePreview.setPdfpath(RuoYiConfig.getProfile()+ "/" + pdfName);busFilePreview.setPdfname(pdfName);return? toAjax(busFilePreviewService.insertBusFilePreview(busFilePreview));}File file = new File(busFilePreview.getUploadpath());FileInputStream fileInputStream = new FileInputStream(file);String htmFileName = FilePdfUtils.file2pdf(fileInputStream, substringAfter,RuoYiConfig.getProfile());String pdfPath = RuoYiConfig.getProfile()+ "/" + htmFileName;busFilePreview.setPdfpath(pdfPath);String pdfName = StringUtils.substringAfterLast(pdfPath, "/");busFilePreview.setPdfname(pdfName);String previewUrl = serverConfig.getUrl()+ Constants.RESOURCE_PREFIX+File.separator+htmFileName;busFilePreview.setPreviewUrl(previewUrl);return toAjax(busFilePreviewService.insertBusFilePreview(busFilePreview));}/*** 修改preview*/@Log(title = "preview", businessType = BusinessType.UPDATE)@PutMappingpublic AjaxResult edit(@RequestBody BusFilePreview busFilePreview) throws IOException {if (StringUtils.isNull(busFilePreview.getFilename())) {AjaxResult.error("缺少文件名稱");}if (StringUtils.isNull(busFilePreview.getUploadpath())) {AjaxResult.error("缺少上傳文件路徑");}String substringAfter = StringUtils.substringAfter(busFilePreview.getUploadpath(), ".");String upName = StringUtils.substringAfterLast(busFilePreview.getUploadpath(), "/");busFilePreview.setUploadfilename(upName);busFilePreview.setFiletype(substringAfter); //類型if ("pdf".equals(substringAfter)){FilePdfUtils.copyFile(busFilePreview.getUploadpath(), RuoYiConfig.getProfile());String pdfName = StringUtils.substringAfterLast(busFilePreview.getUploadpath(), "/");busFilePreview.setPdfpath(RuoYiConfig.getProfile()+ "/" + pdfName);busFilePreview.setPdfname(pdfName);return? toAjax(busFilePreviewService.insertBusFilePreview(busFilePreview));}File file = new File(busFilePreview.getUploadpath());FileInputStream fileInputStream = new FileInputStream(file);String htmFileName = FilePdfUtils.file2pdf(fileInputStream, substringAfter,RuoYiConfig.getProfile());String pdfPath = RuoYiConfig.getProfile()+ "/" + htmFileName;busFilePreview.setPdfpath(pdfPath);String pdfName = StringUtils.substringAfterLast(pdfPath, "/");busFilePreview.setPdfname(pdfName);String previewUrl = serverConfig.getUrl()+ Constants.RESOURCE_PREFIX+File.separator+htmFileName;busFilePreview.setPreviewUrl(previewUrl);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));}@GetMapping("/pdf")@ApiOperation(value = "預覽")public void prePDF(Long id, HttpServletRequest request, HttpServletResponse response) throws IOException {BusFilePreview busFilePreview = busFilePreviewService.selectBusFilePreviewById(id);if (StringUtils.isNotNull(busFilePreview) && StringUtils.isNotNull(busFilePreview.getPdfpath())) {File file = new File(busFilePreview.getPdfpath());if (file.exists()) {byte[] data = null;try {FileInputStream input = new FileInputStream(file);data = new byte[input.available()];input.read(data);response.getOutputStream().write(data);input.close();} catch (Exception e) {e.printStackTrace();}} else if (!file.exists()){BusFilePreview filePreview = new BusFilePreview();filePreview.setId(id);filePreview.setRemark("文件不存在");busFilePreviewService.updateBusFilePreview(filePreview);}}} }后臺通用Controller
package com.ruoyi.web.controller.common;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.file.FileUploadUtils; import com.ruoyi.common.utils.file.FileUtils; import com.ruoyi.framework.config.ServerConfig;import java.io.File;/*** 通用請求處理** @author ruoyi*/ @RestController public class CommonController {private static final Logger log = LoggerFactory.getLogger(CommonController.class);@Autowiredprivate ServerConfig serverConfig;/*** 通用下載請求** @param fileName 文件名稱* @param delete 是否刪除*/@GetMapping("common/download")public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request){try{if (!FileUtils.checkAllowDownload(fileName)){throw new Exception(StringUtils.format("文件名稱({})非法,不允許下載。 ", fileName));}String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);String filePath = RuoYiConfig.getDownloadPath() + fileName;response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);FileUtils.setAttachmentResponseHeader(response, realFileName);FileUtils.writeBytes(filePath, response.getOutputStream());if (delete){FileUtils.deleteFile(filePath);}}catch (Exception e){log.error("下載文件失敗", e);}}/*** 通用上傳請求*/@PostMapping("/common/upload")public AjaxResult uploadFile(MultipartFile file) throws Exception{try{// 上傳文件路徑String filePath = RuoYiConfig.getUploadPath();// 上傳并返回新文件名稱String fileName = FileUploadUtils.upload(filePath, file);String url = serverConfig.getUrl() + fileName;AjaxResult ajax = AjaxResult.success();ajax.put("fileName", fileName);ajax.put("url", url);return ajax;}catch (Exception e){return AjaxResult.error(e.getMessage());}}/*** 通用上傳請求返回磁盤路徑*/@PostMapping("/common/uploadWithAbsolutePath")public AjaxResult uploadFileWithAbsolutePath(MultipartFile file) throws Exception{try{// 上傳文件路徑String filePath = RuoYiConfig.getUploadPath();// 上傳并返回新文件名稱String fileName = FileUploadUtils.uploadWithAbsolutePath(filePath, file);AjaxResult ajax = AjaxResult.success();ajax.put("uploadpath", filePath+ File.separator+fileName);return ajax;}catch (Exception e){return AjaxResult.error(e.getMessage());}}/*** 本地資源通用下載*/@GetMapping("/common/download/resource")public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)throws Exception{try{if (!FileUtils.checkAllowDownload(resource)){throw new Exception(StringUtils.format("資源文件({})非法,不允許下載。 ", resource));}// 本地資源路徑String localPath = RuoYiConfig.getProfile();// 數據庫資源地址String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);// 下載名稱String downloadName = StringUtils.substringAfterLast(downloadPath, "/");response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);FileUtils.setAttachmentResponseHeader(response, downloadName);FileUtils.writeBytes(downloadPath, response.getOutputStream());}catch (Exception e){log.error("下載文件失敗", e);}}/*** 本地資源通用下載*/@GetMapping("/common/download/resourceeasy")public void resourceDownloadEasy(String resource, HttpServletRequest request, HttpServletResponse response)throws Exception{try{if (!FileUtils.checkAllowDownload(resource)){throw new Exception(StringUtils.format("資源文件({})非法,不允許下載。 ", resource));}response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);FileUtils.setAttachmentResponseHeader(response, resource);FileUtils.writeBytes(resource, response.getOutputStream());}catch (Exception e){log.error("下載文件失敗", e);}} }總結
以上是生活随笔為你收集整理的SpringBoot+Vue+OpenOffice实现文档管理(文档上传、下载、在线预览)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Vue+Openlayer使用Draw实
- 下一篇: SpringBoot+Vue+Echar