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.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)