說明
最近使用七牛雲的時候突然想自己製作一個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
使用方法戳->https://github.com/Yunlingfly/qiniu-starter#qiniu-spring-boot-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 yunlingfly@csdn
*/
@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 yunlingfly@csdn
*/
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 yunlingfly@csdn
*/
@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 yunlingfly@csdn
*/
// 裝配配置屬性
@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 運行測試
控制檯會打出我定製的信息
發送一個請求: