springboot + Vue前后端項目(第十一記)

項目實戰第十一記

  • 1.寫在前面
  • 2. 文件上傳和下載后端
    • 2.1 數據庫編寫
    • 2.2 工具類CodeGenerator生成代碼
      • 2.2.1 FileController
      • 2.2.2 application.yml
      • 2.2.3 攔截器InterceptorConfig 放行
  • 3 文件上傳和下載前端
    • 3.1 File.vue頁面編寫
    • 3.2 路由配置
    • 3.3 Aside.vue
  • 最終效果圖
  • 總結
  • 寫在最后

1.寫在前面

本篇主要講解文件的上傳和下載,進行前后端的實現

2. 文件上傳和下載后端

2.1 數據庫編寫

CREATE TABLE `sys_file` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',`name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '文件名稱',`type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '文件類型',`size` bigint(20) DEFAULT NULL COMMENT '文件大小(kb)',`url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '下載鏈接',`md5` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '文件md5',`is_delete` tinyint(1) DEFAULT '0' COMMENT '是否刪除',`enable` tinyint(1) DEFAULT '0' COMMENT '是否禁用鏈接',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

2.2 工具類CodeGenerator生成代碼

其他的正常生成,需要application.yml改動和controller編寫。需要注意的是File在java中重名了,換成Files即可(其他名稱也行)

2.2.1 FileController

