SpringBoot集成亚马逊云Amazon S3
·
1. 引入依赖
<!-- AWS-S3 -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>1.11.374</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-cbor</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-cbor</artifactId>
<version>2.14.1</version>
</dependency>
2. 配置类
@Data
@Configuration
@ConfigurationProperties(prefix = "amazon.s3")
public class AmazonS3Properties {
private String accessKey;
private String secretKey;
private String serviceEndpoint;
private String bucketName;
}
3. 配置信息
amazon:
s3:
access-key: 访问密钥 ID
secret-key: 私有密钥
service-endpoint: S3 服务接入域名 / 内网地址
bucket-name: 存储桶名称
4. S3 连接配置类
@Configuration
@Slf4j
public class AmazonS3Configuration {
@Resource
private AmazonS3Properties amazonS3Properties;
@Bean
public AmazonS3 amazonS3() {
try {
AWSCredentials credentials = new BasicAWSCredentials(amazonS3Properties.getAccessKey(), amazonS3Properties.getSecretKey());
AmazonS3ClientBuilder amazonS3ClientBuilder = AmazonS3ClientBuilder.standard();
amazonS3ClientBuilder.setPathStyleAccessEnabled(true);
return amazonS3ClientBuilder
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(amazonS3Properties.getServiceEndpoint(), "")).build();
} catch (Exception e) {
log.error(e.getMessage());
throw new RuntimeException("Amazons3 build failed");
}
}
// 若加这个bean,选择第二个AmazonService
// @Bean
// public AmazonService amazonService(AmazonS3 amazonS3) {
// return new AmazonService(amazonS3, amazonS3Properties.getBucketName());
// }
}
5. S3 对象存储操作类
5.1 写法一
/**
* Amazon S3 对象存储操作类
*/
@Service
public class AmazonService {
@Resource
private AmazonS3 amazonS3;
/**
* 默认bucket名称
*/
@Value("${amazon.s3.bucket-name:}")
private String bucketName;
/**
* 初始化生成bucket
* @param bucketName
*/
@PostConstruct
public void init(String bucketName) {
if (!amazonS3.doesBucketExistV2(bucketName)) {
amazonS3.createBucket(bucketName);
}
}
/**
* 上传文件
* @param key 目录+文件形式 如:root/user/1.txt,同key会覆盖文件
*/
public void upload(String key, File file) {
amazonS3.putObject(bucketName, key, file);
}
/**
* 上传文件
* @param key 目录+文件形式 如:root/user/1.txt,同key会覆盖文件
*/
public void upload(String key, InputStream inputStream) {
upload(key, inputStream, null);
}
/**
* 上传文件
* @param key 目录+文件形式 如:root/user/1.txt,同key会覆盖文件
* @param inputStream 文件输入流, 使用完成后建议外部关闭流,避免资源泄漏
* @param objectMetadata 文件元数据(可设置文件类型、长度、缓存策略、自定义属性等)
* 例如:Content-Type、Content-Length、Content-Disposition
*/
public void upload(String key, InputStream inputStream, ObjectMetadata objectMetadata) {
amazonS3.putObject(bucketName, key, inputStream, objectMetadata);
}
/**
* 通过key获取url
*/
public String getUrl(String key) {
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key);
// request.setExpiration(new Date(System.currentTimeMillis() + 60L * 60L * 24L * 365L * 99L * 1000L));
String originUrl = amazonS3.generatePresignedUrl(request).toString();
return originUrl.substring(0, originUrl.indexOf("?"));
}
/**
* 获取带有认证参数的url
*/
public String getUrlWithAuthParam(String key) {
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key);
return amazonS3.generatePresignedUrl(request).toString();
}
/**
* 获取文件输入流
*/
public InputStream getObject(String objectKey) {
// 从 S3 获取文件
S3Object s3Object = amazonS3.getObject(bucketName, objectKey);
return s3Object.getObjectContent();
}
/**
* 删除文件
*/
public void deleteObject(String key) {
amazonS3.deleteObject(bucketName, key);
}
/**
* 拷贝文件
* @param key 原key
* @param destinationKey 目标key
*/
public void copy(String key, String destinationKey) {
amazonS3.copyObject(bucketName, key, bucketName, destinationKey);
}
/**
* 获取对象元数据
* @param objectKey 对象key
* @return 对象元数据
*/
public ObjectMetadata getObjectMetadata(String objectKey) {
return amazonS3.getObjectMetadata(bucketName, objectKey);
}
/**
* 根据URL或objectKey获取S3文件的大小(字节数)
* @param identifier 可以是S3文件的URL(格式:https://xxx.com/桶名/objectKey),也可以是objectKey
* @return 文件大小(字节数)
* @throws Exception 解析URL失败或获取S3元数据失败时抛出
*/
public long getFileSize(String identifier) throws Exception {
// 1. 判断输入是URL还是objectKey,并解析出正确的objectKey
String objectKey;
if (isUrl(identifier)) {
objectKey = parseObjectKeyFromUrl(identifier);
} else {
objectKey = identifier;
}
if (objectKey == null || objectKey.isEmpty()) {
throw new Exception("无法从给定的URL中解析出有效的S3对象键(Object Key)" + identifier);
}
// 2. 获取S3对象的元数据
ObjectMetadata metadata = amazonS3.getObjectMetadata(bucketName, objectKey);
// 3. 返回文件大小(字节数)
return metadata.getContentLength();
}
/**
* 判断字符串是否为URL
* @param str 待判断的字符串
* @return true=是URL,false=不是URL
*/
private boolean isUrl(String str) {
if (str == null || str.isEmpty()) {
return false;
}
return str.startsWith("http://") || str.startsWith("https://");
}
/**
* 从自定义S3 URL中直接移除头部桶名,提取objectKey
* 示例URL: https://xxx.com/任意桶名/folder1/file.txt → objectKey = folder1/file.txt
*/
public String parseObjectKeyFromUrl(String urlStr) {
// 空值校验,避免空指针
if (urlStr == null || urlStr.trim().isEmpty()) {
return "";
}
urlStr = urlStr.trim();
try {
urlStr = URLDecoder.decode(urlStr, StandardCharsets.UTF_8.name());
} catch (Exception e) {
e.printStackTrace();
}
int queryIndex = urlStr.lastIndexOf("?");
if (queryIndex != -1) {
urlStr = urlStr.substring(0, queryIndex);
}
// 第一步:移除HTTP/HTTPS协议头
if (urlStr.startsWith("https://")) {
urlStr = urlStr.substring("https://".length());
} else if (urlStr.startsWith("http://")) {
urlStr = urlStr.substring("http://".length());
}
// 第二步:按/分割,同时处理连续/的情况(split("/+") 匹配一个或多个/)
String[] parts = urlStr.split("/+");
// 第三步:如果分割后长度<=1(只有域名,无后续路径),返回空字符串
if (parts.length <= 1) {
return "";
}
// 第四步:截取从索引1开始的部分(跳过域名),拼接为对象键
String[] objectKeyParts = Arrays.copyOfRange(parts, 1, parts.length);
String objectKey = String.join("/", objectKeyParts);
// 第五步:移除末尾的/(如果有)
if (objectKey.endsWith("/")) {
objectKey = objectKey.substring(0, objectKey.length() - 1);
}
// 第六步:移除桶名前缀(如果有)
if (objectKey.startsWith(bucketName + "/")) {
objectKey = objectKey.substring((bucketName + "/").length());
}
return objectKey;
}
}
5.2 写法二
/**
* Amazon S3 对象存储操作类
*/
public class AmazonService {
@Resource
private AmazonS3 amazonS3;
/**
* 默认bucket名称
*/
private String bucketName;
public AmazonService(AmazonS3 amazonS3, String bucketName) {
this.amazonS3 = amazonS3;
this.bucketName = bucketName;
}
//... 后面的代码和第一个一致
}
6. 使用示例
@RestController
public class UploadFileController {
@Resource
private AmazonService amazonService;
@PostMapping("/uploadFile")
public String uploadFile(@RequestParam("file") MultipartFile multipartFile) {
String url = null;
try {
String fileName = multipartFile.getOriginalFilename();
String suffix = this.getFileSuffix(fileName);
String key = this.getOSSObjectKey(suffix);
this.amazonService.upload(key, new ByteArrayInputStream(multipartFile.getBytes()));
url = this.amazonService.getUrl(key);
} catch (IOException e) {
throw new RuntimeException("PDF转换失败", e);
}
return url;
}
/**
* 获取文件后缀名
*/
public String getFileSuffix(String fileName) {
if ((fileName != null) && (!fileName.isEmpty())) {
int dot = fileName.lastIndexOf('.');
if ((dot > -1) && (dot < (fileName.length() - 1))) {
return fileName.substring(dot + 1);
}
}
return fileName;
}
/**
* 获取文件Key,如:2020/7/17/dd48176a-a512-4377-bd80-c8e5d2910be3.jpg
*/
public String getOSSObjectKey(String suffix) {
Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH) + 1;
int day = c.get(Calendar.DAY_OF_MONTH);
StringBuilder obj = new StringBuilder();
obj.append("/").append(year).append("/").append(month).append("/").append(day).
append("/").append(UUID.randomUUID().toString());
if (suffix != null) {
obj.append(".").append(suffix);
}
return obj.toString();
}
}
更多推荐


所有评论(0)