Spring--COS及工厂模式应用

一, 简介

     项目中我们可能会遇到上传文件到云上,有阿里, 百度云BOS(Baidu Object Storage), 腾讯COS(Cloud Object Storage), 七牛 等等, 统一名称都叫 对象存储服务.  这里不主要讲文件上传,因为官方给的文档已经非常非常的详细啦, 我主要写一下在这个文件上传的过程中工厂模式的应用;

COS文档: https://cloud.tencent.com/document/product/436/12263#object-api-.E6.8F.8F.E8.BF 

工厂模式, 什么是工厂模式? 我想在spring使用了这么久,仍然不知道的话,那就和我一样啦. 

维基百科的解释: 

       工厂方法模式(英语:Factory method pattern)是一种实现了“工厂”概念的面向对象设计模式。就像其他创建型模式一样,它也是处理在不指定对象具体类型的情况下创建对象的问题。工厂方法模式的实质是“定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。”

      创建一个对象常常需要复杂的过程,所以不适合包含在一个复合对象中。创建对象可能会导致大量的重复代码,可能会需要复合对象访问不到的信息,也可能提供不了足够级别的抽象,还可能并不是复合对象概念的一部分。工厂方法模式通过定义一个单独的创建对象的方法来解决这些问题。由子类实现这个方法来创建具体类型的对象。

      整理一下,具体的意思就是 为了方便拓展和降低耦合,将复杂的多样的并且有有相同功能的对象进行抽象,由不同的子类来实现不同的功能, 由工厂负责进行子类的实例化.

二, 在代码中的应用

    1, 我们进行腾讯云的对象操作,当然少不了他们的SDK:

		<dependency> <!-- 腾讯云 -->
		    <groupId>com.qcloud</groupId>
		    <artifactId>cos_api</artifactId>
		    <version>5.4.2</version>
		</dependency>

     2, application.properties 中的自定义配置:

#腾讯云
oss.cloud.type=1
oss.cloud.qcloudDomain=https://xxxxx-xxxxxxxx.cos.ap-chengdu.myqcloud.com
oss.cloud.qcloudRegion=ap-chengdu
oss.cloud.qcloudSecretId=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
oss.cloud.qcloudSecretKey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
oss.cloud.qcloudBucketName=xxxxx-xxxxxxxxxxx

     3, bean 配置:  CloudConfig.java

package com.gy.fast.common.config.oss;


import org.hibernate.validator.constraints.Range;
import org.hibernate.validator.constraints.URL;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import com.gy.fast.common.validator.AliyunGroup;
import com.gy.fast.common.validator.QcloudGroup;
import com.gy.fast.common.validator.QiniuGroup;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

/**
 * 云存储配置信息
 * @author geYang
 * @date 2018-05-21
 */
@Component
@ConfigurationProperties(prefix = "oss.cloud")
public class CloudConfig {
    /**
     * 类型 0:本地, 1:腾讯, 2:阿里云 , 3:七牛    
     */
    private Integer type;

    /**
     * 腾讯云绑定的域名
     */
    private String qcloudDomain;
    /**
     * 腾讯云路径前缀
     */
    private String qcloudPrefix;
    /**
     * 腾讯云AppId
     */
    private String qcloudAppId;
    /**
     * 腾讯云SecretId
     */
    private String qcloudSecretId;
    /**
     * 腾讯云SecretKey
     */
    private String qcloudSecretKey;
    /**
     * 腾讯云BucketName
     */
    private String qcloudBucketName;
    /**
     * 腾讯云COS所属地区
     */
    private String qcloudRegion;

    // get / set
 

    // toString()

	
}

    4, 到工厂模式啦, 首先我们要将上传的方法抽象出来

package com.gy.fast.common.config.oss;

import java.io.IOException;
import java.util.Date;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import com.gy.fast.common.util.DateUtil;

/**
 * 文件上传基础类
 * @author geYang
 * @date 2018-05-21
 */
public abstract class BaseUpload {
	
	/**
	 * 生成上传文件名(key:COS的文件路径,即从Bucket根路径开始)
	 * @param file 文件
	 * @param path 目录
	 * @return 上传文件名
	 * @author geYang
	 * @date 2018-05-21 17:51
	 */
	protected final String getKey(MultipartFile file, String path) {
		// 获取文件原先名称
		String originalName = file.getOriginalFilename();
		// 取到上传图片的后缀名
        String suffix= originalName.substring(originalName.lastIndexOf("."));
        // 生成新的文件名
        StringBuffer key = new StringBuffer();
        if (!StringUtils.isBlank(path)) {
        	key.append(path).append("/");
        }
        key.append(DateUtil.format(new Date(),"yyyyMMddHHmmss"))
        	.append(RandomStringUtils.randomAlphabetic(5))
        	.append(suffix);
		return key.toString();
	}
	
	/**
	 * 获取访问路径
	 * @param domain 访问域名
	 * @param key    文件名称
	 * @return 访问路径
	 * @author geYang
	 * @date 2018-05-22 17:57
	 */
	protected final String getUrl (String domain, String key) {
		return domain + "/" + key;
	}
	
