starter可以理解为一个可拔插式的插件,例如,你想使用jdbc插件,那么可以使用spring-boot-starter-jdbc(官方);如果想使用mongodb(官方),可以使用spring-boot-starter-data-mongodb(官方)。
当然我们也可以自定义starter,使其变成一个组件, 例如将微信支付,支付宝支付,阿里云oss等常见的第三方工具封装,然后给他人使用,废话不多说,直接上步骤
我们以阿里云oss(云储存) 为例 (博主这里用的是IDEA)
1.创建一个空项目 ( idea 的 file >> project)
创建好之后,
2 .在空项目里面创建一个新Module, 选择Maven,这一块(子项目)称为(启动器模块)
大家的取名(groupId/artifactId)随意
也可以参考 我的pom.xml
<groupId>com.expansion</groupId>
<artifactId>expansion-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
3 .在空项目里面再创建一个新Module, 选择Spring Initializr,这一块(子项目)称为(自动配置模块)
大家的取名(groupId/artifactId)随意
也可以参考 我的pom.xml
<groupId>com.example.starter</groupId>
<artifactId>expansion-spring-boot-starter-aliyun</artifactId>
<version>0.0.1-SNAPSHOT</version>
在这个子模块里,可以把 关于test的依赖和test包以及项目的启动类都删掉,这里用不到
4 .在你(启动器模块)的pom文件加上(自动配置模块)的依赖
<!--启动器-->
<dependencies>
<!--引入自动配置模块-->
<dependency>
<groupId>com.example.starter</groupId>
<artifactId>expansion-spring-boot-starter-aliyun</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
5 .这里就在(自动配置模块)开始操作阿里云Oss
- 5.1
引入阿里云oss官方依赖:
<!-- aliyunoss-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>2.8.3</version>
</dependency>
-
5.2
在你的项目中创建 oss参数实体类 : OSSClientConstants
以下是OSSClientConstants代码:ps :
这各类中只有属性和对应的get/set方法
@ConfigurationProperties用于指定配置,注意, prefix 不能出现大写
package com.expansion.starter.aliyunoss;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @Auther: lj
* @Date: 2019/4/1 0001 16:18
*/
@ConfigurationProperties(prefix = "expansion.aliyun-oss") //prefix 中不能出现大写
public class OSSClientConstants {
//阿里云API的外网域名
private String endPoint;
//阿里云API的密钥Access Key ID
private String accessKeyId;
//阿里云API的密钥Access Key Secret
private String accessKeySecret;
//阿里云OSS文件夹
private String backetName;
public String getAccessKeyId() {
return accessKeyId;
}
public void setAccessKeyId(String accessKeyId) {
this.accessKeyId = accessKeyId;
}
public String getAccessKeySecret() {
return accessKeySecret;
}
public void setAccessKeySecret(String accessKeySecret) {
this.accessKeySecret = accessKeySecret;
}
public String getBacketName() {
return backetName;
}
public String getEndPoint() {
return endPoint;
}
public void setEndPoint(String endPoint) {
this.endPoint = endPoint;
}
public void setBacketName(String backetName) {
this.backetName = backetName;
}
}
- 5.3
OSSClientConstants创建完毕后在创建 操作oss文件操作类 : AliyunOSSUtil
PS:
这里就只需要将 OSSClientConstants 设置成 AliyunOSSUtil 的 属性,并添加s/g构造方法
在这里插入代码片package com.expansion.starter.aliyunoss;
import java.io.*;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.Bucket;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.DeleteObjectsResult;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;
import org.springframework.util.StringUtils;
/**
* 阿里云oss文件操作
* 支持图片,ppt,word等常见格式的文件上传
* @author lj
*
*/
public class AliyunOSSUtil {
//日志
public static final Logger LOGGER = LoggerFactory.getLogger(AliyunOSSUtil.class);
//oss参数实体类
private static OSSClientConstants ossEntity;
public OSSClientConstants getOssEntity() {
return ossEntity;
}
public void setOssEntity(OSSClientConstants ossEntity) {
this.ossEntity = ossEntity;
}
/**
* 获取阿里云OSS客户端对象
* @return ossClient
*/
static OSSClient getOSSClient() {
return new OSSClient(ossEntity.getEndPoint(), ossEntity.getAccessKeyId(), ossEntity.getAccessKeySecret());
}
/**
* 创建空间
* @param ossClient OSS连接
* @param bucketName 存储空间
* @return String
*/
public static String createBucketName(OSSClient ossClient, String bucketName) {
//存储空间
final String bucketNames = bucketName;
if (!ossClient.doesBucketExist(bucketName)) {
//创建存储空间
Bucket bucket = ossClient.createBucket(bucketName);
LOGGER.info("创建存储空间成功");
return bucket.getName();
}
return bucketNames;
}
/**
* 创建文件夹
* @param ossClient oss连接
* @param bucketName 存储空间
* @param folder
* @return 文件夹名
*/
public static String createFolder(OSSClient ossClient, String bucketName, String folder) {
//文件夹名
final String keySuffixWithSlash = folder;
//判断文件夹是否存在,不存在则创建
if (!ossClient.doesObjectExist(bucketName, keySuffixWithSlash)) {
//创建文件夹
ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
LOGGER.info("创建文件夹成功");
//得到文件夹名
OSSObject object = ossClient.getObject(bucketName, keySuffixWithSlash);
String fileDir = object.getKey();
return fileDir;
}
return keySuffixWithSlash;
}
/**
* 上传文件至OSS
* @param ossClient oss连接
* @param file 上传文件(文件全路径)
* @param bucketName 存储空间
* @param folder 模拟文件夹名
* @return String 返回的唯一MD5数字签名
* */
static String uploadObject2OSS(OSSClient ossClient, File file, String bucketName, String folder) {
String resultStr = null;
try {
//以输入流的形式上传文件
InputStream is = new FileInputStream(file);
//文件名
String fileName = file.getName();
//文件大小
Long fileSize = file.length();
//创建上传Object的Metadata
ObjectMetadata metadata = new ObjectMetadata();
//上传的文件的长度
metadata.setContentLength(is.available());
//指定该Object被下载时的网页的缓存行为
metadata.setCacheControl("no-cache");
//指定该Object下设置Header
metadata.setHeader("Pragma", "no-cache");
//指定该Object被下载时的内容编码格式
metadata.setContentEncoding("utf-8");
//文件的MIME,定义文件的类型及网页编码,决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成,
//如果没有扩展名则填默认值application/octet-stream
metadata.setContentType(getContentType(fileName));
//指定该Object被下载时的名称(指示MINME用户代理如何显示附加的文件,打开或下载,及文件名称)
metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
//上传文件 (上传文件流的形式)
PutObjectResult putResult = ossClient.putObject(bucketName, folder + fileName, is, metadata);
//解析结果
resultStr = putResult.getETag();
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
}
return resultStr;
}
/**
* 通过文件名判断并获取OSS服务文件上传时文件的contentType
* @param fileName 文件名
* @return 文件的contentType
*/
static String getContentType(String fileName) {
//文件的后缀名
String fileExtension = fileName.substring(fileName.lastIndexOf("."));
fileExtension = fileExtension.trim();
if (".bmp".equalsIgnoreCase(fileExtension)) {
return "image/bmp";
}
if (".gif".equalsIgnoreCase(fileExtension)) {
return "image/gif";
}
if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension) || ".png".equalsIgnoreCase(fileExtension)) {
return "image/jpeg";
}
if (".html".equalsIgnoreCase(fileExtension)) {
return "text/html";
}
if (".txt".equalsIgnoreCase(fileExtension)) {
return "text/plain";
}
if (".vsd".equalsIgnoreCase(fileExtension)) {
return "application/vnd.visio";
}
if (".ppt".equalsIgnoreCase(fileExtension) || ".pptx".equalsIgnoreCase(fileExtension)) {
return "application/vnd.ms-powerpoint";
}
if (".doc".equalsIgnoreCase(fileExtension) || ".docx".equalsIgnoreCase(fileExtension)) {
return "application/msword";
}
if (".xml".equalsIgnoreCase(fileExtension)) {
return "text/xml";
}
if (".apk".equalsIgnoreCase(fileExtension)) {
return "application/vnd.android.package-archive";
}
if (".mp4".equalsIgnoreCase(fileExtension)) {
return "video/mp4";
}
if (".x-flv".equalsIgnoreCase(fileExtension)) {
return "video/x-flv";
}
if (".avi".equalsIgnoreCase(fileExtension)) {
return "video/avi";
}
if (".rmvb".equalsIgnoreCase(fileExtension) || ".rm".equalsIgnoreCase(fileExtension)) {
return "application/octet-stream";
}
if (".wmv".equalsIgnoreCase(fileExtension)) {
return "video/x-ms-wmv";
}
if (".mov".equalsIgnoreCase(fileExtension)) {
return "video/quicktime";
}
if (".3gp".equalsIgnoreCase(fileExtension)) {
return "video/3gpp";
}
//默认返回类型
return "image/jpeg";
}
/**
* 获得url链接
* @param key key
* @param ossClient ossClient
* @param backetName backetName
* @return String
*/
static String getUrl(String key, OSSClient ossClient, String backetName) {
// 设置URL有效期
Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 100);
// 生成URL
URL url = ossClient.generatePresignedUrl(backetName, key, expiration);
if (url != null) {
return url.toString();
}
return null;
}
/**
* 获得返回路径
* @param fileUrl fileUrl
* @param ossClient ossClient
* @param backetName backetName
* @param folder folder
* @return String
*/
static String getImgUrl(String fileUrl, OSSClient ossClient, String backetName, String folder) {
LOGGER.info(fileUrl);
if (!StringUtils.isEmpty(fileUrl)) {
String[] split = fileUrl.split("/");
return getUrl(folder + split[split.length - 1], ossClient, backetName);
}
return null;
}
/**
* 文件上传
* 返回oss网络路径,可直接浏览器访问或下载
* @param folder folder
* @param file file
* @return String
*/
public static String aLiYunOssUpload(File file, String folder) {
//初始化OSSClient
OSSClient ossClient = AliyunOSSUtil.getOSSClient();
String md5key = AliyunOSSUtil.uploadObject2OSS(ossClient, file, ossEntity.getBacketName(), folder);
LOGGER.info("上传后的文件MD5数字唯一签名:" + md5key);
//String imgUrl = getImgUrl(name, ossClient, BACKET_NAME, folder);
String imgUrl = "https://" + ossEntity.getBacketName() + "." + ossEntity.getEndPoint() + "/" + folder + file.getName();
//返回网络路径
return imgUrl;
}
/**
* 文件删除(批量)
* @param keys keys
* @return Map
*/
public static Map<String, Object> aLiYunOssDelete(List<String> keys) {
Map<String, Object> result = new HashMap<String, Object>();
//初始化OSSClient
OSSClient ossClient = AliyunOSSUtil.getOSSClient();
try {
DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(ossEntity.getBacketName()).withKeys(keys));
//返回的成功删除Object的结果
List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
int count = 0;
for (String string : deletedObjects) {
count = count + 1;
result.put("item" + count, "第" + count + "张:" + string);
}
if (keys.size() == deletedObjects.size()) {
result.put("status", 0);
} else {
result.put("status", 1);
}
result.put("successCount", deletedObjects.size());
// 关闭client
ossClient.shutdown();
} catch (Exception e) {
LOGGER.error("删除--阿里云OSS服务器异常." + e.getMessage(), e);
result.put("status", 1);
result.put("msg", "删除--阿里云OSS服务器异常.");
}
//返回网络路径
return result;
}
}
- 5.4
AliyunOSSUtil 和 OSSClientConstants创建完之后,再来添加核心 : 自动配置类
我这里取名 : AliyunAutoConfiguration :
作用是,将你的写好的工具类注册成组件
PS :
@EnableConfigurationProperties 用于绑定属性文件,也就是OSSClientConstants类
package com.expansion.starter.config;
import com.expansion.starter.aliyunoss.AliyunOSSUtil;
import com.expansion.starter.aliyunoss.OSSClientConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Auther: lj
* 阿里云自动配置类
* @EnableConfigurationProperties 绑定属性文件
*/
@Configuration
@EnableConfigurationProperties(OSSClientConstants.class)
public class AliyunAutoConfiguration {
@Autowired
OSSClientConstants ossEntity;
/**
* oss组件
* @return AliyunOSSUtil
*/
@Bean
public AliyunOSSUtil aliyunOSSUtil(){
AliyunOSSUtil aliyunOSSUtil = new AliyunOSSUtil();
aliyunOSSUtil.setOssEntity(ossEntity);
return aliyunOSSUtil;
}
}
- 5.4.1
接下来在 自动配置模块 项目下的类路径(resources) 文件夹下创建 MATA-INF/spring.factories
文件内容:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.expansion.starter.config.AliyunAutoConfiguration
- 5.5
到这一步基本完成,现在我们就可以打包测试了
5.5.1
用mvn命令或者点击最右侧的 Maven projects
首先选择 (自动配置模块) 进行 install
然后选择 (启动器模块) 进行 install
到这一步,starter制作基本完成
接下来就可以测试了
6 测试
-
6.1用Spring Initializr快速 创建一个新的springboot工程
-
6.2 添加自定义的starter依赖:
<!--引入自定义的starter-->
<dependency>
<groupId>com.expansion</groupId>
<artifactId>expansion-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
- 6.3
在application.properties或者.yml里面设置 阿里云oss所需的属性:
这里就是在 5.2 步骤的时候用 @ConfigurationProperties指定的prefix
application.properties:
expansion.aliyun-oss.endPoint = XXX
expansion.aliyun-oss.accessKeyId = XXX
expansion.aliyun-oss.accessKeySecret = XXX
expansion.aliyun-oss.backetName = XXX
- 6.4
编写controller进行测试
/**
* @Auther: lj
*/
@Controller
public class TestController {
@Autowired
AliyunOSSUtil aliyunOSSUtil;
@ResponseBody
@GetMapping("/upload")
public String upload() {
//将E盘下的文件上传给oss并返回oss路径
String files="E:\\pic\\11.jpg";
File file =new File(files);
return aliyunOSSUtil.aLiYunOssUpload(file, "test文件夹");
}
}
7. 到这里基本就完成了对oss 自定义starter的编写, 可以依照着这个模式,还可以自定义一些工具类,下面是会用到的一些注解介绍
@Configuration //指定这个类是一个配置类
@ConditionalOnXXX //在指定条件成立的情况下自动配置类生效
@AutoConfigureAfter //指定自动配置类的顺序
@Bean //给容器中添加组件
@ConfigurationPropertie//结合相关xxxProperties类来绑定相关的配置
@EnableConfigurationProperties //让xxxProperties生效加入到容器中
//自动配置类要能加载
// 将需要启动就加载的自动配置类,配置在META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
下面是你根据自己条件 ,可能会用到的一些条件注解介绍 :
@ConditionalOnClass:当类路径classpath下有指定的类的情况下进行自动配置
@ConditionalOnMissingBean:当容器(Spring Context)中没有指定Bean的情况下进行自动配置
@ConditionalOnProperty(prefix = “example.service”, value = “enabled”, matchIfMissing = true),当配置文件中example.service.enabled=true时进行自动配置,如果没有设置此值就默认使用matchIfMissing对应的值
@ConditionalOnMissingBean,当Spring Context中不存在该Bean时。
@ConditionalOnBean:当容器(Spring Context)中有指定的Bean的条件下
@ConditionalOnMissingClass:当类路径下没有指定的类的条件下
@ConditionalOnExpression:基于SpEL表达式作为判断条件
@ConditionalOnJava:基于JVM版本作为判断条件
@ConditionalOnJndi:在JNDI存在的条件下查找指定的位置
@ConditionalOnNotWebApplication:当前项目不是Web项目的条件下
@ConditionalOnWebApplication:当前项目是Web项目的条件下
@ConditionalOnResource:类路径下是否有指定的资源
@ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者在有多个Bean的情况下,用来指定首选的Bean
8. 自定义starter模式步骤
1 . 创建一个启动器,启动器只用来做依赖导入;
2 . 专门来写一个自动配置模块;
3 . 启动器依赖自动配置;别人只需要引入启动器(starter)