当前位置: 首页 > news >正文

从前端到后端全面解析文件上传

从前端到后端全面解析文件上传

  • 1.前端准备(vue+element-ui)
  • 2.后端准备(SpringBoot+minio+mysql)
    • 2.1解决跨域
    • 2.2配置minio与mysql
    • 2.3controller层
    • 2.4service层

1.前端准备(vue+element-ui)

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>index</title><link rel="stylesheet" href="./element-ui/lib/theme-chalk/index.css"><link rel="stylesheet" href="css/index.css"><script src="js/vue.js"></script><script src="js/axios-0.18.0.js"></script><script src="./element-ui/lib/index.js"></script><style>.avatar-uploader .el-upload {border: 1px dashed #d9d9d9;border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;}.avatar-uploader .el-upload:hover {border-color: #409EFF;}.avatar-uploader-icon {font-size: 28px;color: #8c939d;width: 178px;height: 178px;line-height: 178px;text-align: center;}.avatar {width: 178px;height: 178px;display: block;}</style>
</head>
<style>
</style>
<body><div id="app"><el-uploadclass="avatar-uploader"action="http://localhost:8088/members/upload":show-file-list="false":on-success="handleAvatarSuccess":before-upload="beforeAvatarUpload"><img v-if="imageUrl" :src="imageUrl" class="avatar"><i v-else class="el-icon-plus avatar-uploader-icon"></i><p>{{name}}</p></el-upload>
</div><script>new Vue({el: "#app",data() {return {imageUrl: '',name:'',url:'',};},methods: {handleAvatarSuccess(res, file) {this.imageUrl = URL.createObjectURL(file.raw);this.name=file.response.namethis.url=file.response.urlconsole.log(file)},beforeAvatarUpload(file) {const isLt2M = file.size / 1024 / 1024 < 10;if (!isLt2M) {this.$message.error('上传头像图片大小不能超过 10MB!');}return isLt2M;}}})
</script>
</body>
</html>

2.后端准备(SpringBoot+minio+mysql)

2.1解决跨域

package com.data211.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;/*** @author rjj* @date 2023/2/3 - 15:15*/
@Configuration
public class GlobalCorsConfig {/*** 允许跨域调用的过滤器*/@Beanpublic CorsFilter corsFilter() {CorsConfiguration config = new CorsConfiguration();//允许白名单域名进行跨域调用(设置http://localhost:8080/ 表示指定请求源允许跨域)config.addAllowedOriginPattern("*");//允许跨越发送cookieconfig.setAllowCredentials(true);//放行全部原始头信息config.addAllowedHeader("*");//允许所有请求方法跨域调用config.addAllowedMethod("*");UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();//指定拦截路径source.registerCorsConfiguration("/**", config);return new CorsFilter(source);}
}

2.2配置minio与mysql

pom依赖

		<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</version></dependency><!--第三方工具jar包--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.17</version></dependency>

配置文件配置

server:port: 8088spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: username: rootpassword: mybatis-plus:mapper-locations: classpath:mapper/*.xml
#  配置别名type-aliases-package: com.data211.pojoglobal-config:db-config:
#      主键自增长id-type: auto
#      表名前缀table-prefix: data211_
#      逻辑删除logic-delete-value: 1logic-not-delete-value: 0
#      控制台输出操作数据库日志configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplminio:endpoint: accessKey: secretKey: bucket:files: 

配置minio客户端

package com.data211.config;import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/**@author rjj@date 2023/2/18 - 17:37
*/
@Configuration
public class MinioConfig {@Value("${minio.endpoint}")private String endpoint;@Value("${minio.accessKey}")private String accessKey;@Value("${minio.secretKey}")private String secretKey;@Beanpublic MinioClient minioClient() {MinioClient minioClient =MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();return minioClient;}
}

2.3controller层

  @RequestMapping(value = "/upload")public UploadFileResultDto upload(@RequestPart("file") MultipartFile file) throws IOException {return membersService.upload(file);};

2.4service层

package com.data211.service.impl;import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.data211.dao.MembersDao;
import com.data211.dto.UploadFileResultDto;
import com.data211.pojo.MediaFiles;
import com.data211.pojo.Members;
import com.data211.service.IMembersService;
import com.data211.utils.BaseContext;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;@Service
public class MembersServiceImpl extends ServiceImpl<MembersDao, Members> implements IMembersService {@Resourceprivate MinioClient minioClient;//普通文件桶@Value("${minio.bucket.files}")private String bucket_Files;@Resourceprivate MembersServiceImpl membersService;@Resourceprivate MediaFilesServiceImpl mediaFilesService;@Overridepublic UploadFileResultDto upload(MultipartFile file) throws IOException {String fileMd5 = DigestUtil.md5Hex(file.getBytes());String folder = getFileFolder(new Date(), true, true, true);String filename = fileMd5+file.getName().substring(file.getName().lastIndexOf("."));MediaFiles mediaFiles = null;try {//TODO 上传到minioaddMediaFilesToMinIO(file, bucket_Files, folder+filename);//TODO 上传到数据库 (用Spring控制的代理对象实现事务控制生效)mediaFiles = membersService.addMediaFilesToDb(BaseContext.getUserId(),filename,folder+filename);UploadFileResultDto uploadFileParamsDto = new UploadFileResultDto();BeanUtils.copyProperties(mediaFiles,uploadFileParamsDto);return uploadFileParamsDto;} catch (Exception e) {e.printStackTrace();}return null;}@Override@Transactionalpublic MediaFiles addMediaFilesToDb(String userId, String filename,String url) {MediaFiles mediaFiles = new MediaFiles(userId, filename, url);mediaFilesService.save(mediaFiles);return mediaFiles;}public void addMediaFilesToMinIO(MultipartFile file, String bucket, String objectName) throws IOException {//  将文件字节输入到内存流中ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(file.getBytes());//获取文件类型String contentType = file.getContentType();try {PutObjectArgs putObjectArgs =PutObjectArgs.builder().bucket(bucket).object(objectName)//-1 表示文件分片按 5M(不小于 5M,不大于 5T),分片数量最大10000.stream(byteArrayInputStream, byteArrayInputStream.available(), -1).contentType(contentType).build();minioClient.putObject(putObjectArgs);} catch (Exception e) {e.printStackTrace();}}private String getFileFolder(Date date, boolean year, boolean month, boolean day) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");//获取当前日期字符串String dateString = sdf.format(new Date());//取出年、月、日String[] dateStringArray = dateString.split("-");StringBuffer folderString = new StringBuffer();if (year) {folderString.append(dateStringArray[0]);folderString.append("/");}if (month) {folderString.append(dateStringArray[1]);folderString.append("/");}if (day) {folderString.append(dateStringArray[2]);folderString.append("/");}return folderString.toString();}}

相关文章:

从前端到后端全面解析文件上传

从前端到后端全面解析文件上传1.前端准备(vueelement-ui)2.后端准备(SpringBootminiomysql)2.1解决跨域2.2配置minio与mysql2.3controller层2.4service层1.前端准备(vueelement-ui) <!DOCTYPE html> <html lang"en"> <head><meta charset"…...

全网火爆,软件测试面试题大全,接口测试题+回答 (18k+的offer)

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 面试测试工程师的时…...

【iOS】—— 浅看block源码

block 文章目录block如何通过终端clang生成源码cpp文件block实质截获自动变量全局变量和静态变量的截获__block说明符iOS开发“强弱共舞”——weak和strong配套使用解决block循环引用问题如何通过终端clang生成源码cpp文件 之前在学习block中学习的比较浅&#xff0c;只看了oc…...

I.MX6ULL_Linux_系统篇(23) busybox文件系统构建

Linux“三巨头”已经完成了 2 个了&#xff0c;就剩最后一个 rootfs(根文件系统)了&#xff0c;本章我们就来学习一下根文件系统的组成以及如何构建根文件系统。这是 Linux 移植的最后一步&#xff0c;根文件系统构建好以后就意味着我们已经拥有了一个完整的、可以运行的最小系…...

shpjs将.zip文件转成geoJson

一、npm install shpjs二、import shp from shpjs三、async setLayerSource() {const geoJsonData await shp(dataUrl)}一直报错&#xff1a;是因为Buffer这个插件一直没找到Uncaught Error: nodebuffer is not supported by this browser解决办法npm install node-polyfill-w…...

eBay是不是一定要养号?是的

相信每个运营过eBay的用户遇到过这个棘手的问题&#xff0c;eBay个人账户的刊登数量是有限的&#xff0c;尤其是新账户只有5个sku&#xff0c;所以一开始的运营会比较艰难。想要快点走上正轨的话&#xff0c;就一定要去注重这个“养号”。eBay运营模式 1.拍卖 eBay最开始是一个…...

宝塔(二):升级JDK版本

目录 背景 一、下载JDK17 二、配置环境变量 三、配置新的JDK路径 背景 宝塔的软件商店只有JDK8&#xff0c;不满足我当前项目所需的JDK版本&#xff0c;因此想对JDK版本进行升级&#xff0c;升级为JDK17。 一、下载JDK17 先进入 /usr/lib/jvm 目录 点击终端&#xff0c;进…...

【LeetCode】螺旋矩阵 [M](数组)

54. 螺旋矩阵 - 力扣&#xff08;LeetCode&#xff09; 一、题目 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,…...

实验二:动态规划

1.双11的红包雨 问题描述 双11到了&#xff0c;据说这2天会下红包雨&#xff0c;每个红包有不同的价值&#xff0c;小k好开心&#xff0c;但有个规则&#xff0c;就只能接掉落在他身旁的10米范围内的红包&#xff08;0-10这11个位置&#xff09;。小k想尽可能的多抢红包&…...

华为机试 HJ27 查找兄弟单词

题目链接&#xff1a;https://www.nowcoder.com/practice/03ba8aeeef73400ca7a37a5f3370fe68?tpId37&tqId21250&rp1&ru/exam/oj/ta&qru/exam/oj/ta&sourceUrl%2Fexam%2Foj%2Fta%3Fdifficulty%3D3%26page%3D1%26pageSize%3D50%26search%3D%26tpId%3D37%26t…...

佩戴舒适的蓝牙耳机有哪些?佩戴舒适的蓝牙耳机推荐

音乐对许多人而言&#xff0c;都是一种抚慰生命的力量&#xff0c;特别是在上下班的时候&#xff0c;在熙熙攘攘的人流中&#xff0c;戴着耳机听一首动听的曲子&#xff0c;无疑会让人心情变得更加舒畅&#xff0c;要想获得出色的音乐体验&#xff0c;没有一副出色的耳机可不行…...

ESXI主机安装Zabbix 6.2

1&#xff1a;首先下载Zabbix Appliance 2&#xff1a;还需要下载VMware converter &#xff0c;这个需要VMware的账号&#xff0c;或者从其他地方下载也可以。 3:vmdk格式的 image 可直接在 VMware Player、 Server 和 Workstation 产品中使用。要在 ESX,、ESXi 和 vSphere 中…...

【Linux 网络编程1】使用UDP/TCP编写套接字,多进程/多线程版本的TCP编写的套接字,将套接字封装

目录 1.学习网络编程前的一些基础知识 2.UDP(user datagram protocol)协议的特点 3.使用有UPD编写套接字 4.使用TCP编写套接字 4.2.TCP客服端 4.3.TCP服务器端 4.4.单进程版本&#xff08;没有人会使用&#xff09; 4.5.多进程版本 4.6.多线程版本 5.把套接字封装 1…...

滑动窗口求最大和最小

滑动窗口 要区分最小和最大滑窗&#xff0c;内层while循环的条件和更新结果的地方 核心&#xff1a; 关键的区别在于&#xff0c;最大滑窗是在迭代右移右边界的过程中更新结果&#xff0c;而最小滑窗是在迭代右移左边界的过程中更新结果。 最小滑窗 给定数组 nums&#xff0…...

跟ChatGPT学量化,菜鸟炒股也不怕

你是一个python资深量化开发工程师&#xff0c;请介绍量化交易的基本框架 量化交易的基本框架包括以下几个步骤&#xff1a; 数据获取&#xff1a;获取市场数据和公司财务数据等&#xff0c;可以使用API接口、爬虫等方式获取。数据清洗和预处理&#xff1a;对获取到的数据进行清…...

扬帆优配|2600亿新能源巨头狂飙!外资唱多中国:再涨15%

全国停摆的危机&#xff0c;正在迫临法国。 大停工正在将法国推向风险境地。法国政府估计&#xff0c;当地时间3月7日&#xff0c;将迸发全国大型停工游行。法国总工会宣告&#xff0c;到时将让全法国停摆。法国担任交通业务的部长级代表克莱蒙博讷正告称&#xff0c;7日将成为…...

ChatGPT技术与商业模式及产业发展布局方案

文章目录模块一&#xff1a;概念模块二&#xff1a;架构模块三&#xff1a;技术模块四&#xff1a;算力模块五&#xff1a;体验模块六&#xff1a;应用模块七&#xff1a;商业模块八&#xff1a;产业模块九&#xff1a;建议结语主要内容&#xff1a; 采用模块化教学方法&#x…...

CIMCAI port ai shipping ai artificial intelligence smart port

上海人工智能独角兽中集集团高科技中集飞瞳&#xff0c;是全球应用落地最广&#xff0c;规模最大&#xff0c;最先进的的港航人工智能高科技企业&#xff0c;工业级成熟港航人工智能产品全球规模化落地应用&#xff0c;全球前三大船公司及港口码头应用落地。上海人工智能独角兽…...

《数据解构》HashMap源码解读

&#x1f451;作者主页&#xff1a;Java冰激凌 &#x1f4d6;专栏链接&#xff1a;数据结构 目录 了解HashMap HashMap的构造 两个参数的构造方法 一个参数的构造方法 不带参数的构造方法 哈希表初始化的长度 HashMap源码中的成员 Pt Get 了解HashMap 首先我们要明…...

Databend 开源周报 第 83 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.com 。Whats New探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。Support for WebHDFSHDFS 是大数…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法&#xff0c;当前调用一个医疗行业的AI识别算法后返回…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全&#xff0c;让Comfyui导出的图像不包含工作流信息&#xff0c;导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo&#xff08;推荐&#xff09;​​ 在 save_images 方法中&#xff0c;​​删除或注释掉所有与 metadata …...

【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案

目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后&#xff0c;迭代器会失效&#xff0c;因为顺序迭代器在内存中是连续存储的&#xff0c;元素删除后&#xff0c;后续元素会前移。 但一些场景中&#xff0c;我们又需要在执行删除操作…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

WPF八大法则:告别模态窗口卡顿

⚙️ 核心问题&#xff1a;阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程&#xff0c;导致后续逻辑无法执行&#xff1a; var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题&#xff1a…...