在SpringBoot项目中使用阿里云OSS

环境配置
首先,你需要初始化一个SpringBoot的项目,并引入阿里云OSS的依赖,在本教程中,你还需要引入Lombok。由于此教程需要使用到阿里云OSS,所以开始前请先确保您已经开通阿里云OSS并正确创建Bucket桶。
<!--OSS依赖-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
<!--Lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<version>1.18.32</version>
</dependency>
随后,你需要在application.yml中添加以下配置:
aliyun:
oss:
end-point: # 你的阿里云Endpoint,在Bucket创建时会显示
access-key-id: # 能访问你的Bucket桶的账号所对应的access-key-id
access-key-secret: # 能访问你的Bucket桶的账号所对应的access-key-secret
bucket-name: # 创建Bucket时填写的桶名称
相关代码
Step1:配置OSS客户端
首先,创建一个OSSClientConfig.java文件,并输入以下代码。为了防止重复创建多个OSS客户端,我们这里使用了单例模式,将创建的OSS客户端返回。同时,我们需要确保在类销毁时可以正确的关闭客户端,我们需要使用@PreDestory注解,使得客户端可以在类销毁前关闭连接。
@Configuration
@ConfigurationProperties(prefix = "aliyun.oss")
@Data
public class OSSClientConfig {
// yml中的配置
private String endPoint;
private String accessKeyId;
private String accessKeySecret;
// 单例模式
private OSS ossClient;
@Bean
public OSS ossClient() {
// 如果没有对象,直接创建,如果已经存在,不重复生成,直接返回
if (ossClient == null) {
ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, accessKeySecret);
}
return ossClient;
}
@PreDestroy
public void shutdown() {
// 如果客户端被创建,则在类销毁前关闭连接
if (ossClient != null) {
ossClient.shutdown();
}
}
}
Step2:完成文件上传操作
随后,我们需要创建FileService.java接口,及对应的接口实现类FileServiceImpl.java。在这里我们创建了一个upload函数,用于接受前端返回的文件,并在重命名之后上传至服务器中。
public interface FileService {
String upload(MultipartFile file);
}
@Service
@Slf4j
public class FileServiceImpl implements FileService {
@Resource
private OSS ossClient;
@Value("${aliyun.oss.bucket-name}")
private String bucketName;
/**
* 阿里云OSS文件上传
*
* @param file
*/
@Override
public String upload(MultipartFile file) {
//获取原生文件名
String originalFilename = file.getOriginalFilename();
String fileName = generateUUID();
String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
//在OSS上bucket下的文件名
String uploadFileName = "blog/" + fileName + extension;
try {
PutObjectResult result = ossClient.putObject(bucketName, uploadFileName, file.getInputStream());
//拼装返回路径
if (result != null) {
return result;
}
} catch (IOException e) {
log.error("文件上传失败:{}",e.getMessage());
}
return null;
}
/**
* 获取随机字符串
* @return
*/
private String generateUUID() {
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
}
}
完成这些代码之后,我们可以编写FileController.java,来完成文件上传。
/**
* 文件接口
*
*/
@Slf4j
@RestController
@RequestMapping("/file")
public class FileController {
@Resource
private FileService fileService;
/**
* 文件上传接口
* @param file
* @return
*/
@PostMapping("/upload")
public String upload(@RequestPart("file") MultipartFile file){
// 出于教学目的,这里没有对文件的大小、文件类型进行校验,读者可以自行添加
String imgFileStr = fileService.upload(file);
// 这里可以改为你自行封装的返回类
return imgFileStr;
}
}
至此,我们的上传操作已经完成。
Step3:完成文件访问操作
到此,如果你有尝试获取imgFileStr的链接,并直接在浏览器中访问,你会发现,文件是没有办法打开的(如果你设置了私有读写的话)。在OSS中,为了保证数据的安全,我们不能直接读取这些内容,我们需要设置签名,并为其设置具有有效期的访问链接,以供外部访问。由于获取到的链接是动态的,具有有效期,所以我们先指定固定的服务器接口,然后通过服务器重定向到文件的动态链接。
在这里,我们使用了Redis缓存来存储文件的动态地址,在这里我们使用了Redisson来对Redis进行操作。首先,我们在pom.xml中引入Redisson。
<!-- https://github.com/redisson/redisson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.37.0</version>
</dependency>
随后,我们在application.yml中添加redis的配置信息。
spring:
redis:
database: 1
host: localhost
port: 6379
timeout: 5000
password: 123456
随后,我们创建RedissonConfig.java来提供服务。
/**
* Redisson配置
*/
@Configuration
@ConfigurationProperties(prefix = "spring.redis")
@Data
public class RedissonConfig {
private String host;
private Integer port;
private Integer database;
private String password;
private Integer timeout;
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://" + host + ":" + port)
.setDatabase(database)
.setTimeout(timeout)
.setPassword(password);
return Redisson.create(config);
}
}
在引入了依赖之后,我们对FileServiceImpl.java文件进行修改
@Service
@Slf4j
public class FileServiceImpl implements FileService {
...
@Resource
private RedissonClient redissonClient;
@Value("${aliyun.oss.bucket-name}")
private String bucketName;
@Override
public String upload(MultipartFile file) {
...
try {
PutObjectResult result = ossClient.putObject(bucketName, uploadFileName, file.getInputStream());
//拼装返回路径
if (result != null) {
// 这里修改为文件的固定地址
return uploadFileName;
}
} catch (IOException e) {
log.error("文件上传失败:{}",e.getMessage());
}
...
}
/**
* 获取1小时有效的文件链接,并放入redis缓存中
* @param fileName
* @return
*/
private String generateUrlFromOss(String fileName){
Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
String url=ossClient.generatePresignedUrl(bucketName, fileName, expiration).toString();
saveUrlFromRedis("file:images:"+fileName, url);
return url;
}
private String getUrlFromRedis(String key){
RBucket<String> bucket = redissonClient.getBucket("file:images:"+key); // 获取RBucket对象
return bucket.get(); // 获取String值
}
private void saveUrlFromRedis(String key, String url){
RBucket<String> bucket = redissonClient.getBucket(key);
bucket.set(url, Duration.ofHours(1));
}
public String getFileUrl(String fileName){
return getUrlFromRedis(fileName)==null? generateUrlFromOss(fileName):getUrlFromRedis(fileName);
}
...
}
同时,在FileController.java中添加以下内容。
@Slf4j
@RestController
@RequestMapping("/file")
public class FileController {
...
// 处理对文件的请求,并重定向到阿里云OSS文件,同时设置缓存头
@GetMapping("/{prefix}/{fileName:.+}")
public void redirectToOss(@PathVariable String prefix, @PathVariable String fileName, HttpServletRequest request,HttpServletResponse response) {
// 获取阿里云OSS文件的签名URL
String signedUrl = fileService.getFileUrl(prefix+"/"+fileName);
// 在这种情况下不能使用缓存,因为链接会失效,导致图片无法正常加载!
// 设置缓存头,缓存30天
//response.setHeader("Cache-Control", "public, max-age=2592000"); // 30天缓存
//response.setHeader("Pragma", "cache"); // 兼容旧版浏览器
// 重定向到阿里云OSS文件的URL
try {
response.sendRedirect(signedUrl);
} catch (Exception e) {
response.setStatus(404);
}
}
}
至此,就可以直接通过重定向的方法从OSS中获取图片了。