	/**
	 * 文件上传
	 * @param file
	 * @param path
	 * @return 文件访问链接
	 * @throws IOException
	 * @author geYang
	 * @date 2018-05-22 10:09
	 */
	public abstract String upload(MultipartFile file, String path) throws IOException;
	/**
	 * 文件删除
	 * @param key 文件访问路径
	 * @author geYang
	 * @date 2018-05-22 10:13
	 */
	public abstract void delete(String url);
}

    5, 编写COS上传的实现:

package com.gy.fast.common.config.oss;

import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.region.Region;

import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileInputStream;
import java.io.IOException;

/**
 * 腾讯云存储
 * @author geYang
 * @date 2018-05-21
 */
public class QcloudUpload extends BaseUpload {
	
	private CloudConfig cloudConfig;
	// 加载配置文件
	public QcloudUpload(CloudConfig cloudConfig) {
		this.cloudConfig = cloudConfig;
	}
	
	/**
	 * 生成COS客户端
	 * @return
	 * @author geYang
	 * @date 2018-05-21 16:34
	 */
	private COSClient getCosClient() {
		System.err.println(cloudConfig);
		System.err.println(cloudConfig.getQcloudSecretId());
		System.err.println(cloudConfig.getQcloudSecretKey());
		// 1 初始化用户身份信息(secretId, secretKey)
		COSCredentials cred = new BasicCOSCredentials(cloudConfig.getQcloudSecretId(), cloudConfig.getQcloudSecretKey());
		// 2设置bucket的区域, COS地域的简称请参照  https://cloud.tencent.com/document/product/436/6224
		ClientConfig clientConfig = new ClientConfig(new Region(cloudConfig.getQcloudRegion()));
		// 3生成COS客户端
		COSClient cosclient = new COSClient(cred, clientConfig);
		return cosclient;
	}
	
	/**
	 * 文件上传
	 * @param path
	 * @param file
	 * @return 访问路径
	 * @throws IOException
	 * @author geYang
	 * @date 2018-05-21 16:33
	 */
	@Override
	public String upload(MultipartFile file, String path) throws IOException {
		FileInputStream fileInputStream = (FileInputStream) file.getInputStream();
		ObjectMetadata objectMetadata = new ObjectMetadata();
		// 设置输入流长度(需提前告知输入流的长度,否则可能导致OOM)
		objectMetadata.setContentLength(file.getSize());
		String key = getKey(file, path);
		COSClient cosClient = getCosClient();
		PutObjectResult putObjectResult = cosClient.putObject(cloudConfig.getQcloudBucketName(), key, fileInputStream, objectMetadata);
		String etag = putObjectResult.getETag();
		cosClient.shutdown();
		if (StringUtils.isBlank(etag)) {
			return null;
		}
		// 访问路径
		return getUrl(cloudConfig.getQcloudDomain(), key);
	}

	/**
	 * 删除文件
	 * @param key
	 * @author geYang
	 * @date 2018-05-21 16:33
	 */
	@Override
	public void delete(String url) {
		String bucketName = cloudConfig.getQcloudBucketName();
		// 截取域名之后的文件名
		String key = url.substring(bucketName.length()+1);
		COSClient cosClient = getCosClient();
		// 进行删除
		cosClient.deleteObject(cloudConfig.getQcloudBucketName(), key);
		cosClient.shutdown();
	}
	
}

      6, 编写工厂进行实实例化上传类, 通过调用该工厂,来完成上传任务.

package com.gy.fast.common.config.oss;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 上传文件工厂
 * @author geYang
 * @date 2018-05-22
 */
@Component
public final class UploadFactory {
	/**
	 * 云配置信息
	 */
	@Autowired
	private CloudConfig cloudConfig;

	/**
	 * 实例化上传类
	 * @return
	 * @author geYang
	 * @date 2018-05-22 18:20
	 */
	public BaseUpload build() {
		int type = cloudConfig.getType();
		if (type == 1) {
			System.out.println("腾讯云存储");
			return new QcloudUpload(cloudConfig);
		}
		if (type == 2) {
			System.out.println("阿里云存储");
			return new BaiduyunUpload(cloudConfig);
		}
		if (type == 3) {
			System.out.println("七牛云存储");
			return new QiiuUpload(cloudConfig);
		} else {
			System.out.println("本地存储");
			return new MyUpload();
		}
	}
	
}

   7, 调用应用: 

package com.gy.fast.module.sys.controller;

import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import com.gy.fast.common.config.oss.UploadFactory;
import com.gy.fast.common.util.R;

/**
 * 文件上传
 * @author geYang
 * @date 2018-05-21
 */
@RestController
public class SysOssController {
    @Autowired
	protected UploadFactory uploadFactory;

	/**
	 * 上传文件
	 */
	@PostMapping("/upload")
	public R upload(@RequestParam("file") MultipartFile file) throws Exception {
		System.out.println(getUser());
		if (file.isEmpty()) {
			throw new SysException("上传文件不能为空");
		}
		//上传文件
		String url = uploadFactory.build().upload(file, "");
		System.out.println(url);
	
		return R.ok().put("url", url);
	}
}

到此, 关于工厂模式的演示基本完成了, 集成其他云存储配置的话只需要实现BaseUpload就好.

猜你喜欢

转载自my.oschina.net/u/3681868/blog/1816895