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

SpringBoot速成(14)文件上传P23-P26

1. 什么是 multipart/form-data

想象一下,你有一个包裹要寄给朋友,但包裹里有不同类型的东西:比如一封信(文字)、一张照片(图片)和一个小礼物(文件)。为了确保这些东西都能安全地送到朋友手里,你需要把它们分别包装好,然后放在一个大盒子里寄出去。

multipart/form-data 就是这样一个“大盒子”,它用来把不同类型的数据(比如文字、文件等)打包在一起,然后通过网络发送给服务器。

2. 为什么需要 multipart/form-data

当你需要上传文件(比如图片、文档)到服务器时,普通的表单数据(application/x-www-form-urlencoded)是不够用的,因为它只能发送文本数据,不能发送文件内容。而 multipart/form-data 可以同时发送文本和文件,就像一个多功能的快递盒子。

3.创建对象:alt+enter

4.假设用户上传了一个名为 photo.jpg 的文件,那么 file.getOriginalFilename() 的返回值就是 "photo.jpg"

file.getOriginalFilename():获取文件的原始文件名,例如用户上传的文件名。

file.transferTo(destFile):将上传的文件保存到服务器的指定路径。

5.文件上传:上传用户头像,上传文章图片

代码展示:

@RestController
public class FileUploadController {
    @SneakyThrows
    @PostMapping("/upload")
    public Result<String> upload(MultipartFile file){

       //原文件名
        String originalFilename = file.getOriginalFilename();
//        //文件名唯一:防止覆盖,用uuid拼成唯一的名字
//        String filename= UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));
        //把文件内容存到本地磁盘上
        file.transferTo(new File("C:\\Users\\enjoy\\Desktop\\files\\"+originalFilename));
        return Result.success("url访问地址...");
    }
}

运行:

换图片:

file未传上:

修改:1.yml中增加对上传文件大小的限制

  servlet:
    multipart:
      max-file-size: 300KB
      max-request-size: 300KB

2.磁盘路径有错

更改为:

运行成功:尽管在调试过程中postman运行几次,该图片上传好几次,但在磁盘中,若文件原名字相同,则覆盖:


优化:自己用还行,可以覆盖,但是若多个用户上传不同图片仅仅是名字相同就覆盖XXXXXXXXXXXXXXX 

1.UUID 是一个类,用来生成全局唯一标识符(Universally Unique Identifier)。每次调用 UUID.randomUUID() 都会生成一个独一无二的字符串,类似于 123e4567-e89b-12d3-a456-426614174000

作用:生成一个唯一的前缀,确保文件名不会重复。

2.originalFilename.lastIndexOf(".")

originalFilename 是上传文件的原始文件名,比如 photo.jpg

3.lastIndexOf(".") 是一个字符串方法,用来找到最后一个 . 的位置。对于文件名 photo.jpglastIndexOf(".") 会返回 5,因为 . 的位置是第 6 个字符(从 0 开始计数)。

作用:找到文件扩展名的起始位置。

4.substring(...) 是字符串方法,用来截取字符串的一部分。

originalFilename.substring(originalFilename.lastIndexOf(".")):从最后一个 . 开始截取到字符串的末尾。对于 photo.jpg,截取的结果是 .jpg

作用:获取文件的扩展名部分。

5.拼接字符串

把生成的唯一字符串(UUID)和文件扩展名拼接起来,形成一个新的文件名

  • 例如:

    • 原始文件名是 photo.jpg

    • 生成的 UUID123e4567-e89b-12d3-a456-426614174000

    • 最终生成的文件名是 123e4567-e89b-12d3-a456-426614174000.jpg

@RestController
public class FileUploadController {
    @SneakyThrows
    @PostMapping("/upload")
    public Result<String> upload(MultipartFile file){

       //原文件名
        String originalFilename = file.getOriginalFilename();
        //文件名唯一:防止覆盖,用uuid拼成唯一的名字
        String filename= UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));
        //把文件内容存到本地磁盘上
        file.transferTo(new File("C:\\Users\\enjoy\\Desktop\\files\\"+filename));
        return Result.success("url访问地址...");
    }
}

运行:相同文件名不覆盖:


优化:使用阿里云对象存储服务(OSS)

1.在输入图片地址时,现有" ",再在里边粘上地址->\\

2.Bucket本身可以理解为一个存储容器或逻辑空间,用于存储和组织数据。在对象存储系统中,Bucket列表帮助用户快速管理和调度资源

OSS使用过程:

1.创建bucket

2.创建AccessKey

3.点击SDK下载

4.yml中添加:

<!--    阿里云oss依赖坐标-->
    <dependency>
        <groupId>com.aliyun.oss</groupId>
        <artifactId>aliyun-sdk-oss</artifactId>
        <version>3.17.4</version>
    </dependency>


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

5.复制该类,并进行修改:

package com.itheima;

import java.io.ByteArrayInputStream;

import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;

public class Demo {

