学习文档:
学习视频:
本博客的所有配套代码:aliyun-oss—Gitee、aliyun-oss—Github
所有博客文件目录索引:博客目录索引(持续更新)
阿里云开通OSS存储服务可见我的博客:阿里云开通OSS存储服务详细流程
2022.11.11编辑最新流程文档:创建Bucket、配置用户权限以及允许跨域
若是我们仅仅用来自己项目测试的话可以按照下面的来进行创建:
记住要为对应的bucket设置对应的用户权限:对于创建子用户操作见我上面的文章链接跟着走一遍就行!
配置跨域请求:
首先来到官方文档:
代码来源:OSS Java SDK 3.13.2版本—阿里官方文档
依赖:
com.aliyun.oss aliyun-sdk-oss 3.14.0
代码:已调试其中的带中文注释
package com.changlu.test.common;import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;/*** This sample demonstrates how to get started with basic requests to Aliyun OSS * using the OSS SDK for Java.*/
public class GetStartedSample {private static String endpoint = "";private static String accessKeyId = "";private static String accessKeySecret = "";
// private static String bucketName = "pictured-bed";private static String bucketName = "";private static String key = "test/test2/";//若是目录,一定要设置///方便之后拼接private static String shortEndpoint = "oss-cn-beijing.aliyuncs.com";public static void main(String[] args) throws IOException {/** Constructs a client instance with your account for accessing OSS*/OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);System.out.println("Getting Started with OSS SDK for Java\n");try {// /*
// * Determine whether the bucket exists 查看桶是否存在
// */
// if (!ossClient.doesBucketExist(bucketName)) { //创建桶
// /*
// * Create a new OSS bucket
// */
// System.out.println("Creating bucket " + bucketName + "\n");
// ossClient.createBucket(bucketName);//根据当前的认证信息来进行创建Bucket桶,默认是私有
// CreateBucketRequest createBucketRequest= new CreateBucketRequest(bucketName);
// createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);//设置读写权限为公开读
// ossClient.createBucket(createBucketRequest);//来
// }/** List the buckets in your account:获取所有的桶名称*/
// System.out.println("Listing buckets");
//
// ListBucketsRequest listBucketsRequest = new ListBucketsRequest();
// listBucketsRequest.setMaxKeys(500);
//
// for (Bucket bucket : ossClient.listBuckets()) { //发起请求
// System.out.println(" - " + bucket.getName());
// }
// System.out.println();
///** 上传文件* Upload an object to your bucket:上传对象到你的桶中*/
// System.out.println("Uploading a new object to OSS from a file\n");
// File file = new File("C:\\Users\\93997\\Desktop\\桌面壁纸\\1.png");
// String saveFilePath = key + file.getName();//拼接目标路径 + 图片名称
// //第一个参数为:桶的名称;第二个参数为路径+上你的文件名,如test/1.png,若是test/test2/1.png,也会给我们自动创建目录
// //第三个参数为:文件对象
// ossClient.putObject(new PutObjectRequest(bucketName,saveFilePath , file));
// //拼接获取公共访问地址
// String publicVisitPath = "http://" + bucketName + '.' + shortEndpoint + "/" + saveFilePath;
// System.out.println("访问路径:" + publicVisitPath);
//
// /*
// * 删除文件
// * Delete an object:删除对象
// */System.out.println("Deleting an object\n");File file = new File("C:\\Users\\93997\\Desktop\\桌面壁纸\\1.png");String saveFilePath = key + file.getName();//拼接目标路径 + 图片名称ossClient.deleteObject(bucketName, saveFilePath);// /*
// * Determine whether an object residents in your bucket:判断对象是否存在你的桶
// */
// boolean exists = ossClient.doesObjectExist(bucketName, key);
// System.out.println("Does object " + bucketName + " exist? " + exists + "\n");
//
// ossClient.setObjectAcl(bucketName, key, CannedAccessControlList.PublicRead);
// ossClient.setObjectAcl(bucketName, key, CannedAccessControlList.Default);
//
// ObjectAcl objectAcl = ossClient.getObjectAcl(bucketName, key);
// System.out.println("ACL:" + objectAcl.getPermission().toString());
//
// /*
// * Download an object from your bucket
// */
// System.out.println("Downloading an object");
// OSSObject object = ossClient.getObject(bucketName, key);
// System.out.println("Content-Type: " + object.getObjectMetadata().getContentType());
// displayTextInputStream(object.getObjectContent());
//
// /*
// * List objects in your bucket by prefix
// */
// System.out.println("Listing objects");
// ObjectListing objectListing = ossClient.listObjects(bucketName, "My");
// for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
// System.out.println(" - " + objectSummary.getKey() + " " +
// "(size = " + objectSummary.getSize() + ")");
// }
// System.out.println();
//} 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());} 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());} finally {/** Do not forget to shut down the client finally to release all allocated resources.*/ossClient.shutdown();}}private static File createSampleFile() throws IOException {File file = File.createTempFile("oss-java-sdk-", ".txt");file.deleteOnExit();Writer writer = new OutputStreamWriter(new FileOutputStream(file));writer.write("abcdefghijklmnopqrstuvwxyz\n");writer.write("0123456789011234567890\n");writer.close();return file;}private static void displayTextInputStream(InputStream input) throws IOException {BufferedReader reader = new BufferedReader(new InputStreamReader(input));while (true) {String line = reader.readLine();if (line == null) break;System.out.println(" " + line);}System.out.println();reader.close();}}
配套代码:AliyunOss-SDK—Gitee、AliyunOss-SDK—Github
文档可见官网有对应不同功能的代码示例:简单上传文档
测试其中的上传文件流:直接复制的上面文件流的示例代码,然后去修改一下配置信息即可
package com.changlu;import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import java.io.FileInputStream;
import java.io.InputStream;public class Demo {public static void main(String[] args) throws Exception {// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。String endpoint = "";// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。String accessKeyId = "";String accessKeySecret = "";// 填写Bucket名称,例如examplebucket。String bucketName = "";// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。String objectName = "2.png";// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。String filePath= "C:\\Users\\93997\\Desktop\\桌面壁纸\\1.png";// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);try {InputStream inputStream = new FileInputStream(filePath); // 创建PutObject请求。ossClient.putObject(bucketName, objectName, inputStream);} 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());} 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());} finally {if (ossClient != null) {ossClient.shutdown();}}}
}
若是你的配置没有问题,程序不会报任何代码错误!
接下来检查一下对应阿里云的bucket文件列表是否有对应的文件:
配套代码:AliyunOssService-Gitee 、AliyunOssService-Github
上传、删除方法已经封装到Utils中,controller只需要调用工具类的上传、删除即可!
application.yml:
# 图片文件上传
spring:servlet:multipart:max-file-size: 100MBmax-request-size: 1000MB# 阿里云OSS配置
aliyun:oss:endpoint: # 坐标地区示例:oss-cn-beijing.aliyuncs.comaccessKeyId: # 注册用户的keyIDaccessKeySecret: # 注册用户的密钥bucketName: # 桶名称 示例:pictured-stkey: # 存储根路径,例如:img/,以目录形式为结尾,之后图片会自动生成并添加到后缀
package com.changlu.config;import lombok.Data;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;/*** @ClassName AliyunOssConfig* @Author ChangLu* @Date 3/26/2022 4:22 PM* @Description 阿里云OOS配置*/
@Component
// 指定配置文件中自定义属性前缀
@ConfigurationProperties(prefix = "aliyun.oss")
@Data
@ToString
public class AliyunOssConfig {private String endpoint;private String accessKeyId;private String accessKeySecret;private String bucketName;private String key;}
package com.changlu.controller;import com.changlu.domain.ResponseResult;
import com.changlu.utils.AliyunOssUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import java.util.HashMap;
import java.util.Map;/*** @ClassName UploadController* @Author ChangLu* @Date 3/26/2022 5:23 PM* @Description Oss文件控制器*/
@RestController
public class OssFileController {@Autowiredprivate AliyunOssUtil aliOssUtil;/*** 上传图片* @param file* @return*/@PostMapping("/upload")public ResponseResult uploadFile(@RequestParam("file")MultipartFile file){try {String visitUrl = aliOssUtil.uploadFile(file);Map result = new HashMap<>(1);result.put("visitUrl", visitUrl);return new ResponseResult(200,"上传成功!", result);}catch (Exception e){e.printStackTrace();return new ResponseResult(500,"上传失败!");}}/*** 删除图片* @param fileName 文件名称如:b8809d28-82ec-4b06-af5f-8d3d7a16107c.jpg* @return*/@GetMapping("/deleFile/{fileName}")public ResponseResult deleteFile(@PathVariable("fileName")String fileName){try {aliOssUtil.deleteFile(fileName);return new ResponseResult(200,"删除成功!");} catch (Exception e) {e.printStackTrace();return new ResponseResult(500,"删除失败!");}}}
import com.fasterxml.jackson.annotation.JsonInclude;/*** @Author changlu*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResponseResult {/*** 状态码*/private Integer code;/*** 提示信息,如果有错误时,前端可以获取该字段进行提示*/private String msg;/*** 查询到的结果数据,*/private T data;public ResponseResult(Integer code, String msg) {this.code = code;this.msg = msg;}public ResponseResult(Integer code, T data) {this.code = code;this.data = data;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public T getData() {return data;}public void setData(T data) {this.data = data;}public ResponseResult(Integer code, String msg, T data) {this.code = code;this.msg = msg;this.data = data;}
}
package com.changlu.utils;import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.changlu.config.AliyunOssConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.io.InputStream;
import java.util.UUID;/*** @ClassName AliyunOssUtil* @Author ChangLu* @Date 3/26/2022 4:51 PM* @Description OSS对象存储工具类*/
@Component
public class AliyunOssUtil {@Autowiredprivate AliyunOssConfig aliyunOssConfig;/*** 创建一个OSS连接* @return OssClient*/private OSS createOssClient(){String endpoint = "http://" + aliyunOssConfig.getEndpoint();String accessKeyId = aliyunOssConfig.getAccessKeyId();String accessKeySecret = aliyunOssConfig.getAccessKeySecret();return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);}/*** 关闭连接* @param ossClient*/private void close(OSS ossClient){if (ossClient != null) {ossClient.shutdown();}}/*** 上传文件* @param file File类型* @return*/public String uploadFile(File file){String key = aliyunOssConfig.getKey();String bucketName = aliyunOssConfig.getBucketName();String endpoint = aliyunOssConfig.getEndpoint();//1、取得保存文件路径saveFilePath:拼接目标路径 + 图片名称String originFileName = file.getName();String filePrefix = UUID.randomUUID().toString();String saveFileName = filePrefix + originFileName.substring(file.getName().indexOf("."));String saveFilePath = key + saveFileName;OSS ossClient = null;try {ossClient = createOssClient();//2、上传文件//第一个参数为:桶的名称;第二个参数为路径+上你的文件名,如test/1.png,若是test/test2/1.png,也会给我们自动创建目录//第三个参数为:文件对象ossClient.putObject(new PutObjectRequest(bucketName,saveFilePath , file));}catch (Exception e){e.printStackTrace();return null;}finally {this.close(ossClient);}//3、拼接获取公共访问地址String publicVisitPath = "http://" + bucketName + '.' + endpoint + "/" + saveFilePath;return publicVisitPath;}/*** 上传文件* @param file MultipartFile类型* @return*/public String uploadFile(MultipartFile file)throws Exception{String key = aliyunOssConfig.getKey();String bucketName = aliyunOssConfig.getBucketName();String endpoint = aliyunOssConfig.getEndpoint();//1、取得保存文件路径saveFilePath:拼接目标路径 + 图片名称String originFileName = file.getOriginalFilename();String filePrefix = UUID.randomUUID().toString();String saveFileName = filePrefix + originFileName.substring(originFileName.indexOf("."));String saveFilePath = key + saveFileName;OSS ossClient = null;try {ossClient = createOssClient();//2、上传文件//第一个参数为:桶的名称;第二个参数为路径+上你的文件名,如test/1.png,若是test/test2/1.png,也会给我们自动创建目录//第三个参数为:文件对象/*** 阿里云OSS 默认图片上传ContentType是image/jpeg* 图片链接后,图片是下载链接,而并非在线浏览链接* 这里在上传的时候要解决ContentType的问题,将其改为image/jpg*/InputStream is = file.getInputStream();ObjectMetadata meta = new ObjectMetadata();meta.setContentType("image/jpg");ossClient.putObject(new PutObjectRequest(bucketName,saveFilePath , is, meta));}catch (Exception e){throw new RuntimeException(e);}finally {this.close(ossClient);}//3、拼接获取公共访问地址String publicVisitPath = "http://" + bucketName + '.' + endpoint + "/" + saveFilePath;return publicVisitPath;}/*** 删除文件* @param fileName 待删除的文件名* @return*/public void deleteFile(String fileName)throws Exception{String key = aliyunOssConfig.getKey();String bucketName = aliyunOssConfig.getBucketName();//1、拼接待删除路径String deleteFilePath = key + fileName;OSS ossClient = null;try {ossClient = createOssClient();//2、删除文件ossClient.deleteObject(bucketName, deleteFilePath);}catch (Exception e){throw new RuntimeException(e);}finally {this.close(ossClient);}}}
pom.xml:三个版本依次为springboot2.1.8
、springcloud Greenwich.SR3
、SpringCloud Alibaba2.1.0.RELEASE
org.springframework.boot spring-boot-starter-parent 2.1.8.RELEASE
1.8 Greenwich.SR3
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test com.alibaba.cloud spring-cloud-starter-alicloud-oss
org.springframework.boot spring-boot-maven-plugin
org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import com.alibaba.cloud spring-cloud-alibaba-dependencies 2.1.0.RELEASE pom import
配套代码:springcloud-alibaba-oss-Gitee 、springcloud-alibaba-oss-Github
server:port: 8888
spring:cloud:alicloud:access-key: secret-key: oss:endpoint: # 这是自定义的,需要自己来去读取bucketname:
接着对应demo写在了test的示例中:下面黄色框的就是我们需要自己额外编写的,其他的上传操作和之前的普通上传基本一致
package com.changlu;import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;/*** @Description:* @Author: changlu* @Date: 5:44 PM*/@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringCloudOSSApplicationTest {@Autowiredprivate OSS ossClient;@Value("${spring.cloud.alicloud.oss.bucketname}")private String bucketName;//普通上传文件服务@Testpublic void test() {// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。String objectName = "4.png";// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。String filePath= "C:\\Users\\93997\\Desktop\\桌面壁纸\\1.png";try {InputStream inputStream = new FileInputStream(filePath);// 创建PutObject请求。ossClient.putObject(bucketName, objectName, inputStream);} 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());} 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());} catch (FileNotFoundException e) {e.printStackTrace();} finally {if (ossClient != null) {ossClient.shutdown();}}}
}
运行一下,若是没有任何报错信息的话,那么此时说就说上传成功:
后端代码
配套代码:springcloud-alibaba-oss-Gitee 、springcloud-alibaba-oss-Github
文档地址:最佳实践-web端上传数据至OSS-服务器端直传并设置上传回调
pom.xml
:
4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.8.RELEASE com.changlu springcloud-alibaba-oss 0.0.1-SNAPSHOT springcloud-alibaba-oss Demo project for Spring Boot 1.8 Greenwich.SR3 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test com.alibaba.cloud spring-cloud-starter-alicloud-oss org.springframework.boot spring-boot-maven-plugin org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import com.alibaba.cloud spring-cloud-alibaba-dependencies 2.1.0.RELEASE pom import
application.yml
:
server:port: 8888
spring:cloud:alicloud:access-key: secret-key: oss:endpoint: # 这是自定义的,需要自己来去读取bucketname:
R.java
:统一封装响应类
package com.changlu.utils;import java.util.HashMap;
import java.util.Map;/*** 返回数据* * @author chenshun* @email sunlightcs@gmail.com* @date 2016年10月27日 下午9:59:27*/
public class R extends HashMap {private static final long serialVersionUID = 1L;public R() {put("code", 0);put("msg", "success");}public static R error() {return error(500, "未知异常,请联系管理员");}public static R error(String msg) {return error(500, msg);}public static R error(int code, String msg) {R r = new R();r.put("code", code);r.put("msg", msg);return r;}public static R ok(String msg) {R r = new R();r.put("msg", msg);return r;}public static R ok(Map map) {R r = new R();r.putAll(map);return r;}public static R ok() {return new R();}public R put(String key, Object value) {super.put(key, value);return this;}
}
OssController.java
:提供获取签名服务
package com.changlu.controller;import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.changlu.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;/*** @Description:* @Author: changlu* @Date: 7:03 PM*/
@RestController
public class OssController {@Autowiredprivate OSS ossClient;@Value("${spring.cloud.alicloud.oss.bucketname}")private String bucketName;@Value("${spring.cloud.alicloud.access-key}")private String accessId;@Value("${spring.cloud.alicloud.oss.endpoint}")private String endpoint;@RequestMapping("/oss/policy")public R policy() {// 填写Host地址,格式为https://bucketname.endpoint。String host = "https://" + bucketName + "." + endpoint;String dirName = new SimpleDateFormat("yyyy-MM-dd").format(new Date());// 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。String dir = dirName + "/";Map respMap = null;try {long expireTime = 30;long expireEndTime = System.currentTimeMillis() + expireTime * 1000;Date expiration = new Date(expireEndTime);PolicyConditions policyConds = new PolicyConditions();policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);//生成签名String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);byte[] binaryData = postPolicy.getBytes("utf-8");String encodedPolicy = BinaryUtil.toBase64String(binaryData);String postSignature = ossClient.calculatePostSignature(postPolicy);respMap = new LinkedHashMap();respMap.put("accessid", accessId);respMap.put("policy", encodedPolicy);respMap.put("signature", postSignature);respMap.put("dir", dir);respMap.put("host", host);respMap.put("expire", String.valueOf(expireEndTime / 1000));} catch (Exception e) {// Assert.fail(e.getMessage());System.out.println(e.getMessage());}return R.ok().put("data", respMap);}}
测试下:成功获取
前端代码
这里组件源代码可以直接可以查看谷粒商城博客笔记:谷粒商城-基础篇(详细流程梳理+代码)
这里面包含了组件源代码以及实际引入项目并使用的前端案例。
1、每次使用完OSSClient后要进行关闭,ossClient.shutdown()。
OSSClient不关闭,导致大量FullGC
2、可不可以设置OSSClient为单例?
[1] 一小时学会使用springboot操作阿里云OSS实现文件上传,下载,删除(附源码)
[2] SpringBoot整合阿里云OSS