阿里云文件上传oss存储
文档地址
https://help.aliyun.com/zh/oss/object-file-object/
创建存储空间(Bucket)
https://oss.console.aliyun.com/bucket
出于安全考虑,OSS 控制台默认开启阻止公共访问,仅支持创建私有权限的Bucket。
如需改为 公共读 或 公共读写,请按以下步骤操作:
-
单击目标Bucket名称进入该Bucket。
-
在左侧导航栏选择 权限控制 > 阻止公共访问,关闭该策略。
-
切换至 读写权限 页签,单击 设置。
-
按引导修改 Bucket 的读写权限为公共读或公共读写。
引入sdk
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.4</version>
</dependency>
如果使用的是Java 9及以上的版本,则需要添加以下JAXB相关依赖。
<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>
方法一:静态工具类
@Slf4j public class OssFileUploaderUtil { private static final String accessKeyId = "xxxxxxx"; private static final String accessKeySecret = "xxxxxxxxx"; // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。 private static final String endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; private static final String bucketName = "work"; // 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。 private static final String region = "cn-hangzhou"; private final boolean isPublicBucket = false; // 是否为公开Bucket(影响下载链接生成方式) /** * 上传字节流到OSS并返回下载链接 * @param fileBytes 文件字节数组(如Excel模板的字节流) * @param fileName 文件名(含扩展名,如:用户模板_20250910.xlsx) * @param fileDir OSS存储目录(如:user/templates/,末尾需带斜杠) * @param contentType 文件MIME类型(如:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet) * @return 可直接访问的下载链接 * @throws IOException 流处理异常 */ public static String upload(byte[] fileBytes, String fileName, String fileDir, String contentType) throws IOException { // 1. 构建OSS文件完整路径(目录+文件名) String objectPath = fileDir + fileName; log.info("开始上传文件到OSS,路径:{}", objectPath); OSS ossClient = null; ByteArrayInputStream inputStream = null; try { // 2. 初始化OSS客户端 DefaultCredentialProvider credentialProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret); ClientBuilderConfiguration clientConfig = new ClientBuilderConfiguration(); clientConfig.setSignatureVersion(SignVersion.V4); // 使用V4签名算法 ossClient = OSSClientBuilder.create() .endpoint(endpoint) .credentialsProvider(credentialProvider) .clientConfiguration(clientConfig) .region(region) .build(); // 3. 配置文件元数据 ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentType(contentType); // 关键:指定文件类型,避免下载异常 metadata.setContentLength(fileBytes.length); // 设置文件大小 metadata.setContentEncoding("UTF-8"); // 4. 上传文件流 inputStream = new ByteArrayInputStream(fileBytes); PutObjectRequest putRequest = new PutObjectRequest(bucketName, objectPath, inputStream, metadata); ossClient.putObject(putRequest); log.info("文件上传OSS成功,路径:{}", objectPath); // 5. 生成下载链接 return generateDownloadUrl(objectPath, ossClient); } catch (OSSException e) { log.error("OSS上传失败!错误码:{},请求ID:{}", e.getErrorCode(), e.getRequestId(), e); throw new RuntimeException("文件上传OSS失败:" + e.getMessage(), e); } finally { // 6. 释放资源 if (inputStream != null) { inputStream.close(); } if (ossClient != null) { ossClient.shutdown(); } } } /** * 生成文件下载链接 * @param objectPath OSS上的文件完整路径(如:user/templates/用户模板.xlsx) * @return 下载链接(公开Bucket返回永久链接,私有Bucket返回带签名的临时链接) */ private static String generateDownloadUrl(String objectPath, Oss ossClient) { try { // 编码文件名(处理中文/特殊字符) String encodedPath = URLEncoder.encode(objectPath, StandardCharsets.UTF_8.name()) .replaceAll("\\+", "%20"); if (isPublicBucket) { // 公开Bucket:直接拼接HTTP URL String endpointHost = endpoint.replace("https://", ""); String fileUrl = String.format("https://%s.%s/%s", bucketName, endpointHost, encodedPath); log.info("文件地址:{}", fileUrl); return fileUrl; } else { // 私有Bucket:生成带签名的临时URL(有效期1小时) Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000); return ossClient.generatePresignedUrl(bucketName, objectPath, expiration).toString(); } } catch (Exception e) { log.error("生成下载链接失败", e); throw new RuntimeException("生成文件下载链接失败", e); } } }
方法二:spring管理上述方法需要自动注入OSS
application.yml或者bootstrap.yml对应的nacos
# application.yml aliyun: oss: access-key-id: xxx access-key-secret: xxx endpoint: https://oss-cn-shanghai.aliyuncs.com bucket-name: work region: cn-shanghai is-public-bucket: false
OssConfig配置
@Data
@Configuration
@ConfigurationProperties(prefix = "aliyun.oss")
public class OSSConfig { // 从配置文件注入参数 private String accessKeyId; private String accessKeySecret; private String endpoint; private String bucketName; private String region; private boolean isPublicBucket; // 单例OSS客户端(全局唯一实例) private OSS ossClient; /** * 初始化OSS客户端(服务启动时执行,创建一次) */ @Bean public OSS ossClient() { // 配置客户端参数 DefaultCredentialProvider credentialProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret); ClientBuilderConfiguration clientConfig = new ClientBuilderConfiguration(); clientConfig.setSignatureVersion(SignVersion.V4); // 使用V4签名 // 创建客户端实例(单例,由Spring管理) ossClient = OSSClientBuilder.create() .endpoint(endpoint) .credentialsProvider(credentialProvider) .clientConfiguration(clientConfig) .region(region) .build(); System.out.println("OSS客户端初始化完成(单例模式)"); return ossClient; } /** * 服务停止时自动关闭OSS客户端(@PreDestroy确保Spring销毁Bean时执行) */ @PreDestroy public void shutdownOssClient() { if (ossClient != null) { ossClient.shutdown(); System.out.println("服务停止,OSS客户端已关闭"); } } }
调用
@Autowired private OSS ossClient; @Autowired private OSSConfig ossConfig; /** * 上传字节流到OSS并返回下载链接 * @param fileBytes 文件字节数组(如Excel模板的字节流) * @param fileName 文件名(含扩展名,如:用户信息模板_20250910.xlsx) * @param fileDir OSS存储目录(如:user/templates/,末尾需带斜杠) * @param contentType 文件MIME类型(如:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet) * @return 可直接访问的下载链接 * @throws IOException 流处理异常 */ public String upload(byte[] fileBytes, String fileName, String fileDir, String contentType) throws IOException { // 1. 构建OSS文件完整路径(目录+文件名) String objectPath = fileDir + fileName; log.info("开始上传文件到OSS,路径:{}/{}", ossConfig.getBucketName(), objectPath); log.info("配置信息:ossConfig:{}",ossConfig ); ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentType(contentType); // 关键:指定文件类型,避免下载异常 metadata.setContentLength(fileBytes.length); // 设置文件大小 metadata.setContentEncoding("UTF-8"); try (ByteArrayInputStream inputStream = new ByteArrayInputStream(fileBytes)){ PutObjectRequest putRequest = new PutObjectRequest(ossConfig.getBucketName(), objectPath, inputStream, metadata); ossClient.putObject(putRequest); log.info("文件上传OSS成功,路径:{}", objectPath); return generateDownloadUrl(objectPath); } catch (OSSException e) { log.error("OSS上传失败!错误码:{},请求ID:{}", e.getErrorCode(), e.getRequestId(), e); throw new RuntimeException("文件上传OSS失败:" + e.getMessage(), e); } } /** * 生成文件下载链接 * @param objectPath OSS上的文件完整路径(如:user/templates/用户模板.xlsx) * @return 下载链接(公开Bucket返回永久链接,私有Bucket返回带签名的临时链接) */ private String generateDownloadUrl(String objectPath) { try { // 编码文件名(处理中文/特殊字符) String encodedPath = URLEncoder.encode(objectPath, StandardCharsets.UTF_8.name()) .replaceAll("\\+", "%20"); if (ossConfig.getIsPublicBucket()) { // 公开Bucket:直接拼接HTTP URL String endpointHost = ossConfig.getEndpoint().replace("https://", ""); String fileUrl = String.format("https://%s.%s/%s", ossConfig.getBucketName(), endpointHost, encodedPath); log.info("文件地址:{}", fileUrl); return fileUrl; } else { // 私有Bucket:生成带签名的临时URL(有效期1小时) Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000); return ossClient.generatePresignedUrl(ossConfig.getBucketName(), objectPath, expiration).toString(); } } catch (Exception e) { log.error("生成下载链接失败", e); throw new RuntimeException("生成文件下载链接失败", e); } }

浙公网安备 33010602011771号