package com.ppj.controller;import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ppj.entity.Files;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.List;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ppj.common.Result;import com.ppj.service.IFileService;import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;/*** <p>*  前端控制器* </p>** @author ppj* @since 2024-05-21*/
@RestController
@RequestMapping("/file")
public class FileController {@Resourceprivate IFileService fileService;@Value("${files.upload.path}")private String fileUploadPath;// 新增或者更新@PostMappingpublic Result save(@RequestBody Files file) {fileService.saveOrUpdate(file);return Result.success();}@DeleteMapping("/{fileIds}")public Result delete(@PathVariable Integer[] fileIds) {fileService.removeByIds(Arrays.asList(fileIds));return Result.success();}@GetMappingpublic Result findAll() {return Result.success(fileService.list());}@GetMapping("/page")public Result findPage(@RequestParam Integer pageNum,@RequestParam Integer pageSize,@RequestParam String name) {QueryWrapper<Files> queryWrapper = new QueryWrapper<>();queryWrapper.like("name",name);
//        queryWrapper.orderByDesc("id");return Result.success(fileService.page(new Page<>(pageNum, pageSize), queryWrapper));}/*** 文件上傳接口* @param file 前端傳遞過來的文件* @return* @throws IOException*/@PostMapping("/upload")public String upload(@RequestParam MultipartFile file) throws IOException {String originalFilename = file.getOriginalFilename();String type = FileUtil.extName(originalFilename);long size = file.getSize();// 定義一個文件唯一的標識碼String uuid = IdUtil.fastSimpleUUID();String fileUUID = uuid + StrUtil.DOT + type;File uploadFile = new File(fileUploadPath + fileUUID);// 判斷配置的文件目錄是否存在,若不存在則創建一個新的文件目錄File parentFile = uploadFile.getParentFile();if(!parentFile.exists()) {parentFile.mkdirs();}String url;// 獲取文件的md5String md5 = SecureUtil.md5(file.getInputStream());// 從數據庫查詢是否存在相同的記錄Files dbFiles = getFileByMd5(md5);if (dbFiles != null) { // 文件已存在,直接返回數據庫里的urlurl = dbFiles.getUrl();} else {  // 文件不存在才生成url,保存數據至數據庫// 上傳文件到磁盤file.transferTo(uploadFile);// 數據庫若不存在重復文件,則不刪除剛才上傳的文件url = "http://localhost:9000/file/" + fileUUID;// 存儲數據庫Files saveFile = new Files();saveFile.setName(originalFilename);saveFile.setType(type);saveFile.setSize(size/1024);saveFile.setUrl(url);saveFile.setMd5(md5);fileService.saveOrUpdate(saveFile);}return url;}/*** 通過文件的md5查詢文件* @param md5* @return*/private Files getFileByMd5(String md5) {// 查詢文件的md5是否存在QueryWrapper<Files> queryWrapper = new QueryWrapper<>();queryWrapper.eq("md5", md5);Files one = fileService.getOne(queryWrapper);return one != null ? one : null;}/*** 文件下載接口   http://localhost:9090/file/{fileUUID}* @param fileUUID* @param response* @throws IOException*/@GetMapping("/{fileUUID}")public void download(@PathVariable String fileUUID, HttpServletResponse response) throws IOException {// 根據文件的唯一標識碼獲取文件File uploadFile = new File(fileUploadPath + fileUUID);// 設置輸出流的格式ServletOutputStream os = response.getOutputStream();response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileUUID, "UTF-8"));response.setContentType("application/octet-stream");// 讀取文件的字節流os.write(FileUtil.readBytes(uploadFile));os.flush();os.close();}// 開啟和禁用其實就是更新@PostMapping("/update")public Result changeEnable(@RequestBody Files files){return fileService.saveOrUpdate(files)?Result.success():Result.error();}}

2.2.2 application.yml

# 上傳文件大小
spring:servlet:multipart:max-file-size: 10MB# 文件存儲路徑
files:upload:path: D:\實戰項目\前后端分離\后臺管理系統演示\files\

2.2.3 攔截器InterceptorConfig 放行

package com.ppj.config;import com.ppj.config.interceptor.JwtInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class InterceptorConfig implements WebMvcConfigurer {// 添加攔截器@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(jwtInterceptor()).addPathPatterns("/**")  // 攔截所有請求,通過判斷token是否合法來決定是否需要登錄.excludePathPatterns("/user/login", "/user/register", "/*/export", "/*/import","/file/**","/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/api", "/api-docs", "/api-docs/**").excludePathPatterns( "/*/*.html", "/*/*.js", "/*/*.css", "/*/*.woff", "/*/*.ttf");  // 放行靜態文件}@Beanpublic JwtInterceptor jwtInterceptor() {return new JwtInterceptor();}}

重點

  • 為了避免存儲重復的文件,使用md5作為文件唯一標識碼
  • 上傳時要生成并存儲這個文件的url,便于后面的下載和預覽等等

3 文件上傳和下載前端

3.1 File.vue頁面編寫

<template><div><div style="margin: 10px 0"><el-input style="width: 200px" placeholder="請輸入名稱" suffix-icon="el-icon-search" v-model="name"></el-input><el-button class="ml-5" type="primary" @click="getList">搜索</el-button><el-button type="warning" @click="resetQuery">重置</el-button></div><div style="margin: 10px 0"><el-upload action="http://localhost:9000/file/upload" :show-file-list="false" :on-success="handleFileUploadSuccess" style="display: inline-block"><el-button type="primary" class="ml-5">上傳文件 <i class="el-icon-top"></i></el-button></el-upload><el-button type="danger" class="ml-5" :disabled="multiple" @click="handleDelete">批量刪除 <i class="el-icon-remove-outline"></i></el-button></div><el-table :data="tableData" border stripe :header-cell-class-name="'headerBg'"  @selection-change="handleSelectionChange"><el-table-column type="selection" width="55"></el-table-column><el-table-column prop="id" label="ID" width="80"></el-table-column><el-table-column prop="name" label="文件名稱"></el-table-column><el-table-column prop="type" label="文件類型"></el-table-column><el-table-column prop="size" label="文件大小(kb)"></el-table-column><el-table-column label="下載"><template v-slot="scope"><el-button type="primary" @click="download(scope.row.url)">下載</el-button></template></el-table-column><!-- el-switch回顯問題 --><el-table-column label="啟用"><template v-slot="scope"><el-switch v-model="scope.row.enable":active-value="1":inactive-value="0"active-color="#13ce66" inactive-color="#ccc" @change="changeEnable(scope.row)"></el-switch></template></el-table-column><el-table-column label="操作"  width="200" align="center"><template v-slot="scope"><el-button type="danger" @click="handleDelete(scope.row)">刪除 <i class="el-icon-remove-outline"></i></el-button></template></el-table-column></el-table><div style="padding: 10px 0"><el-pagination@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="pageNum":page-sizes="[2, 5, 10, 20]":page-size="pageSize"layout="total, sizes, prev, pager, next, jumper":total="total"></el-pagination></div></div>
</template><script>
export default {name: "File",data() {return {tableData: [],name: '',multiple: true,pageNum: 1,pageSize: 10,total: 0,ids: [],}},created() {this.getList()},methods: {getList() {this.request.get("/file/page", {params: {pageNum: this.pageNum,pageSize: this.pageSize,name: this.name,}}).then(res => {this.tableData = res.data.recordsthis.total = res.data.total})},handleSizeChange(val) {this.pageSize = val;},handleCurrentChange(val) {this.pageNum = val;this.getList();},// 多選框選中數據handleSelectionChange(selection) {this.ids = selection.map(item => item.id);this.single = selection.length != 1;this.multiple = !selection.length;},// 重置按鈕resetQuery(){this.name = '';this.getList();},changeEnable(row) {this.request.post("/file/update", row).then(res => {if (res.code === '200') {this.$message.success("啟用成功")}})},// 刪除handleDelete(row){let _this = this;const fileIds = row.id || this.ids;this.$confirm('是否確認刪除文件編號為"' + fileIds + '"的數據項?', '刪除文件', {confirmButtonText: '確定',cancelButtonText: '取消',type: 'warning'}).then(() => {_this.request.delete("/file/"+fileIds).then(res=>{if(res.code === "200" || res.code === 200){_this.$message.success("刪除成功")}else {_this.$message.error("刪除失敗")}this.getList();})}).catch(() => {});},handleFileUploadSuccess(res) {// console.log(res)this.getList()},download(url) {window.open(url)}}
}
</script><style scoped></style>

3.2 路由配置

{path: 'file',name: '文件管理',component: () => import('../views/File.vue'),meta: {title: '文件管理'}
},

3.3 Aside.vue

<el-menu-item index="/file"><i class="el-icon-files"></i><span slot="title">文件管理</span>
</el-menu-item>

最終效果圖

在這里插入圖片描述

總結

  • 輕松實現文件上傳和下載的前后端

寫在最后

如果此文對您有所幫助,請帥戈靚女們務必不要吝嗇你們的Zan,感謝!!不懂的可以在評論區評論,有空會及時回復。
文章會一直更新

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/16061.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/16061.shtml
英文地址,請注明出處:http://en.pswp.cn/web/16061.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

TabAttention:基于表格數據的條件注意力學習

文章目錄 TabAttention: Learning Attention Conditionally on Tabular Data摘要方法實驗結果 TabAttention: Learning Attention Conditionally on Tabular Data 摘要 醫療數據分析通常結合成像數據和表格數據處理&#xff0c;使用機器學習算法。盡管先前的研究探討了注意力…

Hudi 多表攝取工具 HoodieMultiTableStreamer 配置方法與示例

博主歷時三年精心創作的《大數據平臺架構與原型實現&#xff1a;數據中臺建設實戰》一書現已由知名IT圖書品牌電子工業出版社博文視點出版發行&#xff0c;點擊《重磅推薦&#xff1a;建大數據平臺太難了&#xff01;給我發個工程原型吧&#xff01;》了解圖書詳情&#xff0c;…

vue3添加收藏網站頁面

結構與樣式 <template><div class"web_view"><ul><li v-for"web in webList" :key"web.title"><a :href"web.src" :title"web.title" target"_blank"><img :src"web.img&…

微信小程序基礎 -- 小程序UI組件(5)

小程序UI組件 1.小程序UI組件概述 開發文檔&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/framework/view/component.html 什么是組件&#xff1a; 組件是視圖層的基本組成單元。 組件自帶一些功能與微信風格一致的樣式。 一個組件通常包括 開始標簽 和 結…

Cyber Weekly #8

賽博新聞 1、微軟召開年度發布會Microsoft Build 2024 本周&#xff08;5.22&#xff09;微軟召開了年度發布會&#xff0c;Microsoft Build 2024&#xff0c;發布了包括大殺器 Copilot Studio 在內的 50 項更新。主要包括&#xff1a; 硬件層面&#xff1a;與英偉達 & A…

3D牙科網格分割使用基于語義的特征學習與圖變換器

文章目錄 3D Dental Mesh Segmentation Using Semantics-Based Feature Learning with Graph-Transformer摘要方法實驗結果 3D Dental Mesh Segmentation Using Semantics-Based Feature Learning with Graph-Transformer 摘要 本文提出了一種新穎的基于語義的牙科網格分割方…

民國漫畫雜志《時代漫畫》第16期.PDF

時代漫畫16.PDF: https://url03.ctfile.com/f/1779803-1248612470-6a05f0?p9586 (訪問密碼: 9586) 《時代漫畫》的雜志在1934年誕生了&#xff0c;截止1937年6月戰爭來臨被迫停刊共發行了39期。 ps:資源來源網絡&#xff01;

代碼隨想錄訓練營總結

歷經60天的訓練營終于結束啦&#xff0c;感覺自己兩個月前做的這個決定非常正確&#xff0c;非常感謝卡哥和卡哥助手&#xff0c;從一個代碼沒有系統刷題沒有體系的小白到現在已經有了一些基礎&#xff0c;也具備一些刷題的習慣和手感&#xff0c;如果是我自己沒有規劃的刷可能…

【C++】二分查找:在排序數組中查找元素的第一個和最后一個位置

1.題目 難點&#xff1a;要求時間復雜度度為O(logn)。 2.算法思路 需要找到左邊界和右邊界就可以解決問題。 題目中的數組具有“二段性”&#xff0c;所以可以通過二分查找的思想進行解題。 代碼&#xff1a; class Solution { public:vector<int> searchRange(vect…

Camunda BPM主要組件

Camunda BPM是使用java開發的,核心流程引擎運行在JVM里,純java庫,不依賴其他庫或者底層操作系統。可以完美地與其他java框架融合,比如Spring。除了核心流程引擎外,還提供了一系列的管理,操作和監控工具。 1,工作流引擎 既適用于服務或者微服務編排,也適用于人工任務管…

Leetcode42題:接雨水

1.題目描述 給定 n 個非負整數表示每個寬度為 1 的柱子的高度圖&#xff0c;計算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例1&#xff1a; 輸入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 輸出&#xff1a;6 解釋&#xff1a;上面是由數組 [0,1,0,2,1,0,1,…

hadoop節點添加與刪除測試

hadoop節點上下線 docker run -d --name hd1 -p 8888:8888 -p 2222:22 centos:basic init docker run -d --name hd2 -p 8889:8889 centos:basic init docker run -d --name hd3 centos:basic init# hosts echo "172.17.0.2 hadoop1 172.17.0.3 hadoop2 172.17.0.4 hadoo…

網絡協議:CSMA/CD 和 CSMA/CA

當多臺設備共享同一通信信道時&#xff0c;避免數據傳輸沖突至關重要。本文將探討兩種廣泛使用的協議&#xff1a;CSMA/CD&#xff08;Carrier Sense Multiple Access with Collision Detection&#xff09;和CSMA/CA&#xff08;Carrier Sense Multiple Access with Collision…

【C語言】二叉樹的實現

文章目錄 前言?一、二叉樹的定義&#x1f6b2;二、創建二叉樹&#x1f3a1;三、二叉樹的銷毀&#x1f389;四、遍歷二叉樹1. 前序遍歷2. 中序遍歷3. 后序遍歷4. 層序遍歷 &#x1f332;五、二叉樹的計算1. 計算二叉樹結點個數2. 計算二叉樹葉子結點的個數3. 計算二叉樹的深度4…

一、Elasticsearch介紹與部署

目錄 一、什么是Elasticsearch 二、安裝Elasticsearch 三、配置es 四、啟動es 1、下載安裝elasticsearch的插件head 2、在瀏覽器&#xff0c;加載擴展程序 3、運行擴展程序 4、輸入es地址就可以了 五、Elasticsearch 創建、查看、刪除索引、創建、查看、修改、刪除文檔…

【MySQL】——并發控制

&#x1f4bb;博主現有專欄&#xff1a; C51單片機&#xff08;STC89C516&#xff09;&#xff0c;c語言&#xff0c;c&#xff0c;離散數學&#xff0c;算法設計與分析&#xff0c;數據結構&#xff0c;Python&#xff0c;Java基礎&#xff0c;MySQL&#xff0c;linux&#xf…

計算機畢業設計 | springboot+vue房屋租賃管理系統(附源碼)

1&#xff0c;緒論 1.1 課題來源 隨著社會的不斷發展以及大家生活水平的提高&#xff0c;越來越多的年輕人選擇在大城市發展。在大城市發展就意味著要在外面有一處安身的地方。在租房的過程中&#xff0c;大家也面臨著各種各樣的問題&#xff0c;比如需要費時費力去現場看房&…

oj項目后端分析

1.菜單管理 我們菜單管理有菜單表(sys_menu)&#xff0c;還有用戶角色表&#xff08;sys_role&#xff09;&#xff0c;菜單表是用于管理我們用戶所擁有的權限&#xff0c;不同的用戶所看到的頁面是不一樣的&#xff0c;由于一些用戶他能夠看到題庫管理和考題管理&#xff0c;還…

Anaconda Anaconda支持什么編程語言的環境配置

Anaconda是一個數據科學和機器學習的開發環境&#xff0c;它支持多種編程語言的環境配置&#xff0c;包括&#xff1a; Python&#xff1a;Anaconda默認安裝了Python和必需的Python庫&#xff0c;可以方便地進行Python編程和數據分析。 R&#xff1a;Anaconda也可以配置R語言環…

Aws EC2 + Aws Cli + Terraform

1 什么是 Terraform&#xff1f; Terraform 是由 HashiCorp 創建的“基礎架構即代碼”(Infrastructure-as-Code&#xff0c;IaC)開源工具。Terraform 的配置語言是 HashiCorp Configuration Language&#xff08;HCL&#xff09;&#xff0c;用來替代更加冗長的 JSON 和 XML 等…