1. 程式人生 > >製作七牛-spring-boot-starter並上傳中央倉庫

製作七牛-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 執行測試

控制檯會打出我定製的資訊

傳送一個請求: