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就好.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章