oss文件系統路由方案實現

一、需求背景
1、oss文件系統是阿里的存儲文件的服務。
2、以往一個項目中文件可能存放在多個oss上,也就會有多份配置,造成冗餘和維護困難。
3、爲了oss配置能夠統一維護,可以將其存放到數據庫表中,調用時根據指定的token加載對應的配置進行操作。
4、爲了高效的工作,在第一次調用時將配置加載到內存中。爲了在數據庫更新時及時更新內存,使用觀察者進行設置。
二、概要設計
1、類結構
這裏寫圖片描述
2、數據庫er圖(關鍵字段)
這裏寫圖片描述
三、詳細設計
1、OssServicce*****Impl類

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import common.utils.AES;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.Bucket;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;

/**
 * oss 文件創建,刪除,讀取,訪問url 的實現類
 *
 * 
 */
public class OssService****Impl implements OssService*** {

    private Logger logger         = LoggerFactory.getLogger(OssServiceFacadeImpl.class);

    // 默認的BucketName
    private String                     defaultBucketName;

    // 配置的bucket的文件夾名
    private String                     defaultFilePath;

    // 是否encode true, false
    private boolean                    encode         = false;

    // 採用的是AES加密
    private String                     encodeKey;

    // oss下載的url
    private String                     ossFileHttpUrl;

    // oss的key
    private String                     ossKey;

    // oss的上secret
    private String                     ossSecret;

    // 上傳單個文件最大大小,默認200M
    private long                       fileMaxSize    = 200 * 1024 * 1024L;

    // oss的endpoint
    private String                     endpoint;

    protected static Map<String, String> contentType    = new HashMap<String, String>();

    // 上傳文件的時候是否默認需要先檢查bucket是否配置了,默認要檢查,上線前建議先去oss上新建bucket,採用不檢查bucket效率更好
    private boolean                    checkBucket    = true;

    private boolean                    formatRequired = false;

    // 是否encode true, false
    private boolean                    cacheControl   = false;

    // 採用的是AES加密
    private String                     cacheControlRule;

    static {
        contentType.put("doc", "application/msword");
        contentType.put("docx", "application/msword");
        contentType.put("ppt", "application/x-ppt");
        contentType.put("pptx", "application/x-ppt");
        contentType.put("pdf", "application/pdf");
        contentType.put("xls", "text/xml");
        contentType.put("xlsx", "text/xml");
        contentType.put("html", "text/html");
    }

    /**
     * 上傳文件的時候生成oss的文件key,唯一標示一個文件
     *
     * @return
     */
    private String generateFileId() {
        return UUID.randomUUID().toString();
    }

    /**
     * 獲取oss client
     *
     * @return
     * @throws Exception
     */
    protected OSSClient getOssClient() throws Exception {
        if (StringUtils.isBlank(ossKey) || StringUtils.isBlank(ossSecret)) {
            logger.error("oss key and oss secret must be configed for OssFileHandleServiceImpl class.");
            throw new Exception("oss key and oss secret must be configed for OssFileHandleServiceImpl class.");
        }
        try {
            OSSClient client = null;
            if (StringUtils.isBlank(endpoint)) {
                client = new OSSClient(ossKey, ossSecret);
            } else {
                client = new OSSClient(endpoint, ossKey, ossSecret);
            }
            return client;
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw e;
        }
    }

    /**
     * 獲取 bucket
     *
     * @param client
     * @param bucketName
     * @return
     * @throws Exception
     */
    protected Bucket createBucket(OSSClient client, String bucketName) throws Exception {
        if (client == null) {
            logger.error("oss key and oss secret error.");
            throw new Exception("oss key and oss secret error.");
        }
        boolean exists = client.doesBucketExist(bucketName);
        if (exists) {
            List<Bucket> buckets = client.listBuckets();
            // 遍歷Bucket
            for (Bucket bucket : buckets) {
                if (bucketName.equals(bucket.getName())) {
                    return bucket;
                }
            }
            return null;
        } else {
            Bucket bucket = client.createBucket(bucketName);
            return bucket;
        }
    }

    /**
     * use default bucketName
     */
    @Override
    public HashMap<String, Object> createFile(String fileName, String suffix, InputStream input, long fileSize)
                                                                                                               throws Exception {
        return createFile(defaultBucketName, fileName, suffix, input, fileSize);
    }

    @Override
    public HashMap<String, Object> createFile(String ossFileId,String bucketName, String filePath, String fileName, String suffix, InputStream input,
                                              long fileSize) throws Exception {
        InputStream encodeIs = null;
        try {
            if (StringUtils.isBlank(bucketName)) {
                logger.error("bucketName must be configed for OssFileHandleServiceImpl class.");
                throw new Exception("bucketName must be configed for OssFileHandleServiceImpl class.");
            }
            if (fileSize > fileMaxSize) {
                logger.error("file Size must be smaller than max file size {}.", fileMaxSize);
                throw new Exception("file Size must be smaller than max file size " + fileMaxSize);
            }
            // 獲取oss client
            OSSClient client = getOssClient();

            // 如果需要檢查bucket則調用此代碼,一般情況下都不需要檢查,直接在OSS控制檯又管理員新建bucket
            if (checkBucket) {
                // 判斷bucket是否存在,不存在則創建bucket
                boolean exists = client.doesBucketExist(bucketName);
                // 如果不存在則創建bucket
                if (!exists) {
                    Bucket bucket = createBucket(client, bucketName);
                    if (bucket == null) {
                        logger.error("Create bucket failed, bucket name is {}", bucketName);
                        throw new Exception("Create bucket failed, bucket name is " + bucketName);
                    }
                }
            }

            // 獲取指定文件的輸入流
            // 創建上傳Object的Metadata
            ObjectMetadata meta = new ObjectMetadata();
            String format = "";
            // 如果對文件格式有要求,上傳文件時在HEADER中加入格式信息
            if (formatRequired) {
                int index = fileName.lastIndexOf(".");
                if (index != -1) {
                    format = fileName.substring(index + 1, fileName.length());
                    format = format.toLowerCase();
                    if (contentType.containsKey(format)) {
                        meta.setContentType(contentType.get(format));
                    }
                }
            } else {
                meta.addUserMetadata("filename", fileName);
                meta.addUserMetadata("filesuffix", suffix);
                meta.setHeader("x-oss-server-side-encryption", "AES256");
            }

            //對文件設置緩存策略
            if (cacheControl&&!StringUtils.isBlank(cacheControlRule)) {
                meta.setCacheControl(cacheControlRule);
            }


            if(StringUtils.isBlank(ossFileId)){
             // 文件的key, 用uuid生成
                ossFileId = "";
                if (formatRequired) {
                    ossFileId = generateFileId() + "." + format;
                } else {
                    ossFileId = generateFileId();
                }
            }else{
                //使用用戶自定義的文件key
                if (formatRequired) {
                    ossFileId = ossFileId + "." + format;
                }
            }

            if (!encode) {
                encodeIs = input;
                // 必須設置ContentLength
                meta.setContentLength(fileSize);
            } else {
                encodeIs = handleEncodeStream(input);
                // 必須設置ContentLength
                meta.setContentLength(getInputLength(fileSize));
            }

            // 如果文件放在defaultFilePath這個文件夾下面,則這樣處理
            String resourceId = ossFileId;
            if(!StringUtils.isBlank(filePath)){
                resourceId = filePath + "/" + resourceId;
            }
            else{
                if (!StringUtils.isBlank(defaultFilePath)) {
                    resourceId = defaultFilePath + "/" + resourceId;
                }
            }

            // 上傳Object.
            PutObjectResult result = client.putObject(bucketName, resourceId, encodeIs, meta);
            if (result != null && !StringUtils.isBlank(result.getETag())) {
                HashMap<String, Object> resultMap = new HashMap<String, Object>();
                resultMap.put("size", meta.getContentLength());
                resultMap.put("ossFileId", ossFileId);
                return resultMap;
            }
            logger.error("Create file error, filename is {}, and file suffix is {}", new Object[] { fileName, suffix });
            throw new Exception("Create file error, filename is " + fileName + ", and file suffix is " + suffix);
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (Exception e) {
                    logger.error(e.getMessage());
                }
            }
            if (encodeIs != null) {
                try {
                    encodeIs.close();
                } catch (Exception e) {
                    logger.error(e.getMessage());
                }
            }
        }
    }

    /**
     * 獲得加密後流的長度,算法是 (原流大小/16)*16+16
     *
     * @param fileSize
     * @return
     * @throws Exception
     */
    protected long getInputLength(long fileSize) throws Exception {
        return (fileSize / 16) * 16 + 16;
    }

    /**
     * 加密InputStream,如果encode=true就加密,否則不加密
     *
     * @param input
     * @return
     * @throws Exception
     */
    protected InputStream handleEncodeStream(InputStream input) throws Exception {
        if (encode) {
            if (StringUtils.isBlank(encodeKey)) {
                throw new Exception(
                                    "encodeKey must be configed for OssFileHandleServiceImpl class if you config true for encode property.");
            }
            return AES.encodeStream(input, encodeKey);
        }
        return input;
    }

    /**
     * 解密InputStream,如果encode=true就加密,否則不解密
     *
     * @param input
     * @return
     * @throws Exception
     */
    protected InputStream handleDecodeStream(InputStream input) throws Exception {
        if (encode) {
            if (StringUtils.isBlank(encodeKey)) {
                throw new Exception(
                                    "encodeKey must be configed for OssFileHandleServiceImpl class if you config true for encode property.");
            }
            return AES.decodeStream(input, encodeKey);
        }
        return input;
    }

    @Override
    public boolean delete(String ossFileId) throws Exception {
        // 如果文件放在defaultFilePath這個文件夾下面,則這樣處理
        if (!StringUtils.isBlank(defaultFilePath)) {
            ossFileId = defaultFilePath + "/" + ossFileId;
        }
        return delete(defaultBucketName, ossFileId);
    }

    @Override
    public boolean delete(String bucketName, String ossFileId) throws Exception {
        // 獲取oss client
        OSSClient client = getOssClient();
        client.deleteObject(bucketName, ossFileId);
        return true;
    }

    @Override
    public boolean delete(String filePath, String ossFileId, String format) throws Exception {
        // 獲取oss client
        OSSClient client = getOssClient();
        if (StringUtils.isBlank(filePath)) {
            logger.error("刪除OSS附件,filePath不能爲空");
            throw new Exception("filePath不能爲空");
        }
        if (StringUtils.isBlank(format)) {
            ossFileId = filePath+"/"+ossFileId;
        }
        else{
            ossFileId = filePath+"/"+ossFileId+"."+format;
        }
        client.deleteObject(defaultBucketName, ossFileId);
        return true;
    }

    @Override
    public InputStream readFile(String ossFileId) throws Exception {
        // 如果文件放在defaultFilePath這個文件夾下面,則這樣處理
        if (!StringUtils.isBlank(defaultFilePath)) {
            ossFileId = defaultFilePath + "/" + ossFileId;
        }
        return readFile(defaultBucketName, ossFileId);
    }

    @Override
    public InputStream readFile(String bucketName, String ossFileId) throws Exception {
        if (StringUtils.isBlank(bucketName)) {
            logger.error("bucketName must be configed for OssFileHandleServiceImpl class.");
            throw new Exception("bucketName must be configed for OssFileHandleServiceImpl class.");
        }
        // 獲取oss client
        OSSClient client = getOssClient();
        InputStream objectContent = null;

        // 獲取Object,返回結果爲OSSObject對象
        OSSObject object = client.getObject(bucketName, ossFileId);

        // 獲取Object的輸入流
        objectContent = object.getObjectContent();

        if (encode) {
            return handleDecodeStream(objectContent);
        } else {
            return objectContent;
        }
    }

    @Override
    public String getUrl(String ossFileId) {
        if (StringUtils.isBlank(this.ossFileHttpUrl)) {
            return "";
        }
        return this.ossFileHttpUrl + "?resourceId=" + ossFileId;
    }

    @Override
    public String getUrl(String bucketName, String ossFileId) {
        if (StringUtils.isBlank(this.ossFileHttpUrl)) {
            return "";
        }
        return this.ossFileHttpUrl + "?resourceId=" + ossFileId + "&bucketName=" + bucketName;
    }

    @Override
    public ObjectMetadata getFileMetadata(String ossFileId) throws Exception {
        if (!StringUtils.isBlank(defaultFilePath)) {
            ossFileId = defaultFilePath + "/" + ossFileId;
        }
        return getFileMetadata(defaultBucketName, ossFileId);
    }

    @Override
    public ObjectMetadata getFileMetadata(String bucketName, String ossFileId) throws Exception {
        if (StringUtils.isBlank(bucketName)) {
            logger.error("bucketName must be configed for OssFileHandleServiceImpl class.");
            throw new Exception("bucketName must be configed for OssFileHandleServiceImpl class.");
        }
        // 獲取oss client
        OSSClient client = getOssClient();

        // 獲取Object,返回結果爲OSSObject對象
        OSSObject object = client.getObject(bucketName, ossFileId);
        // 返回文件屬性對象
        return object.getObjectMetadata();
    }

    public String getEndpoint() {
        return endpoint;
    }

    public void setEndpoint(String endpoint) {
        this.endpoint = endpoint;
    }

    public boolean isCheckBucket() {
        return checkBucket;
    }

    public void setCheckBucket(boolean checkBucket) {
        this.checkBucket = checkBucket;
    }


    @Override
    public HashMap<String, Object> createFile(String bucketName, String fileName, String suffix,
                                              InputStream input, long fileSize) throws Exception {

        return this.createFile(null,bucketName, null, fileName, suffix, input, fileSize);
    }


    @Override
    public HashMap<String, Object> createFileByUserDefinedOssFileIdAndFilePath(String ossFileId,String filePath, String fileName, String suffix,
                                                                   InputStream input, long fileSize) throws Exception {
        return this.createFile(ossFileId,defaultBucketName, filePath, fileName, suffix, input, fileSize);
    }

    @Override
    public long getFileSize(String ossFileId) {
        long size = 0;
        InputStream inputStream = null;
        try {
            inputStream = readFile(ossFileId);
            byte[] buf = new byte[1024];
            long len;
            while ((len = inputStream.read(buf)) != -1) {
                size += len;
            }
        } catch (Exception e) {
            return 0;
        } finally {
            IOUtils.closeQuietly(inputStream);
        }
        return size;
    }

    public boolean isFormatRequired() {
        return formatRequired;
    }


    public void setFormatRequired(boolean formatRequired) {
        this.formatRequired = formatRequired;
    }


    public boolean isCacheControl() {
        return cacheControl;
    }


    public void setCacheControl(boolean cacheControl) {
        this.cacheControl = cacheControl;
    }


    public String getCacheControlRule() {
        return cacheControlRule;
    }


    public void setCacheControlRule(String cacheControlRule) {
        this.cacheControlRule = cacheControlRule;
    }

2、Configurable****Handler類

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.Bucket;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;

/**
 * 封裝OSS路由
 * 注意:當前類暫不考慮清理緩存操作,也就是說清理緩存需要重啓服務
 * @author wb-zcf274530
 *
 */
@Component
public class Configurable*****Handler{

    private Logger logger         = LoggerFactory.getLogger(ConfigurableOssHandler.class);

    //業務代碼&配置
    private static final Map<String,OssConfigDTO> ossConfigMap = new ConcurrentHashMap<String,OssConfigDTO>();

    //業務代碼&連接
    //private static final Map<String,OSSClient> ossClientMap = new ConcurrentHashMap<String,OSSClient>();

    //服務處理對象
    private static final Map<String,OssServiceExtend> ossServiceMap = new ConcurrentHashMap<String,OssServiceExtend>();

    @Autowired
    private OssConfigService ossConfigService;  

    /**
     * 從數據庫獲取配置信息
     * @param businessCode
     * @return 失敗返回null
     */
    private OssConfigDTO getOssConfigFromDB(String businessCode) {
        OssConfigDTO  ossConfig = null;
        try {
            validateNull(businessCode,null);
             ActionResult<OssConfigDTO> result = ossConfigService.getOssConfigByBusinessCode(businessCode);
             if(result.isSuccess()&&null!=result.getContent()) {
                 ossConfig = result.getContent();
             }
        }catch(Exception e) {
            throw new AntisPaasException("get ossConfig from db fail,with businessCode:"+businessCode,e);
        }
        return ossConfig;
    }

    /**
     * 獲取Oss配置信息
     * @param businessCode
     * @return
     */
    public OssConfigDTO getOssConfig(String businessCode){
        try {
            validateNull(businessCode,null);
            OssConfigDTO ossConfig = null;
            if(ossConfigMap.containsKey(businessCode)){
                ossConfig = ossConfigMap.get(businessCode);
                return ossConfig;
            }else{
                ossConfig = getOssConfigFromDB(businessCode);
                if(null==ossConfig){
                    throw new AntisPaasException("can not find record,with businessCode:"+businessCode);
                }else {
                    ossConfigMap.put(businessCode,ossConfig);
                    return ossConfig;
                }
            }
        }catch(AntisPaasException e){
            logger.warn("get Config by businessCode fail,with businessCode:"+businessCode,e);
            throw new AntisPaasException(e.getCode(),e.getMessage(),e);
        }catch(Exception e) {
            logger.error("get Config by businessCode fail,with businessCode:"+businessCode,e);
            throw new AntisPaasException(AntisPaasErrorCode.error_0004.getErrorCode(),"獲取oss配置失敗!",e);
        }
    }


    private OssServiceExtend getOssService(String businessCode) {
        if(ossServiceMap.containsKey(businessCode)) {
            return ossServiceMap.get(businessCode);
        }else {
            ossServiceMap.put(businessCode, new OssServiceExtend(businessCode));
        }
        return ossServiceMap.get(businessCode);
    }

    /**
     * 
     * @Description:OSS操作服務
     * @Author wb-zcf274530 2017/12/15 20:15
     */
    private class OssServiceExtend extends EnhanceOssFacadeImpl{

        //默認OSS上傳最大文件,200M
        public static final long MAX_FILE_SIZE = 200 * 1024 * 1024L;

        //業務代碼&連接
        public final ThreadLocal<OSSClient> ossClientMap = new ThreadLocal<OSSClient>();


        private String businessCode;

        public OssServiceExtend(String businessCode) {
            init(businessCode);
            this.businessCode = businessCode;
        }

        private void init(String businessCode){
            validateNull(businessCode,null);
            OssConfigDTO ossConfig = null;
            if(ossConfigMap.containsKey(businessCode)){
                ossConfig = ossConfigMap.get(businessCode);
            }else {
                ossConfig = getOssConfigFromDB(businessCode);
                if (null == ossConfig) {
                    throw new AntisPaasException("records do not exist,with businessCode:"+businessCode);
                } else {
                    ossConfigMap.put(businessCode, ossConfig);
                }
            }
            initParentAttribute(ossConfig);
        }

        /**
         * 獲取oss client
         *
         * @return
         * @throws Exception
         */
        @Override
        protected OSSClient getOssClient() throws Exception {
            if (StringUtils.isBlank(this.getOssKey()) || StringUtils.isBlank(this.getOssSecret())) {
                throw new AntisPaasException("oss key and oss secret must be configed for OssFileHandleServiceImpl class.");
            }
            try {
                if(ossClientMap.get()!=null) {
                    return ossClientMap.get();
                }
                OSSClient client = null;
                if (StringUtils.isBlank(this.getEndpoint())) {
                    client = new OSSClient(this.getOssKey(), this.getOssSecret());
                } else {
                    client = new OSSClient(this.getEndpoint(), this.getOssKey(), this.getOssSecret());
                }
                if(null==client) {
                    throw new AntisPaasException("init client fail,with businessCode :"+businessCode);
                }
                ossClientMap.set(client);
                return client;
            } catch (Exception e) {
                logger.error("get OssClient fail,with this:"+JSONObject.toJSONString(this),e);
                throw new AntisPaasException("get OssClient fail,with this:"+JSONObject.toJSONString(this),e);
            }
        }


        public HashMap<String, Object> createFile(String bucketName, String fileName, String suffix, InputStream input, long fileSize) throws Exception {
            return this.createFile(null,bucketName, null, fileName, suffix, input, fileSize);
        }


        public HashMap<String, Object> createFileByUserDefinedOssFileIdAndFilePath(String ossFileId, String filePath, String fileName, String suffix, InputStream input, long fileSize) throws Exception {
            return this.createFile(ossFileId,this.getDefaultBucketName(), filePath, fileName, suffix, input, fileSize);
        }


        public HashMap<String, Object> createFile(String ossFileId,String bucketName, String filePath, String fileName, String suffix, InputStream input,
                long fileSize) throws Exception {
            InputStream encodeIs = null;
            try {
                validateNull(bucketName,"域名不能爲空!");
                validateTrue(fileSize > this.getFileMaxSize(),"文件大小超過限制,默認200M,當前: " + this.getFileMaxSize());
                validateTrue(useRealName&&StringUtils.isBlank(fileName),"文件名不能爲空!");
                // 獲取oss client
                OSSClient client = getOssClient();

                // 如果需要檢查bucket則調用此代碼,一般情況下都不需要檢查,直接在OSS控制檯又管理員新建bucket
                checkAndaddBucket(this.isCheckBucket(),client,bucketName);

                // 獲取指定文件的輸入流
                // 創建上傳Object的Metadata
                ObjectMetadata meta = new ObjectMetadata();
                String format = "";
                // 如果對文件格式有要求,上傳文件時在HEADER中加入格式信息
                if (this.isFormatRequired()) {
                    int index = fileName.lastIndexOf(".");
                    if (index != -1) {
                        format = fileName.substring(index + 1, fileName.length());
                        format = format.toLowerCase();
                        if (contentType.containsKey(format)) {
                            meta.setContentType(contentType.get(format));
                        }
                    }
                } else {
                    meta.addUserMetadata("filename", fileName);
                    meta.addUserMetadata("filesuffix", suffix);
                    meta.setHeader("x-oss-server-side-encryption", "AES256");
                }

                //對文件設置緩存策略
                if (this.isCacheControl()&&!StringUtils.isBlank(this.getCacheControlRule())) {
                    meta.setCacheControl(this.getCacheControlRule());
                }

                //設置文件名策略
                if(getUseRealName()){
                   ossFileId = fileName;
                }else if(StringUtils.isBlank(ossFileId)){
                    // 文件的key, 用uuid生成
                    ossFileId = "";
                    if (this.isFormatRequired()) {
                        ossFileId = UUID.randomUUID().toString() + "." + format;
                    } else {
                        ossFileId = UUID.randomUUID().toString();
                    }
                }else{
                    //使用用戶自定義的文件key
                    if (this.isFormatRequired()) {
                        ossFileId = ossFileId + "." + format;
                    }
                }

                //設置加密
                if (!this.isEncode()) {
                    encodeIs = input;
                    // 必須設置ContentLength
                    meta.setContentLength(fileSize);
                } else {
                    encodeIs = handleEncodeStream(input);
                    // 必須設置ContentLength
                    meta.setContentLength(getInputLength(fileSize));
                }

                // 如果文件放在defaultFilePath這個文件夾下面,則這樣處理
                String resourceId = ossFileId;
                if(!StringUtils.isBlank(filePath)){
                    resourceId = filePath + "/" + resourceId;
                }else{
                    if (!StringUtils.isBlank(this.getDefaultFilePath())) {
                        resourceId = this.getDefaultFilePath() + "/" + resourceId;
                    }
                }

                // 上傳Object.
                PutObjectResult result = client.putObject(bucketName, resourceId, encodeIs, meta);
                if (result != null && !StringUtils.isBlank(result.getETag())) {
                    HashMap<String, Object> resultMap = new HashMap<String, Object>();
                    resultMap.put("size", meta.getContentLength());
                    resultMap.put("ossFileId", ossFileId);
                    return resultMap;
                }
                throw new AntisPaasException("Create file to oss fail!");
            }catch(Exception e) {
                cleanCache(this.businessCode);
                logger.error("Create file error,with ossFileId:{},bucketName:{},filePath:{},fileName:{},suffix:{},fileSize:{}",ossFileId,bucketName,filePath,fileName,suffix,fileSize,e);
                throw e;
            } finally {
                if (input != null) {
                    try {
                        input.close();
                    } catch (Exception e) {
                        logger.error(e.getMessage(),e);
                    }
                }
                if (encodeIs != null) {
                    try {
                        encodeIs.close();
                    } catch (Exception e) {
                        logger.error(e.getMessage(),e);
                    }
                }
            }
        }


        public HashMap<String, Object> createFile(String fileName, String suffix, InputStream input, long fileSize)
                                                                                                                   throws Exception {
            return createFile(this.getDefaultBucketName(), fileName, suffix, input, fileSize);
        }

        @Override
        public boolean delete(String bucketName, String ossFileId) throws Exception {
            // 構造oss Client
            OSSClient client = getOssClient();
            client.deleteObject(bucketName, ossFileId);
            return true;
        }

        @Override
        public InputStream readFile(String bucketName, String ossFileId) throws Exception {
            if (StringUtils.isBlank(bucketName)) {
                logger.warn("bucketName must be configed for OssFileHandleServiceImpl class.");
                throw new AntisPaasException("bucketName must be configed for OssFileHandleServiceImpl class.");
            }
            // 構造oss client
            OSSClient client = getOssClient();
            InputStream objectContent = null;

            // 獲取對象
            OSSObject object = client.getObject(bucketName, ossFileId);

            // 返回
            objectContent = object.getObjectContent();

            if (this.isEncode()) {
                return handleDecodeStream(objectContent);
            } else {
                return objectContent;
            }
        }

        @Override
        public ObjectMetadata getFileMetadata(String bucketName, String ossFileId) throws Exception {
            if (StringUtils.isBlank(bucketName)) {
                logger.warn("bucketName must be configed for OssFileHandleServiceImpl class.");
                throw new AntisPaasException("bucketName must be configed for OssFileHandleServiceImpl class.");
            }
            // 構造oss client
            OSSClient client = getOssClient();

            // 獲取對象
            OSSObject object = client.getObject(bucketName, ossFileId);
            // 返回
            return object.getObjectMetadata();
        }

        private void checkAndaddBucket(boolean isNeed,OSSClient client,String bucketName) throws Exception {
            if(isNeed) {
                // 判斷bucket是否存在,不存在則創建bucket
                boolean exists = client.doesBucketExist(bucketName);
                // 如果不存在則創建bucket
                if (!exists) {
                    Bucket bucket = createBucket(client, bucketName);
                    if (bucket == null) {
                        throw new AntisPaasException("Create bucket failed, with bucket name is " + bucketName);
                    }
                }
            }
        }

