Springboot图片上传【本地+oss】

文章目录

  • 1 前端组件页面
  • 2 本地上传
  • 3 上传到阿里云oss
    • 3.1申请开通账号,做好先导准备
    • 3.2 开始使用


1 前端组件页面

使用的Vue+Element组件

在线cdn引入:

<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.16/vue.js"></script>
<!-- 引入样式 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!-- 引入组件库 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">

组件页面,不是重点,不过多赘述

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>图片上传</title><script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.16/vue.js"></script><!-- 引入样式 --><script src="https://unpkg.com/element-ui/lib/index.js"></script><!-- 引入组件库 --><link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"><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><body><div id="app"><el-upload class="avatar-uploader" action="http://localhost:8080/upload/image" name="image":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></el-upload></div>
</body>
<script>new Vue({el: '#app',data: {imageUrl: ''},methods: {handleAvatarSuccess(res, file) {// this.imageUrl = URL.createObjectURL(file.raw);this.imageUrl = res.data;//console.log(res.data);//console.log(res.msg);//console.log(file.raw.name);//console.log(file.raw.type);},beforeAvatarUpload(file) {const isLt2M = file.size / 1024 / 1024 < 2;if (!isLt2M) {this.$message.error('上传头像图片大小不能超过 2MB!');}return isLt2M;}}})
</script>
</html>

注:
若是form表单,要注意数据提交的方式和格式:

<form action="/upload/upload" method="post" enctype="multipart/form-data"></form>

2 本地上传

注意:当文件提交的name和后端的参数名称不对应时,可以通过@RequestParam("xxx"),来指定名称,如果名称不对应,那么获取到就是空字符串""而不是null

在这里插入图片描述

顾名思义,就是在运行相关代码的服务器上存储上传的数据【图片、音频、文本等】
本案例是将图片文件上传之后,存储到本地打包之后的target\classes\static\imgs目录下,这样在项目启动的过程中,就可以进行图片的存储和访问。

前端提交的路径:action=“http://localhost:8080/upload/image”,图片存储完成之后,给前端返回一个图片存储的访问路径:http://localhost:8080/imgs/+文件名
文件名:使用的是uuid随机字符串,拼接上截取到的文件后缀名。
【使用时间戳作为文件名并不太好,在并发情况下,若同一时间多用户存储,就会导致图片被覆盖】

注意:
1、使用MultipartFile image
2、使用getOriginalFilename()获取文件名
3、通过transferTo()方法写入

@RestController
@RequestMapping("/upload")
@Slf4j
public class UploadController {@PostMapping("/image")public HashMap<String,Object> fileUpload(MultipartFile image){HashMap<String, Object> map = new HashMap<>();String filename = image.getOriginalFilename();if(filename!=null&& !"".equals(filename)){//文件最后一个“.”的位置int index = filename.lastIndexOf(".");//截取文件名String name = filename.substring(index);//拼接文件名String file = UUID.randomUUID().toString() + name;try {// 获取项目根目录String rootPath = System.getProperty("user.dir");// 拼接保存路径String savePath = rootPath + "/target/classes/static/imgs/" + file;File dest = new File(savePath);// 保存文件image.transferTo(dest);map.put("code",1);map.put("data","http://localhost:8080/imgs/"+file);map.put("msg","存储成功");} catch (IOException e) {map.put("code",0);map.put("msg","存储失败");}}else{map.put("code",0);map.put("msg","数据为空");}return map;}
}

3 上传到阿里云oss

3.1申请开通账号,做好先导准备

1、申请开通账号
2、创建bucket【制定存储空间】
3、获取自己的秘钥
在这里插入图片描述
在这里插入图片描述

最终需要准备好如下数据:
在这里插入图片描述
在yaml配置文件中写入上述数据内容,在后面的util中,使用@value注入。

3.2 开始使用

oss的使用是有专门的sdk文档的
在这里插入图片描述

这里以java为例https://help.aliyun.com/zh/oss/developer-reference/java-installation?spm=a2c4g.11186623.0.0.9e4c5b0frETztb

第一步,引入pom坐标

<dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.15.1</version>
</dependency>

如果使用的是Java 9及以上的版本,则需要添加JAXB相关依赖。添加JAXB相关依赖示例代码如下:

<dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.1</version>
</dependency>
<dependency><groupId>javax.activation</groupId><artifactId>activation</artifactId><version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency><groupId>org.glassfish.jaxb</groupId><artifactId>jaxb-runtime</artifactId><version>2.3.3</version>
</dependency>

第二步:快速上手,以上传文件为例
官方参考代码如下,在此基础上修改。

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import java.io.ByteArrayInputStream;public class Demo {public static void main(String[] args) throws Exception {// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();// 填写Bucket名称,例如examplebucket。String bucketName = "examplebucket";// 填写Object完整路径,例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。String objectName = "exampledir/exampleobject.txt";// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);try {String content = "Hello OSS";ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content.getBytes()));} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}}
}

确保在yaml文件中,已经准备好了前提要准备中的数据
application.yml

spring:#放行静态资源resources:static-locations: classpath:/templates,classpath:/static# 图片大小限制servlet:multipart:max-file-size: 10MBmax-request-size: 100MBalioss:endpoint: oss-cn-xxxxxxxx.aliyuncs.comaccess-key-id: LTxxxxxxxxxxxFK16N5MF3access-key-secret: rUzSTxxxxxxxxxx6Gub05w97d07KNbucket-name: hylxxx

注:两个关键点
new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);//创建对象
putObject(bucketName, objectName, new ByteArrayInputStream(bytes));//云端提交存储数据

编写AliOssUtil类

package com.hyl.utils;import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.io.ByteArrayInputStream;/*** @author hyl* @version 1.0* @date 2024/5/3-16:29*/
@Component
@Slf4j
public class AliOssUtil {@Value("${alioss.endpoint}")private String endpoint;@Value("${alioss.access-key-id}")private String accessKeyId;@Value("${alioss.access-key-secret}")private String accessKeySecret;@Value("${alioss.bucket-name}")private String bucketName;public String ossUpload(String objectName, byte[] bytes) {// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);try {ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}//阿里云oss中文件访问路径规则 https://BucketName.Endpoint/ObjectNameStringBuilder stringBuilder = new StringBuilder("https://");stringBuilder.append(bucketName).append(".").append(endpoint).append("/").append(objectName);log.info("文件上传到:{}", stringBuilder.toString());//返回图片存储路径return stringBuilder.toString();}
}

另一种注入方式,相对@Value的一种简化
在这里插入图片描述

编写controller

/*** @author hyl* @version 1.0* @date 2024/5/3-14:19*/
@RestController
@RequestMapping("/upload")
@Slf4j
public class UploadController {@Autowiredprivate AliOssUtil aliOssUtil;/*** 文件上传* @param file* @return*/@PostMapping("/upload")public HashMap<String,Object>upload(@RequestParam("image") MultipartFile file){log.info("文件上传:{}",file);HashMap<String, Object> map = new HashMap<>();try {//原始文件名String originalFilename = file.getOriginalFilename();//截取原始文件名的后缀   dfdfdf.pngString extension = originalFilename.substring(originalFilename.lastIndexOf("."));//构造新文件名称String objectName = UUID.randomUUID().toString() + extension;//文件的请求路径String filePath = aliOssUtil.ossUpload(objectName,file.getBytes());map.put("code",1);map.put("data",filePath);map.put("msg","存储成功");return map;} catch (IOException e) {log.error("文件上传失败:{}", e);}map.put("code",0);map.put("msg","存储失败");return map;}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Typescript语法

常量声明 let用于声明变量&#xff0c;而const用于声明常量。两者的区别是变量在赋值后可以修改&#xff0c;而常量在赋值后便不能修改。 const b:number 200; 类型判断 如果一个变量或常量的声明包含了初始值&#xff0c;TS便可以根据初始值进行类型判断&#xff0c;此时…

有限元分析

TOC在这里插入代码片 **应力挤压时的横截面内部力 剪应力&#xff1a;应力的相反力 法向力&#xff1a;施加的压力 与应力垂直 你好&#xff01; 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章&#xff0c;了解…

STM32入门学习之DMA

1.直接存储访问DMA(Direct Memory Access)&#xff1a;DMA传输不需要CPU的参与&#xff0c;直接在内存和I/O设备间开辟了一条新的数据传输通道&#xff0c;不仅提高数据传输的速率&#xff0c;还因为不需要CPU的干预&#xff0c;从而提高了CPU的利用率。(注&#xff1a;文中的资…

小红书API接口封装 | 根据笔记链接采集笔记详情,含正文内容、发布时间、转评赞藏等

一、背景介绍 1.1 爬取目标 用python开发的爬虫采集软件&#xff0c;可自动按笔记链接抓取笔记的详情数据。 为什么有了源码还开发界面软件呢&#xff1f;方便不懂编程代码的小白用户使用&#xff0c;无需安装python&#xff0c;无需改代码&#xff0c;双击打开即用&#xf…

零基础学习数据库SQL语句之操作表中数据的DML语句

我们的数据库是根据页面原型和相关需求完成相关开发的 在表中添加数据 删除数据 修改数据 添加数据 页面模型 当点击保存的时候就能将表单数据提交到服务端 服务端将数据添加到数据库 我们要用insert语句 将数据添加到数据库中 代码演示 CREATE DATABASE Dduo; USE Dduo…

在2-3-4树上实现连接与分裂操作的算法与实现

在2-3-4树上实现连接与分裂操作的算法与实现 引言1. 维护2-3-4树结点的高度属性伪代码示例 2. 实现连接操作伪代码示例 3. 证明简单路径p的划分性质4. 实现分裂操作伪代码示例 C代码示例结论 引言 2-3-4树是一种平衡搜索树&#xff0c;它保证了树的高度被有效控制&#xff0c;…

git学习指南

文章目录 一.版本控制1.认识版本控制2.版本控制功能3.集中式版本控制4.分布式版本控制 二.Git的环境安装搭建1.Git的安装2.Git配置分类3.Git配置选项 三.Git初始化本地仓库1. git init/git clone-获取Git仓库2. 本地仓库文件的划分3. git status-检测文件的状态4. git add-文件…

【Redis面试题】Redis常见的一些高频面试题

分享几个Redis入门级常见面试过程中遇到的题目! 你项目中哪里使用到了redis?可以讲一讲嘛 这个题目无论是大公司还是小公司都经常考,建议大家根据自己的项目做总结 redis的几种基础数据结构 redis为什么那么快&#xff1f; 1.基于内存实现&#xff1a;我们都知道内存读写是…

【neteq】tgcall的调用、neteq的创建及接收侧统计

G:\CDN\P2P-DEV\Libraries\tg_owt\src\call\call.cc基本是按照原生webrtc的来的:G:\CDN\P2P-DEV\tdesktop-offical\Telegram\ThirdParty\tgcalls\tgcalls\group\GroupInstanceCustomImpl.cpptg对neteq的使用 worker 线程创建call Call的config需要neteqfactory Call::CreateAu…

STM32单片机实战开发笔记-EXIT外部中断检测

嵌入式单片机开发实战例程合集&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/11av8rV45dtHO0EHf8e_Q0Q?pwd28ab 提取码&#xff1a;28ab EXIT模块测试 功能描述 外部中断/事件控制器由19个产生事件/中断要求的边沿检测器组成。每个输入线可以独立地配置输入类型&a…

【C++】学习笔记——string_5

文章目录 六、string类7. string类的模拟实现8. string类的模拟实现的完整代码string.h头文件test.c源文件 9. string收尾写时拷贝 未完待续 六、string类 7. string类的模拟实现 我们之前讲了实现 insert &#xff0c;但是那个插入函数仅仅是在 pos 位置插入一个字符而且&am…

二、nodejs连接数据库实现登录功能

// 数据库下载可以用这个 DBeaver安装与使用教程&#xff08;超详细安装与使用教程&#xff09;&#xff0c;好用免费的数据库管理工具_dbeaver使用教程-CSDN博客 模块化 &#xff08;1&#xff09;新建一个叫Dao的文件夹&#xff0c;存接数据库代码 // 参考数据库 &#xf…

自动驾驶-第02课软件环境基础(ROSCMake)

1. 什么是ros 2. 为什么使用ros 3. ROS通信 3.1 Catkin编译系统

prometheus的安装与部署及其有点

一、Prometheus 的优点 1、非常少的外部依赖&#xff0c;安装使用超简单&#xff1b; 2、已经有非常多的系统集成 例如&#xff1a;docker HAProxy Nginx JMX等等&#xff1b; 3、服务自动化发现&#xff1b; 4、直接集成到代码&#xff1b; 5、设计思想是按照分布式、微服…

Flutter笔记:Widgets Easier组件库(10)快速处理承若型对话

Flutter笔记 使用Widgets Easier组件库快速处理承若型对话 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://…

小程序账号设置以及request请求的封装

一般开发在小程序时&#xff0c;都会有测试版和正式版&#xff0c;这样在开发时会比较方便。 在开发时。产品经理都会给到测试账号和正式账号&#xff0c;后端给的接口也都会有测试环境用到的接口和正式环境用到的接口。 这里讲一讲我这边如何去做的。 1.在更目录随便命名一…

一机游领航旅游智慧化浪潮:借助前沿智能设备,革新旅游服务效率,构建高效便捷、生态友好的旅游服务新纪元,开启智慧旅游新时代

目录 一、引言 二、一机游的定义与特点 &#xff08;一&#xff09;一机游的定义 &#xff08;二&#xff09;一机游的特点 三、智能设备在旅游服务中的应用 &#xff08;一&#xff09;旅游前的信息查询与预订支付 &#xff08;二&#xff09;旅游中的导航导览与互动体…

MATLAB中功率谱密度计算pwelch函数使用详解

MATLAB中功率谱密度计算pwelch函数使用详解 目录 前言 一、pwelch函数简介 二、pwelch函数参数说明 三、pxx pwelch(x)示例 四、[pxx,f]pwelch(x,window,noverlap,nfft,fs)示例 四、[pxx,f] pwelch(x,window,noverlap,nfft,fs,freqrange,spectrumtype)示例 五、多通道功…

Springboot(SSM)项目实现数据脱敏

目录 一、引入hutool的依赖 二、sql脚本 三、自定义注解代码 3.1 自定义注解 3.2 自定义一个枚举,用于定义脱敏的类型 3.3 序列化 四、使用脱敏注解 4.1 Person.java 4.2 controller 4.3 dao 五、源代码参考 一、引入hutool的依赖 <dependency><groupId>…

FIFO Generate IP核使用——Native读写接口信号详解

Native FIFO接口信号是用于FIFO IP核与外部电路进行通信的信号。当FIFO支持独立的写和读时钟时&#xff0c;这些信号可以包括标准端口和可选端口。 1 当FIFO具有独立时钟时的接口信号 当FIFO具有独立的时钟时&#xff0c;其接口信号会相应地有所变化。特别是关于复位信号rst…