阿里云的 OSS 服务进行云端的文件存储
用户认证需要上传图片、首页轮播需要上传图片,OSS分布式文件服务系统可以提供服务。
- 一般项目使用OSS对象存储服务,主要是对图片、文件、音频等对象集中式管理权限控制,管理数据生命周期等等,提供上传,下载,预览,删除等功能。
- 通过OSS部署前端项目
一、依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>aliyun-oss-spring-boot-starter</artifactId>
</dependency>
二、在配置文件中配置 OSS 服务对应的 accessKey、secretKey 和 endpoint
alibaba.cloud.access-key=your-ak
alibaba.cloud.secret-key=your-sk
alibaba.cloud.oss.endpoint=***
阿里云 accessKey、secretKey 为例,获取方式如下
①、在阿里云控制台界面,单击右上角头像,选择 accesskeys,或者直接登录用户信息管理界面:
②、获取 accessKey、secretKey:
如果使用了阿里云 STS服务 进行短期访问权限管理,则除了 accessKey、secretKey、endpoint 以外,还需配置 securityToken
③、创建Bucket
进入Bucket,上传文件,可以查看上传文件的详情(URL用来访问该文件)
三、注入OSSClient并进行文件上传下载等操作,大量文件对象操作的场景。
@Service
public class YourService{
@Autowired
private OSSClient ossClient;
public void saveFile(){
//下载文件到本地
ossClient.getObject(new GetObejctRequest(bucketName,objectName),new File("pathOfYourLocalFile"));
}
}
如果是仅仅读取文件对象内容,OSS Starter也支持以Resource方式读取文件
①、在应用的 /src/main/resources/application.properties 中添加基本配置信息和 OSS 配置
spring.application.name=oss-example
server.port=18084
alibaba.cloud.access-key=your-ak
alibaba.cloud.secret-key=your-sk
alibaba.cloud.oss.endpoint=***
②、通过IDE直接启动或者编译打包后启动应用
- IDE直接启动:找到主类 OSSApplication,执行 main 方法启动应用
- 打包编译后启动,执行 mvn clean package 将工程编译打包;执行 java -jar oss-example.jar启动应用
应用启动后会自动在 OSS 上创建一个名为 aliyun-spring-boot-test 的 Bucke
@Value("oss://aliyun-spring-boot/oss-test")
private Resource file;
//文件内容读取
StreamUtils.copyToString(file.getInputStream(),Charset.forName(CharEncoding.UTF_8));
上传或下载文件
#使用 curl 调用上传接口 upload。该接口会上传 classpath 下的的 oss-test.json 文件。文件内容是一段 json:
curl http://localhost:18084/upload
#使用 curl 调用下载接口 download。该接口会下载刚才用 upload 接口上传的 oss-test.json 文件,并打印文件内容到结果中:
curl http://localhost:18084/download
在OSS上验证结果
登陆OSS控制台,可以看到左侧 Bucket 列表新增一个名字为aliyun-spring-boot-test的 Bucket。
单击aliyun-spring-boot-test Bucket,选择 文件管理 页签,发现上传的 oss-test 文件。上传的 objectName 为oss-test.json。目录和文件以’/'符号分割。
===============================================
实战操作
一、导入依赖
<!--阿里云OSS依赖-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
</dependency>
<!--日期工具栏依赖-->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
配置文件application.properties
server.port=8205
spring.application.name=service-oss
spring.jackson.data-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
spring.redis.host=192.168.44.165
spring.redis.port=6379
spring.redis.database=0
spring.redis.timeout=1800000
spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(附属表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
aliyun.oss.accessKeyId=
aliyun.oss.secret=
@SpringBootApplication(exclude=DataSourceAutoConfiguration.class)//无需加载数据库
@EnableDiscoveryClient
@ComponentScan(basePackages={"com.michael"})
public class ServiceOssApplication{
public static void main(String[] args){
SpringApplication.run(ServiceOssApplication.class,args);
}
}
二、网关模块gateway中进行对上传oss模块进行配置
spring.cloud.gateway.routes[4].id=service-oss
spring.cloud.gateway.routes[4].uri=lb://service-oss
spring.cloud.gateway.routes[4].predicates=Path=/*/oss/**
三、文件流的方式上传
Controller
@RestController
@RequestMapping("/api/oss/file")
public class FileApiController{
@Autowired
private FileService fileService;
//将本地文件上传到阿里云
@PostMapping("fileUpload")
public Result fileUpLoad(MultipartFile file){//SpringMVC中的,可以得到要上传的内容
//返回上传后的路径
String url = fileService.upload(file);
return Result.ok(url);
}
}
Service
public interface FileService{
String upload(MultipartFile file);
}
@Service
public class FileServiceImpl implements FileService{
@Override
public String upload(MultipartFile file){
//以下变量可以设置到配置文件中,然后通过工具类读取
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
String accessKeyId = "";
String accessKeySecret = "";
String bucket = "";
//创建OSSClient实例
OSS occClient = new OSSClientBuilder().build(endpoint,accessKeyId,accessKeySecret);
//上传文件流
try{
InputStream inputStream = file.getInputStream();//从Controller中获取用户上传的文件流
String fileName = file.getOriginalFilename();//获取文件名称(包括路径)
/**
由于同名原因会导致文件上传的覆盖问题,后上传的覆盖前上传的
*/
//采用uuid生成唯一值,添加到文件名称里(并且将里面的-用空串表示)
String uuid = UUID.randomUUID().toString().replaceAll("-","");
fileName = uuid+fileName;
//按照日期创建文件夹,上传到创建文件夹的里面(joda-time日期工具依赖)
String timeUrl = new DateTime().toString("yyyy/MM/dd");
fileName = timeUrl + "/" + fileName;
ossClient.putObject(bucket,fileName,inputStream);
//关闭OSSClient
ossClient.shutdown();
//上传之后的路径,可以从阿里云工作台的文件详情获取
String url = "https://"+bucketName+"."+endpoint+"/"+fileName;
return url;
}catch(IOException e){
e.printStackTrace();
}
}
}
基于AmazonS3实现 Spring Boot Starter
Amazon Simple Storage Service(Amazon S3,Amazon简便存储服务)是 AWS 最早推出的云服务之一,经过多年的发展,S3 协议在对象存储行业事实上已经成为标准。
- 提供了统一的接口 REST/SOAP 来统一访问任何数据
- 对 S3 来说,存在里面的数据就是对象名(键),和数据(值)
- 不限量,单个文件最高可达 5TB,可动态扩容
- 高速。每个 bucket 下每秒可达 3500 PUT/COPY/POST/DELETE 或 5500 GET/HEAD 请求
- 具备版本,权限控制能力
- 具备数据生命周期管理能力
阿里云OSS兼容S3
七牛云对象存储兼容S3
腾讯云COS兼容S3
Minio兼容S3
今天使用的是阿里云OSS对接阿里云OSS的SDK,后天我们使用的是腾讯COS对接是腾讯云COS,我们何不直接对接AmazonS3实现呢,这样后续不需要调整代码,只需要去各个云服务商配置就好了。
一、创建一个SpringBoot项目
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-s3 -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>${aws.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
二、配置文件OssProperties
oss.endpoint=xxx
oss.accessKey=xxx
oss.secretKey=xxx
@ConfigurationProperties(prefix = “oss”):将配置文件中oss开头的属性绑定到此对象中
@Data
@ConfigurationProperties(prefix = "oss")
public class OssProperties{
/**
* 对象存储服务的URL
*/
private String endpoint;
/**
* 区域
*/
private String region;
/**
* true path-style nginx 反向代理和S3默认支持 pathStyle模式 {http://endpoint/bucketname}
* false supports virtual-hosted-style 阿里云等需要配置为 virtual-hosted-style 模式{http://bucketname.endpoint}
* 只是url的显示不一样
*/
private Boolean pathStyleAccess = true;
/**
* Access key
*/
private String accessKey;
/**
* Secret key
*/
private String secretKey;
/**
* 最大线程数,默认:100
*/
private Integer maxConnections = 100;
}
三、创建接口OssTemplate
public interface OssTemplate{
void createBucket(String bucketName);//创建bucket
List<Bucket> getAllBuckets();//获取所有的bucket
void removeBucket(String bucketName);//通过bucket名称删除bucket
//上传文件
void putObject(String bucketName, String objectName, InputStream stream, String contextType) throws Exception;
void putObject(String bucketName, String objectName, InputStream stream) throws Exception;
//获取文件
S3Object getObject(String bucketName, String objectName);
//获取对象的url
String getObjectURL(String bucketName, String objectName, Integer expires);
//通过bucketName和objectName删除对象
void removeObject(String bucketName, String objectName) throws Exception;
//根据文件前置查询文件
List<S3ObjectSummary> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive);
}
@RequiredArgsConstructor
public class OssTemplateImpl implements OssTemplate{
private final AmazonS3 amazonS3;
//创建Bucket
@Override
@SneakyThrows
public void createBucket(String bucketName){
if ( !amazonS3.doesBucketExistV2(bucketName) ) {
amazonS3.createBucket((bucketName));
}
}
//获取所有的buckets
@Override
@SneakyThrows
public List<Bucket> getAllBuckets() {
return amazonS3.listBuckets();
}
//通过Bucket名称删除Bucket
@Override
@SneakyThrows
public void removeBucket(String bucketName) {
amazonS3.deleteBucket(bucketName);
}
//上传对象
@Override
@SneakyThrows
public void putObject(String bucketName, String objectName, InputStream stream, String contextType) {
putObject(bucketName, objectName, stream, stream.available(), contextType);
}
@Override
@SneakyThrows
public void putObject(String bucketName, String objectName, InputStream stream) {
putObject(bucketName, objectName, stream, stream.available(), "application/octet-stream");
}
//通过bucketName和objectName获取对象
@Override
@SneakyThrows
public S3Object getObject(String bucketName, String objectName) {
return amazonS3.getObject(bucketName, objectName);
}
//获取对象的url
@Override
@SneakyThrows
public String getObjectURL(String bucketName, String objectName, Integer expires) {
Date date = new Date();
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
calendar.add(Calendar.DAY_OF_MONTH, expires);
URL url = amazonS3.generatePresignedUrl(bucketName, objectName, calendar.getTime());
return url.toString();
}
//通过bucketName和objectName删除对象
@Override
@SneakyThrows
public void removeObject(String bucketName, String objectName) {
amazonS3.deleteObject(bucketName, objectName);
}
//根据bucketName和prefix获取对象集合
@Override
@SneakyThrows
public List<S3ObjectSummary> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) {
ObjectListing objectListing = amazonS3.listObjects(bucketName, prefix);
return objectListing.getObjectSummaries();
}
@SneakyThrows
private PutObjectResult putObject(String bucketName, String objectName, InputStream stream, long size,
String contextType) {
byte[] bytes = IOUtils.toByteArray(stream);
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(size);
objectMetadata.setContentType(contextType);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
// 上传
return amazonS3.putObject(bucketName, objectName, byteArrayInputStream, objectMetadata);
}
}
}
四、创建OssAutoConfiguration
OssAutoConfiguration:自动装配配置类,自动装配的bean有AmazonS3和OssTemplate
@Configuration
@RequiredArgsConstructor //lomnok的注解,替代@Autowired
@EnableConfigurationProperties(OssProperties.class) //自动装配我们的配置类
public class OssAutoConfiguration{
@Bean
@ConditionalOnMissingBean//bean被注册之后,注册相同类型的bean,就不会成功,它会保证你的bean只有一个,即你的实例只有一个。多个会报错
public AmazonS3 ossClient(OssProperties ossProperties){
//客户端配置,主要是全局的配置信息
ClientConfiguration cientConfiguration = new ClientConfiguration();
clientConfiguration.setMaxConnections(ossProperties.getMaxConnections());
//url以及region配置
AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder
.EndpointConfiguration(ossProperties.getEndpoint(), ossProperties.getRegion());
//凭证配置
AWSCredentials awsCredentials = new BasicAWSCredentials(ossProperties.getAccessKey(),
ossProperties.getSecretKey());
AWSCredentialsProvider awsCredentialsProvider = new AWSStaticCredentialsProvider(awsCredentials);
// build amazonS3Client客户端
return AmazonS3Client.builder().withEndpointConfiguration(endpointConfiguration)
.withClientConfiguration(clientConfiguration).withCredentials(awsCredentialsProvider)
.disableChunkedEncoding().withPathStyleAccessEnabled(ossProperties.getPathStyleAccess()).build();
}
@Bean
@ConditionalOnBean(AmazonS3.class)//当给定的在bean存在时,则实例化当前Bean
public OssTemplate ossTemplate(AmazonS3 amazonS3){
return new OssTemplateImpl(amazonS3);
}
}
五、ClientConfiguration对象
客户端配置,主要是全局的配置信息
六、创建spring.factories
在resources目录下新增META-INF包,下面新建spring.factories文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.qing.oss.OssAutoConfiguration
七、执行install打包到本地仓库
把springboot工程的启动类,配置文件干掉,干掉Test包。
最重要的是干掉pom文件的spring-boot-maven-plugin,要不然install报错。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
这样我们的一个oss-spring-boot-starter就完成了
执行install打包成jar到我们的本地仓库
到我们的本地仓库就能看到我们的oss-spring-boot-starter
八、测试
创建一个spring-boot工程当作我们的测试工程
①、pom文件新增我们的oss-spring-boot-starter依赖
<properties>
<oss.version>0.0.1-SNAPSHOT</oss.version>
</properties>
<dependency>
<groupId>com.qing</groupId>
<artifactId>oss-spring-boot-starter</artifactId>
<version>${oss.version}</version>
</dependency>
刷新maven后可以看到我们依赖加进来了。
解决打包没有注释的问题
可以发现我们的依赖没有注释没有Javadoc注释,在oss-string-boot-starter的pom文件下加入下面插件,重新install一下就好了。
<build>
<plugins>
<!-- 在打好的jar包中保留javadoc注释,实际会另外生成一个xxxxx-sources.jar -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
在我们的测试项目里面刷新一下maven可以看到已经带注释了
配置文件添加oss-spring-boot-starter所需要的配置
阿里云,腾讯cos,七牛云,minio等等的配置。
以Minio为例
oss.endpoint=xxx
oss.accessKey=xxx
oss.secretKey=xxx
编写测试方法
@SpringBootTest
class TestOssSpringBpptStarterApplicationTests {
@Autowired
private OssTemplate ossTemplate;
@Test
void contextLoads() {
ossTemplate.createBucket("oss02");
}
}
到我的Minio中查看发现测试成功。