製作七牛-spring-boot-starter並上傳中央倉庫
說明
最近使用七牛雲的時候突然想自己製作一個springboot-starter版本,畢竟可以把ak,sk等等直接寫在application.yml裡實在是很好用啊。於是自己製作了qiniu-spring-boot-starter 0.1 RELEASE版(目前版本有簡單上傳、覆蓋上傳和刪除檔案等)( ̄▽ ̄)~*已經上傳到maven中央倉庫和mvnrepository了,地址戳->http://mvnrepository.com/artifact/cn.yunlingfly/qiniu-spring-boot-starter,程式碼放在了github上戳->https://github.com/Yunlingfly/qiniu-starter
快速開始
首先給出專案結構:
新建springboot專案,更新pom.xml(這個pom檔案有點長,主要是配置了上傳到中央倉庫必須的屬性,詳解戳我的另一篇博文->SpringBoot專案釋出到Maven中央倉庫):
<?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.yunlingfly</groupId> <artifactId>qiniu-spring-boot-starter</artifactId> <version>0.1-RELEASE</version> <packaging>jar</packaging> <name>qiniu-spring-boot-starter</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <distributionManagement> <snapshotRepository> <id>oss</id> <url>https://oss.sonatype.org/content/repositories/snapshots</url> </snapshotRepository> <repository> <id>oss</id> <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url> </repository> </distributionManagement> <profiles> <profile> <id>release</id> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>2.2.1</version> <executions> <execution> <id>attach-sources</id> <goals> <goal>jar-no-fork</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-javadoc-plugin</artifactId> <version>2.9.1</version> <executions> <execution> <id>attach-javadocs</id> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-gpg-plugin</artifactId> <version>1.5</version> <executions> <execution> <id>sign-artifacts</id> <phase>verify</phase> <goals> <goal>sign</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles> <licenses> <license> <name>The Apache Software License, Version 2.0</name> <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> </license> </licenses> <scm> <connection>https://github.com/Yunlingfly/qiniu-starter</connection> <url>https://github.com/Yunlingfly/qiniu-starter.git</url> <developerConnection>https://github.com/Yunlingfly</developerConnection> </scm> <developers> <developer> <name>yunlingfly</name> <email>
[email protected]</email> <url>https://github.com/Yunlingfly</url> </developer> </developers> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.10</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- 七牛雲物件儲存 --> <dependency> <groupId>com.qiniu</groupId> <artifactId>qiniu-java-sdk</artifactId> <version>7.1.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <!--<plugin>--> <!--<groupId>org.springframework.boot</groupId>--> <!--<artifactId>spring-boot-maven-plugin</artifactId>--> <!--</plugin>--> <!-- Springboot的專案打包給其他專案用的話不能使用自帶的打包外掛,使用下面的 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <!-- sonatype提供了自動release的外掛,這意味著執行mvn clean deploy後不用手動去close-> release了,此外掛會自動release我們的專案到Maven中央倉庫。 --> <plugin> <groupId>org.sonatype.plugins</groupId> <artifactId>nexus-staging-maven-plugin</artifactId> <version>1.6.7</version> <extensions>true</extensions> <configuration> <serverId>oss</serverId> <nexusUrl>https://oss.sonatype.org/</nexusUrl> <autoReleaseAfterClose>true</autoReleaseAfterClose> </configuration> </plugin> </plugins> </build> </project>
1 首先編寫讀取yaml配置的QiNiuProperties:
package cn.yunlingfly.qiniuspringbootstarter.infra.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* 七牛雲屬性配置
*
* @author [email protected]
*/
@Component
@ConfigurationProperties(prefix = "qiniu")
public class QiNiuProperties {
/**
* 七牛雲的金鑰
*/
private String accessKey = "access-key";
private String secretKey = "secret-key";
/**
* 儲存空間名字
*/
private String bucketName = "bucket-name";
/**
* 一般設定為cdn
*/
private String cdnPrefix = "cdn";
public String getAccessKey() {
return accessKey;
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getBucketName() {
return bucketName;
}
public void setBucketName(String bucketName) {
this.bucketName = bucketName;
}
public String getCdnPrefix() {
return cdnPrefix;
}
public void setCdnPrefix(String cdnPrefix) {
this.cdnPrefix = cdnPrefix;
}
}
2 編寫校驗程式QiNiuCondition:
package cn.yunlingfly.qiniuspringbootstarter.infra.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.StringUtils;
/**
* 校驗類
*
* @author [email protected]
*/
public class QiNiuCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String ak = context.getEnvironment().getProperty("qiniu.access-key");
String sk = context.getEnvironment().getProperty("qiniu.secret-key");
String bucketName = context.getEnvironment().getProperty("qiniu.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 qiniuyun configuration:qiniu.secret-key");
} else if (StringUtils.isEmpty(bucketName)) {
throw new RuntimeException("Lack of qiniuyun configuration:qiniu.bucket-name");
} else {
return true;
}
}
}
3 編寫供呼叫的介面IQiniuService :
package cn.yunlingfly.qiniuspringbootstarter.api.service;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import java.io.File;
/**
* IQiniuService介面
*/
public interface IQiniuService {
/**
* 上傳檔案
* <p>檔案上傳</p>
*
* @param file 填寫上傳檔案File型別
* @param key 新增上傳的key值
* @param existed 是否已經存在
* @return 返回com.qiniu.http.Response
* @throws QiniuException 丟擲QiniuException異常
*/
Response uploadFile(File file, String key, boolean existed) throws QiniuException;
/**
* 上傳檔案
* <p>檔案路徑上傳</p>
*
* @param filePath 填寫上傳檔案的位置
* @param key 新增上傳的key值
* @param existed 是否已經存在
* @return 返回com.qiniu.http.Response
* @throws QiniuException 丟擲QiniuException異常
*/
Response uploadFile(String filePath, String key, boolean existed) throws QiniuException;
/**
* 刪除
*
* @param key 新增上傳的key值
* @throws QiniuException 丟擲QiniuException異常
*/
void deleteFile(String key) throws QiniuException;
}
4 介面實現類QiniuServiceImpl :
package cn.yunlingfly.qiniuspringbootstarter.api.service.impl;
import cn.yunlingfly.qiniuspringbootstarter.api.service.IQiniuService;
import cn.yunlingfly.qiniuspringbootstarter.infra.config.QiNiuProperties;
import com.alibaba.fastjson.JSON;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.UploadManager;
import com.qiniu.util.Auth;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.io.File;
/**
* service實現類
*
* @author [email protected]
*/
@Service
public class QiniuServiceImpl implements IQiniuService {
private static final Logger logger = LoggerFactory.getLogger(QiniuServiceImpl.class);
@Autowired
private UploadManager uploadManager;
@Autowired
private BucketManager bucketManager;
@Autowired
private Auth auth;
@Autowired
private QiNiuProperties qiNiuProperties;
@Override
public Response uploadFile(File file, String key, boolean existed) throws QiniuException {
Response response;
// 覆蓋上傳
if (existed) {
response = this.uploadManager.put(file, key, getUploadToken(key));
} else {
System.out.println("使用檔案上傳");
response = this.uploadManager.put(file, key, getUploadToken());
int retry = 0;
while (response.needRetry() && retry < 3) {
response = this.uploadManager.put(file, key, getUploadToken());
retry++;
}
}
return response;
}
@Override
public Response uploadFile(String filePath, String key, boolean existed) throws QiniuException {
Response response;
// 覆蓋上傳
if (existed) {
response = this.uploadManager.put(filePath, key, getUploadToken(key));
} else {
response = this.uploadManager.put(filePath, key, getUploadToken());
int retry = 0;
while (response.needRetry() && retry < 3) {
response = this.uploadManager.put(filePath, key, getUploadToken());
retry++;
}
}
return response;
}
@Override
public void deleteFile(String key) throws QiniuException {
bucketManager.delete(qiNiuProperties.getBucketName(), key);
}
/**
* 獲取上傳憑證,覆蓋上傳
*/
private String getUploadToken(String fileName) {
return this.auth.uploadToken(qiNiuProperties.getBucketName(), fileName);
}
/**
* 獲取上傳憑證,普通上傳
*/
private String getUploadToken() {
return this.auth.uploadToken(qiNiuProperties.getBucketName());
}
/**
* 這個註解在這裡沒實際用處,就是為了方便在該類構造完成後列印日誌,看看配置資訊是否載入到配置類中了
*/
@PostConstruct
public void init() {
logger.info("qiNiuProperties: {}", JSON.toJSONString(qiNiuProperties));
}
}
5 自動裝配QiNiuYunServiceAutoConfiguration :
package cn.yunlingfly.qiniuspringbootstarter;
import cn.yunlingfly.qiniuspringbootstarter.api.service.IQiniuService;
import cn.yunlingfly.qiniuspringbootstarter.api.service.impl.QiniuServiceImpl;
import cn.yunlingfly.qiniuspringbootstarter.infra.condition.QiNiuCondition;
import cn.yunlingfly.qiniuspringbootstarter.infra.config.QiNiuProperties;
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;
/**
* 七牛雲屬性配置
*
* @author [email protected]
*/
// 裝配配置屬性
@Configuration
// 自動裝配這個properties類,讀取yaml自定義內容
@EnableConfigurationProperties(QiNiuProperties.class)
// service類,@ConditionalOnClass某個 Class 位於類路徑上,才會例項化一個Bean。也就是說,當classpath下發現該類的情況下進行例項化。
@ConditionalOnClass(IQiniuService.class)
// 校驗類
@Conditional(QiNiuCondition.class)
// 當配置檔案中 qiniu 的值為 true 時,例項化此類。可以不填
@ConditionalOnProperty(prefix = "qiniu", value = "true", matchIfMissing = true)
public class QiNiuYunServiceAutoConfiguration {
@Autowired
private QiNiuProperties qiNiuYunProperties;
/// 指定例項化介面的類
@Bean
@ConditionalOnMissingBean(QiniuServiceImpl.class)
public IQiniuService qiNiuYunService() {
return new QiniuServiceImpl();
}
// 構建一個七牛上傳工具例項
@Bean
public UploadManager uploadManager() {
return new UploadManager();
}
// 認證資訊例項
@Bean
public Auth auth() {
return Auth.create(qiNiuYunProperties.getAccessKey(), qiNiuYunProperties.getSecretKey());
}
// 構建七牛空間管理例項
@Bean
public BucketManager bucketManager() {
return new BucketManager(auth());
}
}
6 讓springboot載入我們的裝配類,在resource目錄下新建METE-INF/spring.factories(檔名不能打錯了)內容如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.yunlingfly.qiniuspringbootstarter.QiNiuYunServiceAutoConfiguration
7 寫完後就可以釋出到maven中央倉庫了(如果只是本地用的話直接install就可以在本地m2倉庫找到並引用了):
mvn clean deploy -P release
編寫測試來試試這個spring-boot-starter能不能用:
1 新建一個springboot專案,引入我們製作的依賴:
<dependency>
<groupId>cn.yunlingfly</groupId>
<artifactId>qiniu-spring-boot-starter</artifactId>
<version>0.1-RELEASE</version>
</dependency>
2 修改application.yml(這裡寫配置的時候IDEA會有程式碼提示的哦):
server:
port: 8081
qiniu:
secret-key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
access-key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
bucket-name: xxxxx
3 編寫測試Controller類:
package cn.yunlingfly.qiniustarterdemo.controller;
import cn.yunlingfly.qiniuspringbootstarter.api.service.IQiniuService;
import com.qiniu.common.QiniuException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Autowired
IQiniuService qiniuService;
@RequestMapping(value = "qiniu",method = RequestMethod.GET)
public String hello(){
try {
// 引數分別是:上傳檔案位置、上傳key值、是否是覆蓋上傳
qiniuService.uploadFile("images/1.png","1.png",true);
}catch (QiniuException e){
e.printStackTrace();
return "failed";
}
return "success";
}
}
ps:如果自動注入的時候出現下面的情況是沒有問題的,這是spring檢查機制的結果,程式是能執行的,如果想改的話可以設定在intellij idea file-settings-editor-Inspections-spring 把右邊的Mixed 改為warning
4 執行測試
控制檯會打出我定製的資訊
傳送一個請求: