5.【SpringBoot3】文件上传

news2024/10/2 10:34:50

1. 文件上传到本地

需求分析

在用户更换头像或发布文章时,需要携带一个图片的 url 地址,该 url 地址是当用户访问文件上传接口,将图片上传成功后,服务器返回的地址。所以,后台需要提供一个文件上传接口,用来接收前端提交的文件数据,并且返回文件的访问地址。

在这里插入图片描述

接口文档

在这里插入图片描述

文件上传知识回忆

前端页面文件上传三要素:

  • 请求方式必须是 post;
  • 表单的编码类型必须是 multipart/form-data;
  • 文件表单项对应的类型必须是 file。

在这里插入图片描述

这三个要素满足后,用户就可以选择要上传的文件,点击提交按钮,最终把文件内容提交给服务器。当服务器接收到该请求后,如果服务器中的代码是使用 SpringMVC 框架编写的,我们就可以在方法上声明一个 MultipartFile 类型的参数,用来接收上传的文件内容。MultipartFile 提供了很多方法:

在这里插入图片描述
接口实现思路

Controller 中声明用于上传文件的 upload()方法,方法内部需要借助 MultipartFile 提供的 api,把文件内容写入本地磁盘文件,因此方法上要声明一个 MultipartFile 类型的参数。

在这里插入图片描述

现在还没有把文件内容上传到阿里云服务器,我们先把文件存储到服务器本地,保证接口访问是正常的,接口没问题后,再把文件上传到服务器测试。

@RestController
public class FileUploadController {
    @PostMapping("/upload")
    public Result<String> upload(MultipartFile file) throws IOException {
        //把文件内容存储到本地磁盘

        //获取文件原始的名称
        String originalFilename = file.getOriginalFilename();
        //file.transferTo的异常直接抛出去
        //再次存储的时候使用原来的文件名
        file.transferTo(new File("C:\\Users\\xxx\\Desktop\\files\\"+originalFilename));
        return Result.success("url访问地址...");
    }
}

postman 测试:

在这里插入图片描述

点击 select file 选择要上传的文件:

在这里插入图片描述

打开文件:

在这里插入图片描述

上传成功:

在这里插入图片描述

在这里插入图片描述

但是,现在的代码中还存在bug。当我们在 postman 中针对刚刚选择的图片再次点击 send 时,files 文件夹中并没有出现两张图片。原因是后上传的图片与之前上传的图片重名,导致之前的图片被覆盖了。在现实中,很有可能出现需要上传两张同名图片的需求,比如两个用户上传的图片同名。因此这个问题需要解决一下。

解决方式就是保证上传时的文件名唯一:在文件后缀名前面拼接UUID:

在这里插入图片描述

再次上传:

在这里插入图片描述

现在只是通过将文件上传到本地的方式模拟了将文件上传到服务器的过程。下面来介绍将文件上传到服务器的实现方式。

2. 文件上传到云服务器

云服务器会提供很多服务,当计算机连接上云服务器并开通某个服务后后就可以使用该服务了。

在这里插入图片描述

在本节,我们使用阿里云的对象存储服务。

使用云对象存储 OSS(Object Storage Service),可以通过网络随时存储和调用包括文本、图片、音频和视频等在内的各种文件。

使用第三方服务的通用思路

  • 准备工作:在服务提供商网站上注册用户,开通对应服务
  • 参照官方 SDK 编写入门程序:引入阿里云 OSS 相关的 jar 包,并参照提供的示例代码编写程序
  • 参照入门程序,将功能集成到自己的代码中使用

SDK:Software Development Kit
的缩写,软件开发工具包,包括辅助软件开发的依赖(jar包)、代码示例等,都可以叫做SDK。

2.1 准备工作

在服务提供商网站上注册用户,开通对应服务

在这里插入图片描述

① 登录之后,点击控制台

在这里插入图片描述

② 查看阿里云提供的所有服务

在这里插入图片描述
在这里插入图片描述

③ 搜索对象存储 OSS

在这里插入图片描述

④ 首次使用 OSS 需要开通
在这里插入图片描述
⑤ 按照提示开通后,开始创建 bucket

在这里插入图片描述

⑥ 填写必要信息,创建 bucket

在这里插入图片描述

⑦ 创建成功后,进入 bucket

在这里插入图片描述

⑧ 概览中展示了 bucket 基本信息和访问地址

在这里插入图片描述

⑨ 获取 AccessKey:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

根据提示一步一步操作就能获取到 AccessKey。至此,准备工作完成。

2.2 参照官方 SDK 编写入门程序

导入阿里云 OSS 相关的依赖坐标,并参照提供的示例代码编写程序。

(1) 导入 OSS 相关依赖坐标

① 左侧点击概览:

在这里插入图片描述

② 滑动到底部,点击 SDK 下载

在这里插入图片描述

③ 找到 Java 版本,点击查看文档,会弹出帮助文档。点击“文档中心打开”

在这里插入图片描述

④ 点击”安装“

在这里插入图片描述

⑤ 将所需依赖坐标导入我们的 pom.xml 文件:

在这里插入图片描述

(2) 参照提供的示例代码编写程序

① 因为是要上传文件,所以点击:对象/文件➡上传文件➡简单上传

在这里插入图片描述

② 此处给出了一个示例代码,copy 一下

在这里插入图片描述

copy 的示例代码如下:

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完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
        String objectName = "exampledir/exampleobject.txt";

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        try {
            // 填写字符串。
            String content = "Hello OSS,你好世界";

            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new ByteArrayInputStream(content.getBytes()));

            // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
            // ObjectMetadata metadata = new ObjectMetadata();
            // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            // putObjectRequest.setMetadata(metadata);
           
            // 上传字符串。
            PutObjectResult result = ossClient.putObject(putObjectRequest);            
        } 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();
            }
        }
    }
}   

③ 修改示例代码

public class Demo {

    @Test
    public void test() throws Exception {
        // Endpoint:bucket概览中的访问端口->外网访问的地域节点
        String endpoint = "https://oss-cn-beijing.aliyuncs.com";
        // 阿里云为了防止AccessKeyId和AccessKeySecret泄露,建议以配置环境变量的方式来使用
        // 这里是测试代码,就不再配置环境变量了,直接定义两个变量来模拟,值都改成自己的
        String ACCESS_KEY_ID="**********";
        String ACCESS_KEY_SECRET="**********";
        // Bucket名称
        String bucketName = "big-event-bucket1";
        // 要存储的对象的名称,这里的对象可以是字符串、图片、视频等
        String objectName = "cat.jpg";

        // 创建OSSClient实例
        OSS ossClient = new OSSClientBuilder().build(endpoint, ACCESS_KEY_ID, ACCESS_KEY_SECRET);

        try {
            // 借助图片输入流对象构建出PutObjectRequest对象
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new FileInputStream("C:\\Users\\xxx\\Desktop\\cat.jpg"));

            // 上传到服务器
            PutObjectResult result = ossClient.putObject(putObjectRequest);
        } 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();
            }
        }
    }
}

(3) 运行代码

上传成功:

在这里插入图片描述

点击图片名称,弹出图片具体信息。复制图片在服务器上的 url。

在这里插入图片描述

在浏览器中输入图片在服务器上的 url,搜索。此时已从服务器上下载了图片。

在这里插入图片描述

虽然上面相对于阿里云提供的示例代码该类很多,但只要完成这个 Demo 的改造,今后在一般情况下需要改的地方就只有下面两处:要存储的对象的名称、输入流中要存储的对象在本地的位置。

在这里插入图片描述

2.3 案例集成 OSS

参照入门程序,将功能集成到自己的代码中使用。

为了使用方便,需要把上面改造成功的代码封装成一个工具类。将来哪里需要使用,直接调用工具类的方法即可。

public class AliOssUtil {
    //这四个一般不变,所以抽取到成员处,声明为静态常量
    public static final String ENDPOINT = "https://oss-cn-beijing.aliyuncs.com";//区域节点
    public static final String ACCESS_KEY_ID="LTAI5t9NJbszDF431vYUkzbh";
    public static final String ACCESS_KEY_SECRET="d82arCTGqH3Turz4HY3NA4a9RufHn0";
    public static final String BUCKET_NAME = "big-event-bucket1";// Bucket名称

    // objectName: 要存储的对象的名称,这里的对象可以是字符串、图片、视频等
    // 方法内部可能发生变化的是objectName和输入流,因此以参数的方式暴露出去
    // 方法要返回图片在服务器上的访问地址,因此返回值是String类型
    public static String upLoadFile(String objectName, InputStream inputStream) throws Exception {

        // 创建OSSClient实例
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        String url = ""; //为了返回url,先声明一个空字符串
        try {
            PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKET_NAME, objectName, inputStream);
            PutObjectResult result = ossClient.putObject(putObjectRequest);//上传到服务器
            //如果下面的代码不报错,就该给url赋值了
            //url组成:https://bucket名称.区域节点(去掉https://)/objectName
            //ENDPOINT.lastIndexOf("/")+1: 在ENDPOINT中,从最后一个"/"的下一个位置开始截取字符串
            url="https://"+BUCKET_NAME+"."+ENDPOINT.substring(ENDPOINT.lastIndexOf("/")+1)+"/"+objectName;
        } 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();
            }
        }
        return url;
    }
}

现在工具类准备好了,以后需要将文件上传阿里云只需调用 upLoadFile() 方法即可。

在 FileUploadController 中,之前我们将文件存储到了本地磁盘,现在不需要了,直接调用 upLoadFile() 方法将文件上传服务器。upLoadFile() 方法需要传递两个参数,filename 可以作为传入的第一个参数 objectName;第二个参数是文件输入流,MultipartFile 提供的 getInputStream() 方法可以提供该参数。最后将 upLoadFile() 方法返回的 url 响应给浏览器。

@RestController
public class FileUploadController {
    @PostMapping("/upload")
    public Result<String> upload(MultipartFile file) throws Exception {
        //把文件内容上传到阿里云服务器

        //获取原始文件名
        String originalFilename = file.getOriginalFilename();
        //使用UUID生成文件名,保证文件名唯一,从而防止文件被覆盖
        //originalFilename.lastIndexOf("."): 从文件名的最后一个"."处开始截取字符串(包括"."),即获取原始文件后缀名
        String filename = UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));
        // file.transferTo(new File("C:\\Users\\xxx\\Desktop\\files\\"+filename));
        //upLoadFile()方法上的异常直接抛出去即可
        String url = AliOssUtil.upLoadFile(filename, file.getInputStream());
        return Result.success(url);
    }
}

postman 测试:

在这里插入图片描述

在浏览器中输入文件访问地址,可以下载:

在这里插入图片描述

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

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

相关文章

Unity2020.3打包ARFoundation问题记录

文章目录 前言一、打包成功后再打包失败&#xff08;重启工程后&#xff09;二、URP管线总结 前言 在Unity 2020.3版本中使用ARFoundation进行打包时&#xff0c;遇到一些小问题。本文简要记录了其中一些问题及解决方法&#xff0c;以备不时之需。 一、打包成功后再打包失败&a…

嵌入式培训机构四个月实训课程笔记(完整版)-Linux ARM平台编程第四天-Bootloader编写2(物联技术666)

链接&#xff1a;https://pan.baidu.com/s/1eb94AaDM-cIZsbr929Isbw?pwd1688 提取码&#xff1a;1688 上午&#xff1a;bootloader的编写 下午&#xff1a;bootloader 教学内容&#xff1a; 1、vivi vivi有关nandflash MTD分区表控制命令: part show&#xff1a; …

python爬虫采集下载中国知网《出版来源导航》论文文献下载_PDF文档_数据采集知网爬虫论文Python3

时隔一年&#xff0c;很久没更新博客了。今天给大家带来一个python3采集中国知网 &#xff1a;出版来源导航 这个是网址是中国知网的&#xff0c;以下代码仅限于此URL&#xff08;出版来源导航&#xff09;采集&#xff0c;知网的其他网页路径采集不一定行&#xff0c;大家可以…

C++:vector容器(memcpy浅拷贝问题、迭代器失效问题)

文章目录 一. vector 的介绍二. vector 的使用1. string 和 vector<char> 的区别2. 为什么 vector 没有 find() 接口 三. vector 的模拟实现1. vector 的基本框架2. memcpy 和 memmove 的浅拷贝问题3. vector 迭代器失效问题4. 模拟代码 一. vector 的介绍 vector 的文档…

mysql调优-Join多种连接方式

简单嵌套循环连接 r为驱动表&#xff0c;s为匹配表&#xff0c;可以看到从r中分别取出每一个记录去匹配s表的列&#xff0c;然 后再合并数据&#xff0c;对s表进行r表的行数次访问&#xff0c;对数据库的开销比较大 索引嵌套循环连接 这个要求非驱动表&#xff08;匹配表s&…

【Python】01快速上手爬虫案例一:搞定豆瓣读书

文章目录 前言一、VSCodePython环境搭建二、爬虫案例一1、爬取第一页数据2、爬取所有页数据3、格式化html数据4、导出excel文件 前言 实战是最好的老师&#xff0c;直接案例操作&#xff0c;快速上手。 案例一&#xff0c;爬取数据&#xff0c;最终效果图&#xff1a; 一、VS…

EMQX 单机及集群搭建

目录 1. 通过 Yum 源安装&#xff08;CentOS7 单机安装&#xff09; 1.1. 通过以下命令配置 EMQX Yum 源&#xff1a; 1.2. 运行以下命令安装 EMQX&#xff1a; 1.3. 运行以下命令启动 EMQX&#xff1a; 1.4. 访问 http://192.168.88.130:18083&#xff0c;默认用户名: adm…

【斯坦福计网CS144项目】Lab2 实现一个简单的 TCP 接收类

&#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&#xff0c;你的&#x1f44d;点赞&#x1f64c;收藏❤️关注对我真的很重要&…

数据结构(C语言版)代码实现(四)——静态单链表的部分代码实现

目录 参考材料、格式 头文件SLinkList.h 库、宏定义、函数类型声明 线性表的静态单链表存储结构 按值查找 初始化静态链表 分配空间 回收空间 打印已用链表中的元素 求集合(A-B)U(B-A)中的元素&#xff08;重点介绍&#xff09; 调试过程 修改报错与警告 调试 完整…

