以七牛云为例,手写一个Spring Boot的Starter

GitHub源码地址

概述

我们使用 Spring Boot,基本上都是沉醉在它 Stater 的方便之中。Starter 为我们带来了众多的自动化配置,有了这些自动化配置,我们可以不费吹灰之力就能搭建一个生产级开发环境,其实 Starter 的核心就是条件注解 @Conditional ,当 classpath下存在某一个Class时,某个配置才会生效,下面就以七牛云为例,写一个简单的Spring Boot Starter

项目目录结构

代码实现

1、创建一个普通的Maven项目,pom文件中加入以下依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>cn.mrain22.qiniu</groupId>
<artifactId>qiniu-spring-boot-starter</artifactId>
<version>1.0</version>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.1.5.RELEASE</version>
<optional>true</optional>
</dependency>
<!--七牛-->
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>7.2.20</version>
</dependency>

</dependencies>
</project>

2、编写一个MqiniuProperties,用来接受 application.properties中注入的值,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package cn.mrain22.qiniu;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @Author: Xiuming Lee
* @Date: 2019/6/1 12:31
* @Version 1.0
* @Describe: 七牛配置文件
*/
@ConfigurationProperties(prefix = "mqiniu")
public class MqiniuProperties {

/** accessKey*/
private String accessKey;
/** secretKey*/
private String secretKey;
/** 要上传的空间*/
private String bucketName;
/** 文件地址前缀,cdn地址*/
private String filePathPrefix;

//这里省略了 get/set
}

3、编写校验类MqiniuCondition,用来校验用户必要的配置信息是否填写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package cn.mrain22.qiniu;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.StringUtils;

/**
* @Author: Xiuming Lee
* @Date: 2019/6/1 16:03
* @Version 1.0
* @Describe: 校验类
*/
public class MqiniuCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata annotatedTypeMetadata) {
String ak = context.getEnvironment().getProperty("mqiniu.access-key");
String sk = context.getEnvironment().getProperty("mqiniu.secret-key");
String bucketName = context.getEnvironment().getProperty("mqiniu.bucket-name");

/** 校验用户是否将配置信息填写完整*/
if (StringUtils.isEmpty(ak)) {
throw new RuntimeException("Lack of qiniuyun configuration:access-key");
} else if (StringUtils.isEmpty(sk)) {
throw new RuntimeException("Lack of mqiniuyun configuration:secret-key");
} else if (StringUtils.isEmpty(bucketName)) {
throw new RuntimeException("Lack of qiniuyun configuration:bucket-name");
} else {
return true;
}
}
}

4、编写供调用的接口MqiniuService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package cn.mrain22.qiniu;

import com.qiniu.common.QiniuException;

/**
* @Author: Xiuming Lee
* @Date: 2019/6/1 16:12
* @Version 1.0
* @Describe: 七牛上传服务接口
*/
public interface MqiniuService {
/**
* 上传文件
* @param fileBytes 文件的字节数组
* @param fileName 文件名带后缀
* @return 上传后文件的url路径
*/
String uploadFile(byte[] fileBytes, String fileName) throws QiniuException;

/**
* 删除文件
* @param key 上传文件后返回的url路径
* @return
*/
boolean deleteByKey(String key) throws QiniuException;
}

5、编写默认的实现类MqiniuServiceImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package cn.mrain22.qiniu;

import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.UUID;

/**
* @Author: Xiuming Lee
* @Date: 2019/6/1 16:29
* @Version 1.0
* @Describe: 七牛上传删除实现类
*/
public class MqiniuServiceImpl implements MqiniuService {

@Autowired
private UploadManager uploadManager;
@Autowired
private BucketManager bucketManager;
@Autowired
private Auth auth;
@Autowired
private MqiniuProperties mqiniuProperties;

public String uploadFile(byte[] fileBytes, String fileName) throws QiniuException {
String fileExtName = fileName.substring(fileName.lastIndexOf(".") + 1);
String newFileName = UUID.randomUUID() + "." + fileExtName;
Response response = uploadManager.put(fileBytes, newFileName, getUploadToken());
//解析上传成功的结果
DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
String key = mqiniuProperties.getFilePathPrefix() + putRet.key;
return key;
}

public boolean deleteByKey(String key) throws QiniuException {
key = key.replace(mqiniuProperties.getFilePathPrefix(),"");
bucketManager.delete(mqiniuProperties.getBucketName(), key);
return true;
}

/**
* 获取上传凭证,普通上传
*/
private String getUploadToken() {
return this.auth.uploadToken(mqiniuProperties.getBucketName());

}
}

