SpringBoot 自定义starter 添加第三方组件(阿里云oss为例子)

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)

9.大家只需要照着这个模式,写一个组件(启动器(starter)), 别人就只需要引入, 减少了大量繁琐的配置和代码的编写, 大大的提高了重用性也简化了开发步骤
  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值