SpringCloud-Alibaba之OSS对象存储服务

阿里云的 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中查看发现测试成功。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值