基于spring boot实现本都文件上传和阿里云OSS文件上传,以及spring boot的配置文件

2023-12-14 16:50:10

文件上传的简介:

  • 文件上传:是指将本地图片、视频、音频等文件上传到服务器,供其他用户浏览或下载的过程。
  • 文件上传在项目中应用非常广泛,我们经常发微博、发微信朋友圈都用到了文件上传功能。

?

前端页面三要素:
  1. 文件选择输入框(File Input):提供给用户选择本地文件的输入框。

  2. 表单(Form):包含用于提交文件的表单,需要设置enctype属性为"multipart/form-data"。

  3. 提交按钮(Submit Button):用于用户点击提交上传文件的操作。

后端接收:

  1. 使用@RequestParam注解:在Controller的方法参数上添加@RequestParam注解,并指定参数名,Spring会自动将上传的文件绑定到该参数上。
  2. 使用MultipartHttpServletRequest:如果需要同时接收上传的文件和其他表单数据,可以使用MultipartHttpServletRequest来获取请求中的文件和表单数据。

在resources目录下面的static文件夹里面,创建一个html页面

?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>上传文件</title>
</head>
<body>

    <form action="/upload" method="post" enctype="multipart/form-data">
        姓名: <input type="text" name="username"><br>
        年龄: <input type="text" name="age"><br>
        头像: <input type="file" name="file"><br>
        <input type="submit" value="提交">
    </form>

</body>
</html>

测试一下:

新建一个 UploadController控制器类

    @PostMapping("/upload")
    public Result upload(String username, Integer age, MultipartFile file){
        log.info("用户名,{}年龄,{}file文件{}",username,age,file);
        return Result.success();
    }

在浏览器地址栏,输入 http://localhost:端口号+这个html的名称

http://localhost:8080/upload.html

打开浏览器查看:

看idea控制台:

通过Debug启动:

可以看到在访问这个接口的时候,已经获取到了前端传递来的数据。

根据提示找到文件的位置,复制在电脑里面访问。

复制刚才的路径在电脑的磁盘上面找到了,刚刚前端传递过来的临时文件。

我把后台执行完,发现这几个临时文件没有了。

怎么样才能保存下来呢,后面我提供了两种方案。

本地存储:

在服务端,接收到上传上来的文件之后,将文件存储在本地服务器磁盘中。

    @PostMapping("/upload")
    public Result uploadTest(String username,Integer age,MultipartFile file) throws Exception {
        // 获取文件的原始名称
        String oldName = file.getOriginalFilename();
        //截取元素文件的后缀名
        String substring = oldName.substring(oldName.lastIndexOf("."));
        //生成一个唯一,不重复的文件名
        String uname = UUID.randomUUID().toString();
        //拼接一个新的文件名称
        String newFileName = uname+substring;
        //把上传到服务器的文件,转存到本地磁盘
        file.transferTo(new File("G:\\resources\\"+newFileName));
        return Result.success();
    }
MultipartFile 类常用的方法:
  • transferTo(File dest): 将接收到的文件转存到磁盘文件中
  • getOriginalFilename(): 获取原始文件名
  • getSize(): 获取文件的大小,单位:字节
  • getBytes(): 获取文件内容的字节数组
  • getInputStream(): 获取接收到的文件内容的输入流

然后进行测试:

把我准备好的中国梦.txt 文本文件 上传到我本地磁盘指定的目录

可以发现已经上传成功了

这个时候的1.txt是一个文本文件。

?我们在测试一次

我把java.txt 上传到我执行名称和目录的磁盘中

查看效果:

可以发现原本,1.txt文本文件里面的数据,被覆盖了。

文件上传不重名问题:

?分析得知,我在进行文件上传的时候,文件类型和文件名都是写死的,但是我不能写死,因为,后面上传的时候,我们无法确定要上传文件的类型(jpg,png,txt,xml)很多,所以文件名和文件类型,是要改变的。

① 文件名不能重复

②文件类型要根据上传时的类型决定

UUID:

?UUID?(Universally?Unique?Identifier)通用唯一识别码,128位。RFC 4122描述了具体的规范实现。?