        public static void main(String[] args) throws Exception {
            // Endpoint以华北(北京)为例,其它Region请按实际情况填写。
            String endpoint = "https://oss-cn-beijing.aliyuncs.com";
            // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
//            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            String ACCESS_KEY_ID="自己填";
            String ACCESS_KEY_SSCREST="自己填";
            // 填写Bucket名称,例如big-event。
            String bucketName = "big-event";
            // 填写Object完整路径,完整路径中不能包含Bucket名称,例如001.png。
            String objectName ="001.png";
            // 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。
//            String region = "cn-hangzhou";

            // 创建OSSClient实例。
//            ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
//            clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
           OSS ossClient = new OSSClientBuilder().build(endpoint,ACCESS_KEY_ID,ACCESS_KEY_SSCREST);
//            .create()
//                    .endpoint(endpoint)
//                    .credentialsProvider(credentialsProvider)
//                    .clientConfiguration(clientBuilderConfiguration)
//                    .region(region)


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

                // 创建PutObjectRequest对象。
                PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new FileInputStream("C:\\Users\\enjoy\\Pictures\\001.png"));

                // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
                // 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();
                }
            }
        }
    }


运行:

点对象存储,快速进入OSS管理控制台

文件列表出现001.png

在浏览器地址栏粘贴地址,自动下载


结合源代码:

代码展示:

AliOssUtil:

package com.itheima.utils;

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.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;

import java.io.FileInputStream;
import java.io.InputStream;

public class AliOssUtil {

    private static String ENDPOINT = "https://oss-cn-beijing.aliyuncs.com";

    private static String ACCESS_KEY_ID="LTAI5tAi5kPgBPddtw9W1Cyk";
    private static String ACCESS_KEY_SSCREST="H7ATBUYZaKlcznauOO10LrpJYjdIuV";

    private static String BUCKETNAME= "big-eventxian";
    //会更改的是图片的名字和地址,把这两个提出来做参数
    //原方法名main,改名
    //方法运行后返回图片地址,所以返回值改为string
    public static String uploadFile(String objectName, InputStream in) throws Exception {

        OSS ossClient = new OSSClientBuilder().build(ENDPOINT,ACCESS_KEY_ID,ACCESS_KEY_SSCREST);
//添加返回值为空
        String url="";
//成功执行,并赋地址给url
        try {

            String content = "Hello OSS,你好世界";


            PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKETNAME, objectName, in);


            PutObjectResult result = ossClient.putObject(putObjectRequest);

            //url的格式https://big-eventxian.oss-cn-beijing.aliyuncs.com/001.png?Expires=1739886181&OSSAccessKeyId=TMP.3KkTvEibCf7tgTUtbapGLFhRg5NVwjJsi44ghDSZnxrzZkJdj3M4R1UeLCHQWg54L41EQYdqVE8rRhrpY7AC74ZsVCdNBX&Signature=PdGRCtze5IpO0bOnlEgHsRUuKLA%3D
            url="https://"+BUCKETNAME+"."+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;
    }

}

FileUploadController:

package com.itheima.controller;

import com.itheima.pojo.Result;
import com.itheima.utils.AliOssUtil;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.UUID;

@RestController
public class FileUploadController {
    @SneakyThrows
    @PostMapping("/upload")
    public Result<String> upload(MultipartFile file){

       //原文件名
        String originalFilename = file.getOriginalFilename();
//        //文件名唯一:防止覆盖,用uuid拼成唯一的名字
        String filename= UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));
        //把文件内容存到本地磁盘上
//        file.transferTo(new File("C:\\Users\\enjoy\\Desktop\\files\\"+originalFilename));
        String url=AliOssUtil.uploadFile(filename,file.getInputStream());
        return Result.success(url);
    }
}

运行成功:

但是点击data的url,访问失败:You have no right to access this object because of bucket acl.,意思是你没有权限访问这个对象,因为存储桶的访问控制列表(ACL)设置不允许。

修改方式: 

如果粘贴url到地址栏,可以直接下载:

相关文章:

  • 【JAVA实战】JAVA实现Excel模板下载并填充模板下拉选项数据
  • 【C++】36.C++IO流
  • 级联选择器多选动态加载
  • 洛谷P11042 [蓝桥杯 2024 省 Java B] 类斐波那契循环数
  • Linux系统配置阿里云yum源,安装docker
  • Step-Video-T2V:阶跃星辰发布最强开源视频生成模型(论文详解)
  • 《深度学习》——ResNet网络
  • 单纯禁用Cookie能否保证隐私安全?
  • 跳表的C语言实现
  • MySQL5.7 创建用户并授予超管权限脚本
  • uni-app发起网络请求的三种方式
  • 探讨如何加快 C# 双循环的速度效率
  • 【route】route add命令详解
  • 记一次一波三折的众测SRC经历
  • DevOps自动化部署详解:从理念到实践
  • DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方DeepSeek接入)
  • 从零搭建微服务项目Base(第5章——SpringBoot项目LogBack日志配置+Feign使用)
  • 开源AI智能名片2+1链动模式S2B2C商城小程序在社交价值挖掘中的应用与策略研究
  • Linux 网络安全技巧
  • ubuntu网络及软件包管理
  • 关税影响下沃尔玛想涨价,特朗普施压:自行承担,别转嫁给顾客
  • 李伟任山东省委常委、省纪委书记
  • 外交部介绍对巴西、阿根廷、智利、秘鲁、乌拉圭等5国试行免签政策
  • “三个集中”之后:图说浦东新区28次撤乡并镇
  • 加强战略矿产出口全链条管控将重点开展哪些工作?商务部答问
  • “75万买299元路由器”事件进展:重庆市纪委等三部门联合介入调查