        /**
         * 獲取 bucket
         *
         * @param client
         * @param bucketName
         * @return
         * @throws Exception
         */
        protected Bucket createBucket(OSSClient client, String bucketName) throws Exception {
            if (client == null) {
                logger.warn("oss key and oss secret error.");
                throw new AntisPaasException("oss key and oss secret error.");
            }
            boolean exists = client.doesBucketExist(bucketName);
            if (exists) {
                List<Bucket> buckets = client.listBuckets();
                // 遍歷Bucket
                for (Bucket bucket : buckets) {
                    if (bucketName.equals(bucket.getName())) {
                        return bucket;
                    }
                }
                return null;
            } else {
                Bucket bucket = client.createBucket(bucketName);
                return bucket;
            }
        }

        /**
         * 初始化父類屬性
         */
        private void initParentAttribute(OssConfigDTO config){
            this.setDefaultBucketName(config.getOssBucket());
            this.setDefaultFilePath(config.getDefaultPath());
            this.setEncodeKey(config.getEncryptKey());
            this.setEndpoint(config.getOssEndpoint());
            this.setOssFileHttpUrl(config.getFileHttpUrl());
            this.setOssKey(config.getOssKey());
            this.setOssSecret(config.getOssSecret());
            this.setCacheControlRule(config.getCacheControlRule());
            this.setCheckBucket(config.getCheckBucket());
            this.setEncode(config.getEncode());
            this.setFormatRequired(config.getFormatRequired());
            this.setUseRealName(config.getUseRealName());
            this.setCacheControl(config.getCacheControl());
            //默認200M
            if(null==config.getFileMaxSize()) {
                this.setFileMaxSize(MAX_FILE_SIZE);
            }else {
                this.setFileMaxSize(config.getFileMaxSize());
            }

        }

    }

    /**
     * 創建文件流對象
     * @param businessCode
     * @param fileName
     * @param suffix
     * @param input
     * @param fileSize
     * @return
     * @throws Exception
     */
    public HashMap<String, Object> createFile(String businessCode, String fileName, String suffix, InputStream input, long fileSize) throws Exception{
        try {
            validateNull(businessCode,null);
            validateNull(input,null);
            return getOssService(businessCode).createFile(fileName, suffix, input, fileSize);
        }catch(AntisPaasException e) {
            logger.warn("createFile fail,with businessCode:{},fileName:{}, suffix:{},fileSize:{}",businessCode,fileName,suffix,fileSize,e);
            throw new AntisPaasException(e.getCode(),e.getMessage(),e);
        }catch(Exception e) {
            logger.error("createFile fail,with businessCode:{},fileName:{}, suffix:{},fileSize:{}",businessCode,fileName,suffix,fileSize,e);
            throw new AntisPaasException(AntisPaasErrorCode.error_0004.getErrorCode(),"創建流文件失敗!",e);
        }
    }

    /**
     * 創建文件流對對象
     * @param businessCode
     * @param bucketName
     * @param fileName
     * @param suffix
     * @param input
     * @param fileSize
     * @return
     * @throws Exception
     */
    public HashMap<String, Object> createFile(String businessCode, String bucketName, String fileName,
            String suffix, InputStream input, long fileSize) throws Exception{
        try {
            validateNull(businessCode,null);
            validateNull(input,null);
            return getOssService(businessCode).createFile(bucketName, fileName, suffix, input, fileSize);
        }catch(AntisPaasException e) {
            logger.warn("createFile fail,with businessCode:{},bucketName:{}, fileName:{}, suffix:{},fileSize:{}",businessCode,bucketName,fileName,suffix,fileSize,e);
            throw new AntisPaasException(e.getCode(),e.getMessage(),e);
        }catch(Exception e) {
            logger.error("createFile fail,with businessCode:{},bucketName:{}, fileName:{}, suffix:{},fileSize:{}",businessCode,bucketName,fileName,suffix,fileSize,e);
            throw new AntisPaasException(AntisPaasErrorCode.error_0004.getErrorCode(),"獲取文件流對象失敗!",e);
        }
    }



    /**
     * 創建文件流對象
     * @param businessCode
     * @param ossFileId
     * @param filePath
     * @param fileName
     * @param suffix
     * @param input
     * @param fileSize
     * @return
     * @throws Exception
     */
    public HashMap<String, Object> createFileByUserDefinedOssFileIdAndFilePath(String businessCode,
            String ossFileId, String filePath, String fileName, String suffix, InputStream input, long fileSize) throws Exception{
        try {
            validateNull(businessCode,null);
            validateNull(input,null);
            return getOssService(businessCode).createFileByUserDefinedOssFileIdAndFilePath(ossFileId, filePath, fileName, suffix, input, fileSize);
        }catch(AntisPaasException e) {
            logger.warn("createFile By UserDefined OssFileId And FilePath fail,with businessCode:{},ossFileId:{}, filePath:{}, fileName:{}, suffix:{},fileSize:{}",businessCode,ossFileId, filePath, fileName, suffix,fileSize,e);
            throw new AntisPaasException(e.getCode(),e.getMessage(),e);
        }catch(Exception e) {
            logger.error("createFile By UserDefined OssFileId And FilePath fail,with businessCode:{},ossFileId:{}, filePath:{}, fileName:{}, suffix:{},fileSize:{}",businessCode,ossFileId, filePath, fileName, suffix,fileSize,e);
            throw new AntisPaasException(AntisPaasErrorCode.error_0004.getErrorCode(),"獲取文件流對象失敗!",e);
        }
    }