然后通过字符串截取,获取到上传文件的后缀。

    public Result uploadTest(String username,Integer age,MultipartFile file) throws Exception {
        // 获取文件的原始名称
        String oldName = file.getOriginalFilename();
        //截取元素文件的后缀名
        String substring = oldName.substring(oldName.lastIndexOf("."));
        //生成一个唯一,不重复的文件名
        String uname = UUID.randomUUID().toString();
        //拼接一个新的文件名称
        String newFileName = uname+substring;
        
    }

?上传到本地服务器最后的改进:

    @PostMapping("/upload")
    public Result uploadTest(String username,Integer age,MultipartFile file) throws Exception {
        // 获取文件的原始名称
        String oldName = file.getOriginalFilename();
        //截取元素文件的后缀名
        String substring = oldName.substring(oldName.lastIndexOf("."));
        //生成一个唯一,不重复的文件名
        String uname = UUID.randomUUID().toString();
        //拼接一个新的文件名称
        String newFileName = uname+substring;
        //把上传到服务器的文件,转存到本地磁盘
        file.transferTo(new File("G:\\resources\\"+newFileName));
        return Result.success();
    }

现在进行测试:

在测试:

点击提交,报错了,然后我们查看控制台输出的错误信息。

百度翻译下:

上传文件过大了

配置文件上传文件大小:

在SpringBoot中,文件上传,默认单个文件允许最大大小为 1M。如果需要上传大文件,可以进行如下配置:

#文件上传配置

#配置单个文件最大上传大小 spring.servlet.multipart.max-file-size=10MB

#配置单个请求最大上传大小(一次请求可以上传多个文件)

spring.servlet.multipart.max-request-size=100MB

  # spring 文件上传修改单个上传文件大小的配置和一次请求的文件上传大小的配置
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 100MB

配置文件写好之后,在进行测试:

测试成功了:

看看我的文件夹里面是否多了一个ppt

那我们的本地上传就写成功了。

阿里云OSS:

本地服务器上传有一个缺点就是,如果服务器崩溃了就不能在访问了。

阿里云是阿里巴巴集团旗下全球领先的云计算公司,也是国内最大的云服务提供商 。

阿里云对象存储OSS(Object Storage Service),是一款海量、安全、低成本、高可靠的云存储服务。使用OSS,您可以通过网络随时存储和调用包括文本、图片、音频和视频等在内的各种文件。

我们前面上传的是从本地到我们自己的服务器,现在上传到阿里云OSS

通用思路:

SDK:

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

Bucket:

Bucket:存储空间是用户用于存储对象(Object,就是文件)的容器,所有的对象都必须隶属于某个存储空间。

使用步骤:

1,引入阿里云OSS上传文件工具类(由官方的示例代码改造而来)。

2,上传图片接口开发。

引入依赖:

<!--        阿里云oss-->
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.15.1</version>
        </dependency>
<!--        jdk1.9版本以上需要额外加上面三个依赖-->
        <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>

上传图片接口开发:

封装提供一个?AliyunOSSUtils的工具类。

/**
 * 阿里云OSS操作工具类
 */
@Slf4j
public class AliyunOSSUtils {

    /**
     * 上传文件
     * @param endpoint endpoint域名
     * @param bucketName 存储空间的名字
     * @param content 内容字节数组
     */
    public static String upload(String endpoint, String bucketName, byte[] content, String extName) throws Exception {
        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
        String objectName = UUID.randomUUID() + extName;

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
        try {
            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new ByteArrayInputStream(content));
            // 创建PutObject请求。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
        } catch (OSSException oe) {
            log.error("Caught an OSSException, which means your request made it to OSS, but was rejected with an error response for some reason.");
            log.error("Error Message:" + oe.getErrorMessage());
            log.error("Error Code:" + oe.getErrorCode());
            log.error("Request ID:" + oe.getRequestId());
            log.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            log.error("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.");
            log.error("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }

        return endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + objectName;
    }

}

编写UploadController层接口:

endpoin和bucket节点

    private String endpoint = "https://oss-cn-beijing.aliyuncs.com";
    private String bucket = "bigevent-sun";

?

