前言

很多时候我们需要将项目部署到远程服务器上供别人使用,项目中难免会需要存放一些静态文件,例如Excel表格模板、Word文档模板、图片、视频之类的。

但是像图片、视频这种资源往往都是很大的,在网络上传输特别吃带宽,便宜的服务器一般都是5Mbps,传个图片都要转很久。

这时候就需要我们的静态文件托管平台来帮我们管理了。

平台有很多,常用的有腾讯云对象存储COS阿里云对象存储OSS七牛云对象存储Kodo,这里将会演阿里云OSSSpringBoot项目中的使用(个人理解)。

创建存储桶

进入阿里云对象存储OSS控制台,点击创建Bucket,选择低频访问(适用于自己玩儿的项目,详见官方文档),如果想要URL干净一些,可以把公共读勾选上,然后确定创建。

image-20230928155906543

创建RAM用户

如果直接使用你的阿里云账号的令牌来访问的话,如果令牌泄露问题会特别大,就像root账号被泄露一样。

所以为存储桶创建新的用户,为了方便管理资源的权限。

进入阿里云RAM访问控制,可以在页面添加用户,再添加用户组,然后将用户加入到用户组中,再给用户组分配权限。

我这里只创建用户,然后直接给用户权限。

勾选OpenAPI调用访问

image-20230928161043856

创建完成后会有IDKEY生成,一定要复制好

然后给这个用户分配权限,点击添加权限,指定资源组、选择OSS权限,点击确定。

image-20230928161505320

代码

首先导入OSS的Maven坐标

1
2
3
4
5
<dependency><!-- 阿里云OSS依赖 -->
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
</dependency>

application.yml中加入阿里云OSS相关配置:

1
2
3
4
5
6
7
8
9
# 阿里云OSS相关配置
aliyun:
oss:
endpoint: 'https://oss-cn-chengdu.aliyuncs.com'
access-key-id: 'xxxxx'
access-key-secret: 'xxxxxx'
bucket-name: '存储桶名称'
url: '资源URL前缀'
path-set-meal: '随便定义的上传目录'

创建读取配置的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.itheima.configure.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Repository;

@ConfigurationProperties(prefix = "aliyun.oss")
@Repository
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AliyunOSSConfig {
protected String endpoint;
protected String accessKeyId;
protected String accessKeySecret;
protected String bucketName;
protected String pathSetMeal;
protected String url;
}

创建工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package com.itheima.util;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.itheima.configure.config.AliyunOSSConfig;
import com.itheima.exception.BizException;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;
import java.util.UUID;

@EqualsAndHashCode(callSuper = true)
@Data
public class AliyunOSSUtil extends AliyunOSSConfig {

public AliyunOSSUtil(AliyunOSSConfig aliyunOSSConfig) {
this.setEndpoint(aliyunOSSConfig.getEndpoint());
this.setAccessKeyId(aliyunOSSConfig.getAccessKeyId());
this.setAccessKeySecret(aliyunOSSConfig.getAccessKeySecret());
this.setBucketName(aliyunOSSConfig.getBucketName());
}

/**
* 通过URL获取文件名
* @param urlStr
* @return
*/
public String getFileNameByURL(String urlStr) {
// 创建URL对象
URL url = null;
try {
url = new URL(urlStr);
} catch (MalformedURLException e) {
//throw new BizException("文件名异常");
return null;
}
// 使用Paths.get方法将URL转换成Path对象
Path path = Paths.get(url.getPath());
return path.getFileName().toString();
}

/**
* 上传图片到阿里云OSS
* @param multipartFile
* @param folderPath
* @return
*/
public String upload(MultipartFile multipartFile, String folderPath){
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 定义文件名称
String fileName = generateFileName(Objects.requireNonNull(multipartFile.getOriginalFilename()));
// 上传图片
try {
ossClient.putObject(getBucketName(), folderPath + fileName, multipartFile.getInputStream());
} catch (IOException e) {
throw new BizException("图片上传失败");
} finally {
// 关闭OSSClient。
ossClient.shutdown();
}

return url + folderPath + fileName;
}

/**
* 删除一个文件
* @param folderPath
* @param fileName
*/
public void delete(String folderPath, String fileName) {
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

try {
// 删除文件或目录。如果要删除目录,目录必须为空。
ossClient.deleteObject(bucketName, folderPath + fileName);
} 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());
throw new BizException("阿里云OSS删除图片失败");
} 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());
throw new BizException("阿里云OSS删除图片失败");
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}

/**
* 生成唯一的文件名
* @param originalFilename 文件本来的名称
* @return
*/
private String generateFileName(String originalFilename) {
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
String suffix = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
return dateFormat.format(date) + "-" + UUID.randomUUID() + "." + suffix;
}
}

将工具类注入到bean中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.itheima.configure;

import com.itheima.configure.config.AliyunOSSConfig;
import com.itheima.util.AliyunOSSUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AliyunOSSConfigure {
@Autowired
private AliyunOSSConfig aliyunOSSConfig;

@Bean
public AliyunOSSUtil ossUtil() {
return new AliyunOSSUtil(aliyunOSSConfig);
}
}

参考文档

阿里云官网文档

java整合阿里云OSS