    /**
     * 創建文件流對象
     * @param businessCode
     * @param ossFileId
     * @param bucketName
     * @param filePath
     * @param fileName
     * @param suffix
     * @param input
     * @param fileSize
     * @return
     * @throws Exception
     */
    public HashMap<String, Object> createFile(String businessCode, String ossFileId, String bucketName,
            String filePath, String fileName, String suffix, InputStream input, long fileSize) throws Exception {
        try {
            validateNull(businessCode,null);
            validateNull(input,null);
            return getOssService(businessCode).createFile(ossFileId, bucketName, filePath, fileName, suffix, input, fileSize);
        }catch(AntisPaasException e) {
            logger.warn("createFile fail,with businessCode:{},ossFileId:{}, bucketName:{},filePath:{}, fileName:{}, suffix:{},fileSize:{}",businessCode,ossFileId,bucketName, filePath, fileName, suffix,fileSize,e);
            throw new AntisPaasException(e.getCode(),e.getMessage(),e);
        }catch(Exception e) {
            logger.error("createFile fail,with businessCode:{},ossFileId:{}, bucketName:{},filePath:{}, fileName:{}, suffix:{},fileSize:{}",businessCode,ossFileId,bucketName, filePath, fileName, suffix,fileSize,e);
            throw new AntisPaasException(AntisPaasErrorCode.error_0004.getErrorCode(),"創建文件流對象失敗!",e);
        }
    }

    /**
     * 根據指定域名&資源Id獲取文件流對象
     * @param businessCode
     * @param bucketName
     * @param ossFileId
     * @return
     * @throws Exception
     */
    public InputStream readFile(String businessCode, String bucketName, String ossFileId) throws Exception{
        try {
            validateNull(businessCode,null);
            validateNull(ossFileId,null);
            validateNull(bucketName,null);
            return getOssService(businessCode).readFile(bucketName,ossFileId);
        }catch(AntisPaasException e) {
            logger.warn("readFile fail,with businessCode:{},bucketName:{}, ossFileId:{}",businessCode,bucketName,ossFileId,e);
            throw new AntisPaasException(e.getCode(),e.getMessage(),e);
        }catch(Exception e) {
            logger.error("readFile fail,with businessCode:{},bucketName:{}, ossFileId:{}",businessCode,bucketName,ossFileId,e);
            throw new AntisPaasException(AntisPaasErrorCode.error_0004.getErrorCode(),"獲取文件流對象失敗!",e);
        }
    }

    /**
     * 根據資源Id獲取文件流對象
     * @param businessCode
     * @param ossFileId
     * @return
     * @throws Exception
     */
    public InputStream readFile(String businessCode, String ossFileId) throws Exception{
        try {
            validateNull(businessCode,null);
            validateNull(ossFileId,null);
            return getOssService(businessCode).readFile(ossFileId);
        }catch(AntisPaasException e) {
            logger.warn("readFile fail,with businessCode:{},ossFileId:{}",businessCode,ossFileId,e);
            throw new AntisPaasException(e.getCode(),e.getMessage(),e);
        }catch(Exception e) {
            logger.error("readFile fail,with businessCode:{},ossFileId:{}",businessCode,ossFileId,e);
            throw new AntisPaasException(AntisPaasErrorCode.error_0004.getErrorCode(),"獲取文件流對象失敗!",e);
        }
    }

    /**
     * 根據資源Id刪除文件
     * @param businessCode
     * @param ossFileId
     * @return
     * @throws Exception
     */
    public boolean delete(String businessCode, String ossFileId) throws Exception{
        try {
            validateNull(businessCode,null);
            validateNull(ossFileId,null);
            return getOssService(businessCode).delete(ossFileId);
        }catch(AntisPaasException e) {
            logger.warn("delete fail,with businessCode:{},ossFileId:{}",businessCode,ossFileId,e);
            throw new AntisPaasException(e.getCode(),e.getMessage(),e);
        }catch(Exception e) {
            logger.error("delete fail,with businessCode:{},ossFileId:{}",businessCode,ossFileId,e);
            throw new AntisPaasException(AntisPaasErrorCode.error_0004.getErrorCode(),"刪除文件失敗!",e);
        }
    }

    /**
     * 根據指定域名&資源Id刪除文件
     * @param businessCode
     * @param bucketName
     * @param ossFileId
     * @return
     * @throws Exception
     */
    public boolean delete(String businessCode, String bucketName, String ossFileId) throws Exception{
        try {
            validateNull(businessCode,null);
            validateNull(ossFileId,null);
            validateNull(bucketName,null);
            return getOssService(businessCode).delete(bucketName,ossFileId);
        }catch(AntisPaasException e) {
            logger.warn("delete fail,with businessCode:{},bucketName:{},ossFileId:{}",businessCode,bucketName,ossFileId,e);
            throw new AntisPaasException(e.getCode(),e.getMessage(),e);
        }catch(Exception e) {
            logger.error("delete fail,with businessCode:{},bucketName:{},ossFileId:{}",businessCode,bucketName,ossFileId,e);
            throw new AntisPaasException(AntisPaasErrorCode.error_0004.getErrorCode(),"刪除文件失敗!",e);
        }
    }

    /**
     * 根據指定域名&資源Id獲取文件配置信息
     * @param businessCode
     * @param bucketName
     * @param ossFileId
     * @return
     * @throws Exception
     */
    public ObjectMetadata getFileMetadata(String businessCode, String bucketName, String ossFileId) throws Exception{
        try {
            validateNull(businessCode,null);
            validateNull(ossFileId,null);
            validateNull(bucketName,null);
            return getOssService(businessCode).getFileMetadata(bucketName,ossFileId);
        }catch(AntisPaasException e) {
            logger.warn("getFileMetadata fail,with businessCode:{},bucketName:{}, ossFileId:{}",businessCode,bucketName,ossFileId,e);
            throw new AntisPaasException(e.getCode(),e.getMessage(),e);
        }catch(Exception e) {
            logger.error("getFileMetadata fail,with businessCode:{},bucketName:{}, ossFileId:{}",businessCode,bucketName,ossFileId,e);
            throw new AntisPaasException(AntisPaasErrorCode.error_0004.getErrorCode(),"獲取配置信息失敗!",e);
        }
    }