    @PostMapping("/upload")
    public Result upload(MultipartFile file) throws Exception {
        log.info("文件上传{}",file);
        String extName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        String url = AliyunOSSUtils.upload(endpoint, bucket, file.getBytes(), extName);
        return Result.success(url);
    }

然后就能测试了

问题分析,如果我们这么写很多的controller有很多的弊端,假如配置文件很多,类也很多,不便于维护。

配置文件:

参数配置化:

把一些灵活多变的参数配置到配置文件中

# 阿里云配置
Aliyunoss.endpoint=https://oss-cn-beijing.aliyuncs.com
Aliyunoss.bucketname=big-eventsun
@Value注解:

@Value 注解通常用于外部配置的属性注入,具体用法为:@Value("${配置文件中的key}")

在UploadController控制器类里面,编写代码

    @Value("${aliyun.oss.endpoint}")
    private String endpoint;
   @Value("${aliyun.oss.bucketName}")
    private String bucketName;

upload方法:


    @PostMapping("/upload")
    public Result upload(MultipartFile file) throws Exception {
        log.info("文件上传{}",file);
        String extName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        String url = AliyunOSSUtils.upload(endpoint, bucketName, file.getBytes(), extName);
        return Result.success(url);
    }

然后就能就行测试了

?

yml配置文件:

spring boot提供了多种的配置方式

application.properties

?server.port=8080

server.address=127.0.0.

?application.yml

server: ?

???????port: 8080 ?

??????????address: 127.0.0.1

?application.yml

server: ?

? ? port: 8080 ?

? ? ? ?address: 127.0.0.1

常见的配置文件格式对比:

格式:
  • 数值前边必须有空格,作为分隔符
  • 使用缩进表示层级关系,缩进时,不允许使用Tab键,只能用空格(idea中会自动将Tab转换为空格)
  • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
  • # 表示注释,从这个字符一直到行尾,都会被解析器忽略
定义对象/map集合

#定义user对象
user:
  name: 张三
  age: 18
  password: 123456

可以发现:

在我的光标选中行底部会提示我,下面写的说user对象,并且展示出来我写的对象名和对象值

定义数组/list/set集合:

# 定义数组
hobby:
  - swim
  - java
  - html
  - css

?可以看到,我光标所在数组某一行,它可以知道我的数组有几个元素,并且还能知道我现在是在第几行。并且还能显示出来这一行对应的值。

?

注意:

在yml格式的配置文件中,如果配置项的值是以 0 开头的,值需要使用 '' 引起来,因为以0开头在yml中表示8进制的数据??

math:
  max: "034"
  min: "0981"
  acg: 233

从properties换成yml

?

?

#数据库连接的四要素
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/tlias
    username: root
    password: root
  # spring 文件上传修改单个上传文件大小的配置和一次请求的文件上传大小的配置
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 100MB

#配置mybatis的日志输出信息
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true

  # spring事务日志
logging:
  level:
    org.springframework.jdbc.support.JdbcTransactionManager: debug

#阿里云oos的配置
aliyun:
  oss:
    endpoint: https://oss-cn-beijing.aliyuncs.com
    bucketName: big-eventsun
@ConfigurationProperties注解:

使用@Value注解,注入配置文件的配置项,如果配置项多,注入繁琐,不便于维护管理 和 复用。

我们可以定义,一个实体类,是实体类的属性名和配置文件的key值,保持一致。

然后把这个类交给ioc容器管理,在需要用到的地方进行依赖注入。

定义配置文件:

定义:AliyunOssProperties实体类:

@Data
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliyunOssProperties {
    private String endpoint;
    private String bucketName;
}

在UploadController层,进行注入

 @Autowired
    private AliyunOssProperties aliyunOssProperties;

通过依赖注入,调用这个对象的属性

    @PostMapping("/upload")
    public Result upload(MultipartFile file) throws Exception {
        log.info("文件上传{}",file);
        String extName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        String url = AliyunOSSUtils.upload(aliyunOssProperties.getEndpoint(), aliyunOssProperties.getBucketName(), file.getBytes(), extName);
        return Result.success(url);
    }

文章来源:https://blog.csdn.net/weixin_64502989/article/details/134987955
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。