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.mzph.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;

【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,…

【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;比如需要费时费力去现场看房&…

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 等…

SpringBoot注解--09--idea创建spring boot项目,java版本只能选择17和21

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 idea创建spring boot项目1.问题描述2.原因3.解决方法方案一&#xff1a;升级JDK版本至17或更高方案二&#xff1a;替换Spring初始化的源https://start.aliyun.com i…

实时计算及异构计算随笔笔记

3、异构计算的典型应用 异构计算并不神秘&#xff0c;目前已渗透各个领域&#xff0c;不仅是PC领域&#xff0c;也包括了手持移动设备领域、行业领域&#xff0c;甚至是云计算、分布式计算领域。事实上&#xff0c;异构计算至少在应用端&#xff08;前台&#xff09;并不像它的…

ES的安装以及配置+ik分词

环境&#xff1a;windows10、ES&#xff08;8.13.3&#xff09;、Kibana&#xff08;8.13.3&#xff09;、Logstash&#xff08;8.13.3&#xff09;、ik&#xff08;8.13.3&#xff09; 1.下载安装ES Download Elasticsearch | ElasticDownload Elasticsearch or the complet…

AI预测体彩排3采取888=3策略+和值012路一缩定乾坤测试5月26日预测第2弹

今天继续基于8883的大底进行测试&#xff0c;昨天的预测已成功命中&#xff01;今天继续测试&#xff0c;按照排三前面的规律&#xff0c;感觉要出对子了&#xff0c;所以本次预测不再杀对子&#xff0c;将采用杀一个和尾来代替。好了&#xff0c;直接上结果吧~ 首先&#xff0…

mongoengine,一个非常实用的 Python 库!

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个超酷的 Python 库 - mongoengine。 Github地址&#xff1a;https://github.com/MongoEngine/mongoengine 在现代应用程序开发中&#xff0c;NoSQL数据库因其灵活性和高性能而广受欢迎。MongoD…