何恺明 ResNet 引用量正式破20万!!!

注: 本文转自微信公众号 BravoAI (专注AI资讯和技术分享), 原文网址: 何恺明 ResNet 引用量正式破20万!!!, 扫码关注公众号 谷歌学术显示, 截止到 2024年1月26日, 何凯明 ResNet 一文引用量正式突破 20W!!! 更为惊人的是, 从论文发表到今天, 不过7年!!!‍‍‍‍‍‍‍‍‍‍‍‍…

6轴机器人运动正解-逆解控制【1】——三种控制位姿的方式

概览&#xff1a; 通过运动学正解控制机器人运动通过运动学逆解控制机器人运动一个简单的物体搬运&#xff08;沿轨迹运动&#xff09; 后续会陆续更新&#xff08;本例仅供学习交流用&#xff09; 一、6轴机器人 二、运动正解控制 通过修改各个轴的角度&#xff0c;实现末…

演示黄金票据,使用普通账户导入黄金票据创建域管理员

前提域搭建好了&#xff0c;域名是lin.com 首先我进入的是本机的用户不是域用户 我要是用本地用户&#xff0c;本地用户拿的票告诉我们这个TGS服务说我是域管账户administrator&#xff08;需要拿到域用户的哈希&#xff09; 此时进入到预控主机中&#xff08;人家是正儿八经…

Google Chrome RCE漏洞 CVE-2020-6507 和 CVE-2024-0517 流程分析

本文深入研究了两个在 Google Chrome 的 V8 JavaScript 引擎中发现的漏洞&#xff0c;分别是 CVE-2020-6507 和 CVE-2024-0517。这两个漏洞都涉及 V8 引擎的堆损坏问题&#xff0c;允许远程代码执行。通过EXP HTML部分的内存操作、垃圾回收等流程方式实施利用攻击。 CVE-2020-…

计算机网络 第6章(应用层)

系列文章目录 计算机网络 第1章&#xff08;概述&#xff09; 计算机网络 第2章&#xff08;物理层&#xff09; 计算机网络 第3章&#xff08;数据链路层&#xff09; 计算机网络 第4章&#xff08;网络层&#xff09; 计算机网络 第5章&#xff08;运输层&#xff09; 计算机…

MySQL十部曲之一:MySQL概述及手册说明

文章目录 数据库、数据库管理系统以及SQL之间的关系关系型数据库与非关系型数据库手册语法约定 数据库、数据库管理系统以及SQL之间的关系 名称说明数据库&#xff08;Database&#xff09;即存储数据的仓库&#xff0c;其本质是一个文件系统。它保存了一系列有组织的数据。数…

【第四天】蓝桥杯备战

题 1、求和2、天数3、最大缝隙 1、求和 https://www.lanqiao.cn/problems/1442/learning/ 解法&#xff1a;字符串方法的应用 import java.util.Scanner; // 1:无需package // 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {Scann…

xshell无法连接linux,查询本机ip时出现<NO-CARRIER,BROADCAST,MULTICAST,UP>

在用xshell连接虚拟机VMware中的linux时&#xff0c;发现昨天还能连通的&#xff0c;今天连接不了了 我寻思应该是网卡配置出问题了&#xff0c;就去终端ip addr试了一下&#xff0c;果然发现问题&#xff0c;ip 查看网卡ens33就发现出现ens33:<NO-CARRIER,BROADCAST,MULTI…

操作符详解(上)

目录 操作符的分类 二进制和进制转换 2进制转10进制 10进制转2进制数字 2进制转8进制 2进制转16进制 原码、反码、补码 移位操作符 左移操作符 右移操作符 位操作符&#xff1a;&、|、^、~ 单目操作符 逗号表达式 操作符的分类 • 算术操作符&#xff1a; …

无法获得dpkg前端锁、Linux之E: 无法锁定管理目录(/var/lib/dpkg/),是否有其他进程正占用它?(解决方法)

无法获得dpkg前端锁的解决方法 sudo rm /var/lib/dpkg/lock sudo rm /var/lib/dpkg/lock-frontend sudo rm /var/cache/apt/archives/lock 输入以上三个命令即可解除占用。解除后&#xff0c;继续运行apt命令&#xff0c;已经顺利运行了。解除前端锁后&#xff0c;Linux之E: 无…

自动写作软件有哪些?一次性分享5个好用软件

自动写作软件有哪些&#xff1f;随着科技的不断发展&#xff0c;自动写作软件逐渐进入了人们的视野。这些软件能够根据用户提供的关键词和主题&#xff0c;自动生成一篇完整的文章。这对于需要大量内容创作者来说&#xff0c;无疑是一个福音。下面介绍一些知名的自动写作软件&a…