美文网首页
文件上传

文件上传

作者: 千年的心 | 来源:发表于2021-04-26 17:42 被阅读0次

    背景

    在实际开发中,我们经常会使用到文件上传功能,特在此总结常用的文件上传,我们常用的长传是阿里云OSS、七牛云、自建(MinIO,FastDFS等)

    方式

    代码

    代码结构

    外部包

    <properties>
           <spring.plugin.version>2.0.0.RELEASE</spring.plugin.version>
            <spring.boot.version>2.4.1</spring.boot.version>
            <spring.cloud.version>2020.0.0</spring.cloud.version>       
            <qiniu.oss.version>7.2.18</qiniu.oss.version>
            <ali.oss.version>3.1.0</ali.oss.version>
            <ali.pay.version>4.10.97.ALL</ali.pay.version>
            <min.io.version>3.0.10</min.io.version>
            <lombok.version>1.18.12</lombok.version>
        </properties>
    
    <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.plugin</groupId>
                    <artifactId>spring-plugin-core</artifactId>
                    <version>${spring.plugin.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework.plugin</groupId>
                    <artifactId>spring-plugin-metadata</artifactId>
                    <version>${spring.plugin.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-dependencies</artifactId>
                    <version>${spring.boot.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring.cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
    <dependencies>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>sharp-weapon</groupId>
                <artifactId>core-tool</artifactId>
                <version>${sharp.weapon.core.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!--七牛云-->
            <dependency>
                <groupId>com.qiniu</groupId>
                <artifactId>qiniu-java-sdk</artifactId>
                <version>${qiniu.oss.version}</version>
            </dependency>
            <!--阿里云oss-->
            <dependency>
                <groupId>com.aliyun.oss</groupId>
                <artifactId>aliyun-sdk-oss</artifactId>
                <version>${ali.oss.version}</version>
            </dependency>
            <!-- MinIO -->
            <dependency>
                <groupId>io.minio</groupId>
                <artifactId>minio</artifactId>
                <version>${min.io.version}</version>
            </dependency>
        </dependencies>
    

    实体定义

    文件资源

    package org.weapon.third.file.model;
    
    import lombok.Data;
    
    import java.time.LocalDateTime;
    
    /**
     * 文件资源
     *
     * @author lieber
     */
    @Data
    public class FileResource {
    
        /**
         * 文件地址
         */
        private String link;
    
        /**
         * 文件名
         */
        private String name;
    
        /**
         * 文件hash值
         */
        public String hash;
    
        /**
         * 文件大小
         */
        private long length;
    
        /**
         * 文件上传时间
         */
        private LocalDateTime putTime;
    
        /**
         * 文件contentType
         */
        private String contentType;
    }
    

    文件上传结果

    package org.weapon.third.file.model;
    
    import lombok.Builder;
    import lombok.Data;
    
    /**
     * 文件上传结果
     *
     * @author lieber
     */
    @Data
    @Builder
    public class FileUploadResult {
    
        /**
         * 文件地址
         */
        private String path;
    
        /**
         * 文件名
         */
        private String name;
    
        /**
         * 原始文件名
         */
        private String originalName;
    }
    

    参数配置

    package org.weapon.third.file.props;
    
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    
    /**
     * 参数配置类
     *
     * @author lieber
     */
    @Data
    @ConfigurationProperties(prefix = "weapon.file")
    public class FileProperties {
    
        /**
         * 是否启用
         */
        private Boolean enabled;
    
        /**
         * 对象存储名称
         */
        private String name;
    
        /**
         * 对象存储服务的URL
         */
        private String endpoint;
    
        /**
         * Access key就像用户ID,可以唯一标识你的账户
         */
        private String accessKey;
    
        /**
         * Secret key是你账户的密码
         */
        private String secretKey;
    
        /**
         * 默认的存储桶名称
         */
        private String bucketName;
    
        private long expireTime = 3600L;
    
        private long contentLengthRange = 10485760;
    
    }
    

    通用规则

    通用规则接口定义

    package org.weapon.third.file.rule;
    
    /**
     * 通用规则
     *
     * @author lieber
     */
    public interface IFileRule {
    
        /**
         * 获取存储桶规则
         *
         * @param bucketName 存储桶名称
         * @return String
         */
        String bucketName(String bucketName);
    
        /**
         * 获取文件名规则
         *
         * @param originalFilename 文件名
         * @return String
         */
        String fileName(String originalFilename);
    
    }
    
    

    默认规则实现

    package org.weapon.third.file.rule;
    
    import org.weapon.core.tool.DateTimeUtil;
    import org.weapon.core.tool.FileUtil;
    import org.weapon.core.tool.Strings;
    
    /**
     * 默认存储桶生成规则
     *
     * @author lieber
     */
    public class DefaultFileRule implements IFileRule {
    
        @Override
        public String bucketName(String bucketName) {
            return bucketName;
        }
    
        @Override
        public String fileName(String originalFilename) {
            return "upload" + Strings.FILE_SLASH +
                    DateTimeUtil.today() + Strings.FILE_SLASH +
                    Strings.randomUUID() + Strings.DOT + FileUtil.getFileExtension(originalFilename);
        }
    
    }
    
    

    文件上传

    文件上传接口

    package org.weapon.third.file.template;
    
    import org.springframework.web.multipart.MultipartFile;
    import org.weapon.third.file.model.FileResource;
    import org.weapon.third.file.model.FileUploadResult;
    
    import java.io.InputStream;
    import java.util.List;
    
    /**
     * @author lieber
     */
    public interface IFileTemplate {
    
        /**
         * 创建bucket
         *
         * @param bucketName bucket名称
         */
        void createBucket(String bucketName);
    
        /**
         * 删除bucket
         *
         * @param bucketName bucket名称
         */
        void removeBucket(String bucketName);
    
        /**
         * bucket是否存在
         *
         * @param bucketName bucket名称
         * @return 存在为true
         */
        boolean bucketExists(String bucketName);
    
        /**
         * 文件拷贝
         *
         * @param bucketName            bucket名称
         * @param fileName              文件名
         * @param destinationBucketName 目标文件名
         */
        void copyFile(String bucketName, String fileName, String destinationBucketName);
    
        /**
         * 文件拷贝
         *
         * @param bucketName            原bucket名称
         * @param fileName              原文件名
         * @param destinationBucketName 目标bucket名称
         * @param destinationFileName   目标文件名
         */
        void copyFile(String bucketName, String fileName, String destinationBucketName, String destinationFileName);
    
        /**
         * 获取文件信息
         *
         * @param fileName 文件名
         * @return 文件信息
         */
        FileResource statFile(String fileName);
    
        /**
         * 获取文件信息
         *
         * @param bucketName bucket名称
         * @param fileName   文件名
         * @return 文件信息
         */
        FileResource statFile(String bucketName, String fileName);
    
        /**
         * 获取文件路径
         *
         * @param fileName 文件名
         * @return 文件路径
         */
        String filePath(String fileName);
    
        /**
         * 获取文件路径
         *
         * @param bucketName bucket名称
         * @param fileName   文件名
         * @return 文件路径
         */
        String filePath(String bucketName, String fileName);
    
        /**
         * 获取文件链接
         *
         * @param fileName 文件名
         * @return 件链接
         */
        String fileLink(String fileName);
    
        /**
         * 取文件链接
         *
         * @param bucketName bucket名称
         * @param fileName   文件名
         * @return 件链接
         */
        String fileLink(String bucketName, String fileName);
    
        /**
         * 文件上传
         *
         * @param file 文件
         * @return 上传结果
         */
        FileUploadResult putFile(MultipartFile file);
    
        /**
         * 文件上传
         *
         * @param fileName 文件名
         * @param file     文件
         * @return 上传结果
         */
        FileUploadResult putFile(String fileName, MultipartFile file);
    
        /**
         * 文件上传
         *
         * @param bucketName bucket名称
         * @param fileName   文件名
         * @param file       文件
         * @return 上传结果
         */
        FileUploadResult putFile(String bucketName, String fileName, MultipartFile file);
    
        /**
         * 文件上传
         *
         * @param fileName 文件名
         * @param stream   文件流
         * @return 上传结果
         */
        FileUploadResult putFile(String fileName, InputStream stream);
    
        /**
         * 文件上传
         *
         * @param bucketName bucket名称
         * @param fileName   文件名
         * @param stream     文件流
         * @return 上传结果
         */
        FileUploadResult putFile(String bucketName, String fileName, InputStream stream);
    
        /**
         * 文件上传
         *
         * @param bucketName bucket名称
         * @param stream     文件流
         * @param fileName   文件名
         * @param cover      是否覆盖上传
         * @return 上传结果
         */
        FileUploadResult put(String bucketName, InputStream stream, String fileName, boolean cover);
    
        /**
         * 删除文件
         *
         * @param fileName 文件名
         */
        void removeFile(String fileName);
    
        /**
         * 删除文件
         *
         * @param bucketName bucket名称
         * @param fileName   文件名
         */
        void removeFile(String bucketName, String fileName);
    
        /**
         * 批量删除文件
         *
         * @param fileNames 文件名集合
         */
        void removeFiles(List<String> fileNames);
    
        /**
         * 批量删除文件
         *
         * @param bucketName bucket名称
         * @param fileNames  文件名集合
         */
        void removeFiles(String bucketName, List<String> fileNames);
    
        /**
         * 上传凭证
         *
         * @return 上传凭证
         */
        String getUploadToken();
    
        /**
         * 上传凭证
         *
         * @param bucketName bucket名称
         * @return 上传凭证
         */
        String getUploadToken(String bucketName);
    
    }
    
    

    实现

    阿里云OSS文件上传接口实现

    package org.weapon.third.file.template;
    
    import com.aliyun.oss.OSSClient;
    import com.aliyun.oss.common.utils.BinaryUtil;
    import com.aliyun.oss.model.MatchMode;
    import com.aliyun.oss.model.ObjectMetadata;
    import com.aliyun.oss.model.PolicyConditions;
    import com.aliyun.oss.model.PutObjectResult;
    import lombok.AllArgsConstructor;
    import lombok.SneakyThrows;
    import org.springframework.util.StringUtils;
    import org.springframework.web.multipart.MultipartFile;
    import org.weapon.third.file.model.FileResource;
    import org.weapon.third.file.model.FileUploadResult;
    import org.weapon.third.file.props.FileProperties;
    import org.weapon.third.file.rule.IFileRule;
    import org.weapon.core.tool.DateTimeUtil;
    import org.weapon.core.tool.JsonUtil;
    import org.weapon.core.tool.Strings;
    
    import java.io.InputStream;
    import java.nio.charset.StandardCharsets;
    import java.util.Date;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 阿里云OSS文件上传
     *
     * @author lieber
     */
    @AllArgsConstructor
    public class AliOssTemplate implements IFileTemplate {
    
    
        private OSSClient client;
    
        private FileProperties properties;
    
        private IFileRule rule;
    
        @Override
        public void createBucket(String bucketName) {
            if (!bucketExists(bucketName)) {
                client.createBucket(getBucketName(bucketName));
            }
        }
    
        @Override
        public void removeBucket(String bucketName) {
            client.deleteBucket(getBucketName(bucketName));
        }
    
        @Override
        public boolean bucketExists(String bucketName) {
            return client.doesBucketExist(getBucketName(bucketName));
        }
    
        @Override
        public void copyFile(String bucketName, String fileName, String destinationBucketName) {
            client.copyObject(getBucketName(bucketName), fileName, getBucketName(destinationBucketName), fileName);
        }
    
        @Override
        public void copyFile(String bucketName, String fileName, String destinationBucketName, String destinationFileName) {
            client.copyObject(getBucketName(bucketName), fileName, getBucketName(destinationBucketName), destinationFileName);
        }
    
        @Override
        public FileResource statFile(String fileName) {
            return statFile(properties.getBucketName(), fileName);
        }
    
        @Override
        public FileResource statFile(String bucketName, String fileName) {
            ObjectMetadata stat = client.getObjectMetadata(getBucketName(bucketName), fileName);
            FileResource fileResource = new FileResource();
            fileResource.setName(fileName);
            fileResource.setLink(fileLink(fileResource.getName()));
            fileResource.setHash(stat.getContentMD5());
            fileResource.setLength(stat.getContentLength());
            fileResource.setPutTime(DateTimeUtil.toDateTime(stat.getLastModified()));
            fileResource.setContentType(stat.getContentType());
            return fileResource;
        }
    
        @Override
        public String filePath(String fileName) {
            return this.getHost().concat(Strings.FILE_SLASH).concat(fileName);
        }
    
        @Override
        public String filePath(String bucketName, String fileName) {
            return this.getHost(bucketName).concat(Strings.FILE_SLASH).concat(fileName);
        }
    
        @Override
        public String fileLink(String fileName) {
            return this.getHost().concat(Strings.FILE_SLASH).concat(fileName);
        }
    
        @Override
        public String fileLink(String bucketName, String fileName) {
            return this.getHost(bucketName).concat(Strings.FILE_SLASH).concat(fileName);
        }
    
        @Override
        @SneakyThrows
        public FileUploadResult putFile(MultipartFile file) {
            return putFile(properties.getBucketName(), file.getOriginalFilename(), file);
        }
    
        @Override
        @SneakyThrows
        public FileUploadResult putFile(String fileName, MultipartFile file) {
            return putFile(properties.getBucketName(), fileName, file);
        }
    
        @Override
        @SneakyThrows
        public FileUploadResult putFile(String bucketName, String fileName, MultipartFile file) {
            return putFile(bucketName, fileName, file.getInputStream());
        }
    
        @Override
        public FileUploadResult putFile(String fileName, InputStream stream) {
            return putFile(properties.getBucketName(), fileName, stream);
        }
    
        @Override
        public FileUploadResult putFile(String bucketName, String fileName, InputStream stream) {
            return put(bucketName, stream, fileName, false);
        }
    
        @Override
        public FileUploadResult put(String bucketName, InputStream stream, String originalName, boolean cover) {
            if (!this.bucketExists(bucketName)) {
                this.createBucket(bucketName);
            }
            String key = getFileName(originalName);
            // 覆盖上传
            if (cover) {
                client.putObject(getBucketName(bucketName), key, stream);
            } else {
                PutObjectResult response = client.putObject(getBucketName(bucketName), key, stream);
                int retry = 0;
                int retryCount = 5;
                while (StringUtils.hasText(response.getETag()) && retry < retryCount) {
                    response = client.putObject(getBucketName(bucketName), key, stream);
                    retry++;
                }
            }
            return FileUploadResult.builder().name(key).originalName(originalName).path(this.fileLink(bucketName, key)).build();
        }
    
        @Override
        public void removeFile(String fileName) {
            client.deleteObject(getBucketName(), fileName);
        }
    
        @Override
        public void removeFile(String bucketName, String fileName) {
            client.deleteObject(getBucketName(bucketName), fileName);
        }
    
        @Override
        public void removeFiles(List<String> fileNames) {
            fileNames.forEach(this::removeFile);
        }
    
        @Override
        public void removeFiles(String bucketName, List<String> fileNames) {
            fileNames.forEach(fileName -> removeFile(getBucketName(bucketName), fileName));
        }
    
        @Override
        public String getUploadToken() {
            return this.getUploadToken(properties.getBucketName());
        }
    
        @Override
        public String getUploadToken(String bucketName) {
            return this.getUploadToken(bucketName, properties.getExpireTime());
        }
    
        private String getUploadToken(String bucketName, long expireTime) {
            String baseDir = "upload";
    
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
    
            PolicyConditions policyConditions = new PolicyConditions();
            // 默认大小限制10M
            policyConditions.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, properties.getContentLengthRange());
            policyConditions.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, baseDir);
    
            String postPolicy = client.generatePostPolicy(expiration, policyConditions);
            byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = client.calculatePostSignature(postPolicy);
    
            Map<String, String> respMap = new LinkedHashMap<>(16);
            respMap.put("accessid", properties.getAccessKey());
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", baseDir);
            respMap.put("host", this.getHost(bucketName));
            respMap.put("expire", String.valueOf(expireEndTime / 1000));
            return JsonUtil.toJsonString(respMap).orElse(Strings.EMPTY);
        }
    
        private String getBucketName() {
            return getBucketName(properties.getBucketName());
        }
    
        private String getHost(String bucketName) {
            String prefix = properties.getEndpoint().contains("https://") ? "https://" : "http://";
            return prefix + getBucketName(bucketName) + Strings.DOT + properties.getEndpoint().replaceFirst(prefix, Strings.EMPTY);
        }
    
        private String getHost() {
            return this.getHost(properties.getBucketName());
        }
    
        private String getBucketName(String bucketName) {
            return rule.bucketName(bucketName);
        }
    
        private String getFileName(String originalFilename) {
            return rule.fileName(originalFilename);
        }
    }
    
    

    七牛云文件上传接口实现

    package org.weapon.third.file.template;
    
    import com.qiniu.common.Zone;
    import com.qiniu.http.Response;
    import com.qiniu.storage.BucketManager;
    import com.qiniu.storage.UploadManager;
    import com.qiniu.storage.model.FileInfo;
    import com.qiniu.util.Auth;
    import lombok.AllArgsConstructor;
    import lombok.SneakyThrows;
    import org.springframework.web.multipart.MultipartFile;
    import org.weapon.third.file.model.FileResource;
    import org.weapon.third.file.model.FileUploadResult;
    import org.weapon.third.file.props.FileProperties;
    import org.weapon.third.file.rule.IFileRule;
    import org.weapon.core.tool.CollectionUtil;
    import org.weapon.core.tool.DateTimeUtil;
    import org.weapon.core.tool.Strings;
    
    import java.io.InputStream;
    import java.util.List;
    
    /**
     * 七牛云文件上传
     *
     * @author lieber
     */
    @AllArgsConstructor
    public class QiNiuTemplate implements IFileTemplate {
    
    
        private Auth auth;
    
        private UploadManager uploadManager;
    
        private BucketManager bucketManager;
    
        private FileProperties properties;
    
        private IFileRule rule;
    
    
        @Override
        @SneakyThrows
        public void createBucket(String bucketName) {
            if (!CollectionUtil.contains(this.bucketManager.buckets(), getBucketName(bucketName))) {
                this.bucketManager.createBucket(getBucketName(bucketName), Zone.zone0().getRegion());
            }
        }
    
    
        @Override
        @SneakyThrows
        public void removeBucket(String bucketName) {
            this.bucketManager.deleteBucket(getBucketName(bucketName));
        }
    
    
        @Override
        @SneakyThrows
        public boolean bucketExists(String bucketName) {
            return CollectionUtil.contains(this.bucketManager.buckets(), getBucketName(bucketName));
        }
    
    
        @Override
        @SneakyThrows
        public void copyFile(String bucketName, String fileName, String destinationBucketName) {
            this.bucketManager.copy(getBucketName(bucketName), fileName, getBucketName(destinationBucketName), fileName);
        }
    
    
        @Override
        @SneakyThrows
        public void copyFile(String bucketName, String fileName, String destinationBucketName, String destinationFileName) {
            this.bucketManager.copy(getBucketName(bucketName), fileName, getBucketName(destinationBucketName), destinationFileName);
        }
    
    
        @Override
        public FileResource statFile(String fileName) {
            return statFile(this.properties.getBucketName(), fileName);
        }
    
    
        @Override
        @SneakyThrows
        public FileResource statFile(String bucketName, String fileName) {
            FileInfo stat = this.bucketManager.stat(getBucketName(bucketName), fileName);
            FileResource ossFile = new FileResource();
            ossFile.setName(stat.key);
            ossFile.setLink(fileLink(ossFile.getName()));
            ossFile.setHash(stat.hash);
            ossFile.setLength(stat.fsize);
            ossFile.setPutTime(DateTimeUtil.formTimestamp(stat.putTime / 10000));
            ossFile.setContentType(stat.mimeType);
            return ossFile;
        }
    
    
        @Override
        public String filePath(String fileName) {
            return getBucketName().concat(Strings.FILE_SLASH).concat(fileName);
        }
    
    
        @Override
        public String filePath(String bucketName, String fileName) {
            return getBucketName(bucketName).concat(Strings.FILE_SLASH).concat(fileName);
        }
    
    
        @Override
        public String fileLink(String fileName) {
            return properties.getEndpoint().concat(Strings.FILE_SLASH).concat(fileName);
        }
    
    
        @Override
        public String fileLink(String bucketName, String fileName) {
            return properties.getEndpoint().concat(Strings.FILE_SLASH).concat(fileName);
        }
    
    
        @Override
        public FileUploadResult putFile(MultipartFile file) {
            return putFile(properties.getBucketName(), file.getOriginalFilename(), file);
        }
    
    
        @Override
        public FileUploadResult putFile(String fileName, MultipartFile file) {
            return putFile(properties.getBucketName(), fileName, file);
        }
    
    
        @Override
        @SneakyThrows
        public FileUploadResult putFile(String bucketName, String fileName, MultipartFile file) {
            return putFile(bucketName, fileName, file.getInputStream());
        }
    
    
        @Override
        public FileUploadResult putFile(String fileName, InputStream stream) {
            return putFile(properties.getBucketName(), fileName, stream);
        }
    
    
        @Override
        public FileUploadResult putFile(String bucketName, String fileName, InputStream stream) {
            return put(bucketName, stream, fileName, false);
        }
    
        @Override
        @SneakyThrows
        public FileUploadResult put(String bucketName, InputStream stream, String fileName, boolean cover) {
            if (this.bucketExists(bucketName)) {
                this.createBucket(bucketName);
            }
            String key = getFileName(fileName);
            // 覆盖上传
            if (cover) {
                this.uploadManager.put(stream, key, getUploadToken(bucketName, key), null, null);
            } else {
                Response response = this.uploadManager.put(stream, key, getUploadToken(bucketName), null, null);
                int retry = 0;
                int retryCount = 5;
                while (response.needRetry() && retry < retryCount) {
                    response = this.uploadManager.put(stream, key, getUploadToken(bucketName), null, null);
                    retry++;
                }
            }
            return FileUploadResult.builder().name(key).originalName(fileName).path(fileLink(bucketName, key)).build();
        }
    
    
        @Override
        @SneakyThrows
        public void removeFile(String fileName) {
            bucketManager.delete(getBucketName(), fileName);
        }
    
    
        @Override
        @SneakyThrows
        public void removeFile(String bucketName, String fileName) {
            bucketManager.delete(getBucketName(bucketName), fileName);
        }
    
    
        @Override
        public void removeFiles(List<String> fileNames) {
            fileNames.forEach(this::removeFile);
        }
    
    
        @Override
        public void removeFiles(String bucketName, List<String> fileNames) {
            fileNames.forEach(fileName -> removeFile(getBucketName(bucketName), fileName));
        }
    
        @Override
        public String getUploadToken() {
            return this.getUploadToken(this.properties.getBucketName());
        }
    
        /**
         * 根据规则生成存储桶名称规则
         *
         * @return String
         */
        private String getBucketName() {
            return getBucketName(this.properties.getBucketName());
        }
    
        /**
         * 根据规则生成存储桶名称规则
         *
         * @param bucketName 存储桶名称
         * @return String
         */
        private String getBucketName(String bucketName) {
            return this.rule.bucketName(bucketName);
        }
    
        /**
         * 根据规则生成文件名称规则
         *
         * @param originalFilename 原始文件名
         * @return string
         */
        private String getFileName(String originalFilename) {
            return this.rule.fileName(originalFilename);
        }
    
        /**
         * 获取上传凭证,普通上传
         */
        @Override
        public String getUploadToken(String bucketName) {
            return this.auth.uploadToken(this.getBucketName(bucketName));
        }
    
    
        /**
         * 获取上传凭证,覆盖上传
         */
        private String getUploadToken(String bucketName, String key) {
            return this.auth.uploadToken(this.getBucketName(bucketName), key);
        }
    
    }
    
    

    MinIO上传接口实现

    package org.weapon.third.file.template;
    
    import io.minio.MinioClient;
    import io.minio.ObjectStat;
    import lombok.AllArgsConstructor;
    import lombok.SneakyThrows;
    import org.springframework.web.multipart.MultipartFile;
    import org.weapon.core.tool.DateTimeUtil;
    import org.weapon.core.tool.Strings;
    import org.weapon.third.file.model.FileResource;
    import org.weapon.third.file.model.FileUploadResult;
    import org.weapon.third.file.props.FileProperties;
    import org.weapon.third.file.rule.IFileRule;
    
    import java.io.InputStream;
    import java.util.List;
    
    /**
     * MinIO文件上传
     *
     * @author lieber
     */
    @AllArgsConstructor
    public class MinIoTemplate implements IFileTemplate {
    
        private MinioClient client;
    
        private FileProperties properties;
    
        private IFileRule rule;
    
        @SneakyThrows
        @Override
        public void createBucket(String bucketName) {
            if (!bucketExists(bucketName)) {
                client.makeBucket(getBucketName(bucketName));
            }
        }
    
        @SneakyThrows
        @Override
        public void removeBucket(String bucketName) {
            client.removeBucket(getBucketName(bucketName));
        }
    
        @SneakyThrows
        @Override
        public boolean bucketExists(String bucketName) {
            return client.bucketExists(getBucketName(bucketName));
        }
    
        @SneakyThrows
        @Override
        public void copyFile(String bucketName, String fileName, String destinationBucketName) {
            client.copyObject(getBucketName(bucketName), fileName, getBucketName(destinationBucketName), fileName);
        }
    
        @SneakyThrows
        @Override
        public void copyFile(String bucketName, String fileName, String destinationBucketName, String destinationFileName) {
            client.copyObject(getBucketName(bucketName), fileName, getBucketName(destinationBucketName), destinationFileName);
        }
    
        @Override
        public FileResource statFile(String fileName) {
            return statFile(properties.getBucketName(), fileName);
        }
    
        @SneakyThrows
        @Override
        public FileResource statFile(String bucketName, String fileName) {
            ObjectStat stat = client.statObject(getBucketName(bucketName), fileName);
            FileResource fileResource = new FileResource();
            fileResource.setName(fileName);
            fileResource.setLink(fileLink(fileResource.getName()));
            fileResource.setHash(null);
            fileResource.setLength(stat.length());
            fileResource.setPutTime(DateTimeUtil.toDateTime(stat.createdTime()));
            fileResource.setContentType(stat.contentType());
            return fileResource;
        }
    
        @Override
        public String filePath(String fileName) {
            return this.getHost().concat(Strings.FILE_SLASH).concat(fileName);
        }
    
        @Override
        public String filePath(String bucketName, String fileName) {
            return this.getHost(bucketName).concat(Strings.FILE_SLASH).concat(fileName);
        }
    
        @Override
        public String fileLink(String fileName) {
            return this.getHost().concat(Strings.FILE_SLASH).concat(fileName);
        }
    
        @Override
        public String fileLink(String bucketName, String fileName) {
            return this.getHost(bucketName).concat(Strings.FILE_SLASH).concat(fileName);
        }
    
        @Override
        @SneakyThrows
        public FileUploadResult putFile(MultipartFile file) {
            return putFile(properties.getBucketName(), file.getOriginalFilename(), file);
        }
    
        @Override
        @SneakyThrows
        public FileUploadResult putFile(String fileName, MultipartFile file) {
            return putFile(properties.getBucketName(), fileName, file);
        }
    
        @Override
        @SneakyThrows
        public FileUploadResult putFile(String bucketName, String fileName, MultipartFile file) {
            return putFile(bucketName, fileName, file.getInputStream());
        }
    
        @Override
        public FileUploadResult putFile(String fileName, InputStream stream) {
            return putFile(properties.getBucketName(), fileName, stream);
        }
    
        @Override
        public FileUploadResult putFile(String bucketName, String fileName, InputStream stream) {
            return put(bucketName, stream, fileName, false);
        }
    
        @Override
        @SneakyThrows
        public FileUploadResult put(String bucketName, InputStream stream, String originalName, boolean cover) {
            if (!this.bucketExists(bucketName)) {
                this.createBucket(bucketName);
            }
            String key = getFileName(originalName);
            // 覆盖上传
            if (cover) {
                client.putObject(getBucketName(bucketName), key, stream, stream.available(), "application/octet-stream");
            } else {
                boolean success = false;
                int retry = 0;
                int retryCount = 5;
                while (!success && retry < retryCount) {
                    try {
                        client.putObject(getBucketName(bucketName), key, stream, stream.available(), "application/octet-stream");
                        success = true;
                    } catch (Exception ignore) {
                    }
                    retry++;
                }
            }
            return FileUploadResult.builder().name(key).originalName(originalName).path(this.fileLink(bucketName, key)).build();
        }
    
        @Override
        @SneakyThrows
        public void removeFile(String fileName) {
            client.removeObject(getBucketName(), fileName);
        }
    
        @Override
        @SneakyThrows
        public void removeFile(String bucketName, String fileName) {
            client.removeObject(getBucketName(bucketName), fileName);
        }
    
        @Override
        public void removeFiles(List<String> fileNames) {
            fileNames.forEach(this::removeFile);
        }
    
        @Override
        public void removeFiles(String bucketName, List<String> fileNames) {
            fileNames.forEach(fileName -> removeFile(getBucketName(bucketName), fileName));
        }
    
        @Override
        public String getUploadToken() {
            return this.getUploadToken(properties.getBucketName());
        }
    
        @Override
        public String getUploadToken(String bucketName) {
            throw new IllegalArgumentException("不支持的方式");
        }
    
    
        private String getBucketName() {
            return getBucketName(properties.getBucketName());
        }
    
        private String getHost(String bucketName) {
            String prefix = properties.getEndpoint().contains("https://") ? "https://" : "http://";
            return prefix + properties.getEndpoint().replaceFirst(prefix, Strings.EMPTY) + Strings.FILE_SLASH + getBucketName(bucketName);
        }
    
        private String getHost() {
            return this.getHost(properties.getBucketName());
        }
    
        private String getBucketName(String bucketName) {
            return rule.bucketName(bucketName);
        }
    
        private String getFileName(String originalFilename) {
            return rule.fileName(originalFilename);
        }
    }
    

    使用配置

    阿里OSS配置类

    package org.weapon.third.file.config;
    
    import com.aliyun.oss.ClientConfiguration;
    import com.aliyun.oss.OSSClient;
    import com.aliyun.oss.common.auth.CredentialsProvider;
    import com.aliyun.oss.common.auth.DefaultCredentialProvider;
    import lombok.AllArgsConstructor;
    import org.springframework.boot.autoconfigure.AutoConfigureAfter;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
    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.Configuration;
    import org.weapon.third.file.template.AliOssTemplate;
    import org.weapon.third.file.template.IFileTemplate;
    import org.weapon.third.file.props.FileProperties;
    import org.weapon.third.file.rule.DefaultFileRule;
    import org.weapon.third.file.rule.IFileRule;
    
    /**
     * 阿里OSS配置类
     *
     * @author lieber
     */
    @Configuration(proxyBeanMethods = false)
    @AllArgsConstructor
    @AutoConfigureAfter(QiNiuConfiguration.class)
    @EnableConfigurationProperties(FileProperties.class)
    @ConditionalOnProperty(value = "weapon.file.name", havingValue = "ali-oss")
    public class AliOssConfiguration {
    
        private FileProperties ossProperties;
    
        @Bean
        @ConditionalOnMissingBean(IFileRule.class)
        public IFileRule ossRule() {
            return new DefaultFileRule();
        }
    
        @Bean
        @ConditionalOnMissingBean(OSSClient.class)
        public OSSClient ossClient() {
            // 创建ClientConfiguration。ClientConfiguration是OSSClient的配置类,可配置代理、连接超时、最大连接数等参数。
            ClientConfiguration conf = new ClientConfiguration();
            // 设置OSSClient允许打开的最大HTTP连接数,默认为1024个。
            conf.setMaxConnections(1024);
            // 设置Socket层传输数据的超时时间,默认为50000毫秒。
            conf.setSocketTimeout(50000);
            // 设置建立连接的超时时间,默认为50000毫秒。
            conf.setConnectionTimeout(50000);
            // 设置从连接池中获取连接的超时时间(单位:毫秒),默认不超时。
            conf.setConnectionRequestTimeout(1000);
            // 设置连接空闲超时时间。超时则关闭连接,默认为60000毫秒。
            conf.setIdleConnectionTime(60000);
            // 设置失败请求重试次数,默认为3次。
            conf.setMaxErrorRetry(5);
            CredentialsProvider credentialsProvider = new DefaultCredentialProvider(ossProperties.getAccessKey(), ossProperties.getSecretKey());
            return new OSSClient(ossProperties.getEndpoint(), credentialsProvider, conf);
        }
    
        @Bean
        @ConditionalOnMissingBean(IFileTemplate.class)
        @ConditionalOnBean({OSSClient.class, IFileRule.class})
        public IFileTemplate aliOssTemplate(OSSClient ossClient, IFileRule fileRule) {
            return new AliOssTemplate(ossClient, ossProperties, fileRule);
        }
    
    }
    
    

    七牛配置类

    package org.weapon.third.file.config;
    
    import com.qiniu.common.Zone;
    import com.qiniu.storage.BucketManager;
    import com.qiniu.storage.UploadManager;
    import com.qiniu.util.Auth;
    import lombok.AllArgsConstructor;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
    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.Configuration;
    import org.weapon.third.file.props.FileProperties;
    import org.weapon.third.file.rule.DefaultFileRule;
    import org.weapon.third.file.rule.IFileRule;
    import org.weapon.third.file.template.IFileTemplate;
    import org.weapon.third.file.template.QiNiuTemplate;
    
    /**
     * 七牛配置类
     *
     * @author lieber
     */
    @Configuration(proxyBeanMethods = false)
    @AllArgsConstructor
    @EnableConfigurationProperties(FileProperties.class)
    @ConditionalOnProperty(value = "weapon.file.name", havingValue = "qi-niu")
    public class QiNiuConfiguration {
    
        private FileProperties properties;
    
        @Bean
        @ConditionalOnMissingBean(IFileRule.class)
        public IFileRule ossRule() {
            return new DefaultFileRule();
        }
    
        @Bean
        public com.qiniu.storage.Configuration qiNiuConfiguration() {
            return new com.qiniu.storage.Configuration(Zone.zone0());
        }
    
        @Bean
        public Auth auth() {
            return Auth.create(properties.getAccessKey(), properties.getSecretKey());
        }
    
        @Bean
        @ConditionalOnBean(com.qiniu.storage.Configuration.class)
        public UploadManager uploadManager(com.qiniu.storage.Configuration cfg) {
            return new UploadManager(cfg);
        }
    
        @Bean
        @ConditionalOnBean(com.qiniu.storage.Configuration.class)
        public BucketManager bucketManager(com.qiniu.storage.Configuration cfg) {
            return new BucketManager(auth(), cfg);
        }
    
        @Bean
        @ConditionalOnMissingBean(IFileTemplate.class)
        @ConditionalOnBean({Auth.class, UploadManager.class, BucketManager.class, IFileRule.class})
        public IFileTemplate qiNiuTemplate(Auth auth, UploadManager uploadManager, BucketManager bucketManager, IFileRule rule) {
            return new QiNiuTemplate(auth, uploadManager, bucketManager, properties, rule);
        }
    
    
    }
    
    

    MinIO配置类

    package org.weapon.third.file.config;
    
    import io.minio.MinioClient;
    import lombok.AllArgsConstructor;
    import lombok.SneakyThrows;
    import org.springframework.boot.autoconfigure.AutoConfigureAfter;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
    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.Configuration;
    import org.weapon.third.file.props.FileProperties;
    import org.weapon.third.file.rule.DefaultFileRule;
    import org.weapon.third.file.rule.IFileRule;
    import org.weapon.third.file.template.IFileTemplate;
    import org.weapon.third.file.template.MinIoTemplate;
    
    /**
     * 阿里OSS配置类
     *
     * @author lieber
     */
    @Configuration
    @AllArgsConstructor
    @AutoConfigureAfter(MinIoConfiguration.class)
    @EnableConfigurationProperties(FileProperties.class)
    @ConditionalOnProperty(value = "weapon.file.name", havingValue = "min-io")
    public class MinIoConfiguration {
    
        private FileProperties minIoProperties;
    
        @Bean
        @ConditionalOnMissingBean(IFileRule.class)
        public IFileRule ossRule() {
            return new DefaultFileRule();
        }
    
        @Bean
        @ConditionalOnMissingBean(MinioClient.class)
        @SneakyThrows
        public MinioClient minioClient() {
            return new MinioClient(minIoProperties.getEndpoint(), minIoProperties.getAccessKey(), minIoProperties.getSecretKey());
        }
    
        @Bean
        @ConditionalOnMissingBean(IFileTemplate.class)
        @ConditionalOnBean({MinioClient.class, IFileRule.class})
        public IFileTemplate aliOssTemplate(MinioClient minioClient, IFileRule fileRule) {
            return new MinIoTemplate(minioClient, minIoProperties, fileRule);
        }
    
    }
    
    

    相关文章

      网友评论

          本文标题:文件上传

          本文链接:https://www.haomeiwen.com/subject/ztkerltx.html