    /**
     * 根據資源Id獲取文件配置信息
     * @param businessCode
     * @param ossFileId
     * @return
     * @throws Exception
     */
    public ObjectMetadata getFileMetadata(String businessCode, String ossFileId) throws Exception{
        try {
            validateNull(businessCode,null);
            validateNull(ossFileId,null);
            return getOssService(businessCode).getFileMetadata(ossFileId);
        }catch(AntisPaasException e) {
            logger.warn("getFileMetadata fail,with businessCode:{},ossFileId:{}",businessCode,ossFileId,e);
            throw new AntisPaasException(e.getCode(),e.getMessage(),e);
        }catch(Exception e) {
            logger.error("getFileMetadata fail,with businessCode:{},ossFileId:{}",businessCode,ossFileId,e);
            throw new AntisPaasException(AntisPaasErrorCode.error_0004.getErrorCode(),"獲取配置信息失敗!",e);
        }
    }


    /**
     * 根據指定域名&資源Id獲取下載路徑
     * @param businessCode
     * @param bucketName
     * @param ossFileId
     * @return
     */
    public String getUrl(String businessCode, String bucketName, String ossFileId) {
        try {
            validateNull(businessCode,null);
            validateNull(ossFileId,null);
            validateNull(bucketName,null);
            return getOssService(businessCode).getUrl(bucketName,ossFileId);
        }catch(AntisPaasException e) {
            logger.warn("getUrl fail,with businessCode:{},bucketName:{}, ossFileId:{}",businessCode,bucketName,ossFileId,e);
            throw new AntisPaasException(e.getCode(),e.getMessage(),e);
        }catch(Exception e) {
            logger.error("getUrl fail,with businessCode:{},bucketName:{}, ossFileId:{}",businessCode,bucketName,ossFileId,e);
            throw new AntisPaasException(AntisPaasErrorCode.error_0004.getErrorCode(),"獲取下載路徑失敗!",e);
        }
    }

    /**
     * 根據資源id獲取文件下載路徑
     * @param businessCode
     * @param ossFileId
     * @return
     */
    public String getUrl(String businessCode, String ossFileId) {
        try {
            validateNull(businessCode,null);
            validateNull(ossFileId,null);
            return getOssService(businessCode).getUrl(ossFileId);
        }catch(AntisPaasException e) {
            logger.warn("getUrl fail,with businessCode:{},ossFileId:{}",businessCode,ossFileId,e);
            throw new AntisPaasException(e.getCode(),e.getMessage(),e);
        }catch(Exception e) {
            logger.error("getUrl fail,with businessCode:{},ossFileId:{}",businessCode,ossFileId,e);
            throw new AntisPaasException(AntisPaasErrorCode.error_0004.getErrorCode(),"獲取下載路徑失敗!",e);
        }
    }

    /**
     * 根據資源Id獲取文件大小
     * @return
     */
    public long getFileSize(String businessCode,String ossFileId) {
        try {
            return getOssService(businessCode).getFileSize(ossFileId);
        }catch(AntisPaasException e) {
            logger.warn("get File Size fail,with businessCode:{},ossFileId:{}",businessCode,ossFileId,e);
            throw new AntisPaasException(e.getCode(),e.getMessage(),e);
        }catch(Exception e) {
            logger.error("get File Size fail,with businessCode:{},ossFileId:{}",businessCode,ossFileId,e);
            throw new AntisPaasException(AntisPaasErrorCode.error_0004.getErrorCode(),"獲取文件大小失敗!",e);
        }
    }

    public static void cleanCache(Object businessCode) {
        ossServiceMap.remove(businessCode);
        ossConfigMap.remove(businessCode);
        //ossClientMap.remove(businessCode);
    }


    public void beginAction(Object businessCode) {
        //Don't do any thing
    }

    private void validateNull(Object input,String errMsg) {
        if(null==input) {
            if(StringUtils.isNotBlank(errMsg)) {
                throw new AntisPaasException(AntisPaasErrorCode.error_0001.getErrorCode(),errMsg);
            }else {
                throw new AntisPaasException(AntisPaasErrorCode.error_0001.getErrorCode(), AntisPaasErrorCode.error_0001.getErrorMsg());
            }
        }
    }

    private void validateTrue(boolean isTrue,String errMsg) {
        if(isTrue) {
            throw new AntisPaasException(AntisPaasErrorCode.error_0005.getErrorCode(),errMsg);
        }
    }

    /**
     * 獲得加密後流的長度,算法是 (原流大小/16)*16+16
     *
     * @param fileSize
     * @return
     * @throws Exception
     */
    protected long getInputLength(long fileSize) throws Exception {
        return (fileSize / 16) * 16 + 16;
    }



}

3、觀察者模式很簡單,可以參考觀察者者的具體定義。
關鍵:
1、spring中 implements ApplicationContextAware獲取上下文
2、context.getBeansOfType(MessageSend.class) 上下文中通過接口定義獲取所有觀察者接口的實現類
四、相關maven配置


com.aliyun.oss
aliyun-sdk-oss
2.2.1

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