6、接下来就是我们的重轴戏,自动配置类的定义.MqiniuServiceAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package cn.mrain22.qiniu;

/**
* @Author: Xiuming Lee
* @Date: 2019/6/1 16:49
* @Version 1.0
* @Describe:
*/
// 装配配置属性

import com.qiniu.common.Region;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.UploadManager;
import com.qiniu.util.Auth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
// 自动装配这个properties类,读取yaml自定义内容
@EnableConfigurationProperties(MqiniuProperties.class)
// service类,@ConditionalOnClass某个 Class 位于类路径上,才会实例化一个Bean。也就是说,当classpath下发现该类的情况下进行实例化。
@ConditionalOnClass(MqiniuService.class)
// 校验类
@Conditional(MqiniuCondition.class)
// 当配置文件中 mqiniu 的值为 true 时,实例化此类。可以不填
@ConditionalOnProperty(prefix = "mqiniu", value = "true", matchIfMissing = true)
public class MqiniuServiceAutoConfiguration {
@Autowired
private MqiniuProperties mqiniuProperties;

/**
* 指定实例化接口的类
* @return
* @ConditionalOnMissingBean 当spring容器中不存在MqiniuService的实例时,默认调用这个。
* 如果你实现了MqiniuService接口,并添加到了Spring容器,则会使用你的MqiniuService实例。
*/
@Bean
@ConditionalOnMissingBean
public MqiniuService qiNiuYunService() {
return new MqiniuServiceImpl();
}

/**
* 构建一个七牛上传工具实例
* @return
*/
@Bean
@ConditionalOnMissingBean
public UploadManager uploadManager() {
return new UploadManager(new com.qiniu.storage.Configuration(Region.autoRegion()));
}

/**
* 认证信息实例
* @return
*/
@Bean
public Auth auth() {
return Auth.create(mqiniuProperties.getAccessKey(), mqiniuProperties.getSecretKey());
}

/**
* 构建七牛空间管理实例
* @return
*/
@Bean
public BucketManager bucketManager() {
return new BucketManager(auth(),new com.qiniu.storage.Configuration(Region.autoRegion()));
}
}

7、spring boot加载我们的装配类,需要在resource目录下新建META-INF/spring.factories内容如下:

1
org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.mrain22.qiniu.MqiniuServiceAutoConfiguration

本地安装

完成以上步骤,一个简单Spring Boot Starter也就写完了,下一步就是将其发布到Maven仓库,我这里就简单点,只发布到本地。

方式很简单,在IntelliJ IDEA 中,点击右边的 Maven Project,然后选择 Lifecycle 中的 install,双击即可,如下:

双击完成后,这个 Starter就安装到我们本地仓库了。

使用 Starter

在我们需要的项目中引入依赖即可。如下:

1
2
3
4
5
<dependency>
<groupId>cn.mrain22.qiniu</groupId>
<artifactId>qiniu-spring-boot-starter</artifactId>
<version>1.0</version>
</dependency>

application.properties中添加以下属性。

1
2
3
4
mqiniu.access-key=your qiniu`s ak
mqiniu.secret-key=your qiniu`s sk
mqiniu.bucket-name=空间名称
mqiniu.file-path-prefix=your qiniu cdn url

代码使用

1
2
3
4
5
6
7
8
9
10
@Autowired
private MqiniuService mqiniuService;

@PostMapping("/file")
public Object fileUploadTest(MultipartFile file) throws Exception {
byte[] fileBytes = file.getBytes();
String filename = file.getOriginalFilename();
String url = mqiniuService.uploadFile(fileBytes, filename);
return url;
}

#

Xiuming Lee wechat
欢迎您扫一扫上面的微信公众号订阅,更多惊喜等着您哦!
-------------本文结束感谢您的阅读-------------