• Springboot策略模式实现文件上传功能(Windows/Linux本地,oss,cos)


    1:首先配置pom依赖:

            
            <dependency>
                <groupId>com.aliyun.ossgroupId>
                <artifactId>aliyun-sdk-ossartifactId>
                <version>3.8.0version>
            dependency>
            
            <dependency>
                <groupId>com.qcloudgroupId>
                <artifactId>cos_apiartifactId>
                <version>5.6.75version>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2:application.yml:

    # 上传模式 (本地 阿里云 腾讯云)
    # 上传模式 (Window服务器,Linux服务器本地 阿里云 腾讯云)
    upload:
      mode: windowsLocal
      linuxLocal:
        # nginx映射本地文件路径,无域名则为 ip:83
        url: https://上传子域名/
        # 本地文件存储路径
        path: /usr/local/blog/upload/
        # Windows环境下测试 这里路径对应config中mvc拦截器里面的路径
      windowsLocal:
        url: http://localhost:8080/upload/
        path: G:/桌面/博客/mongo-blog-master/springboot/src/main/resources/upload/
      oss:
        url: http://Bucket域名/
        endpoint: OSS配置endpoint
        accessKeyId: OSS配置accessKeyId
        accessKeySecret: OSS配置accessKeySecret
        bucketName: OSS配置bucketName
      cos:
        url: https://ftz-1307097786.cos.ap-beijing.myqcloud.com/
        region: ap-beijing
        secretId: AKIDhKqBJPN8mDWcWFm6oVBj4A2h7IF2lFUX
        secretKey: tBLekcFi27yb3IJ6i7GCzYt2ymLgtwmt
        bucketName: ftz-1307097786
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    2.1:腾讯云信息查看:secretId+secretKey在访问密钥里面查看

    在这里插入图片描述

    2.2:url+region+bucketName在配置管理查看

    在这里插入图片描述

    3:Windows本地,Linux本地,阿里云,腾讯云的配置:

    3.1 :Windows本地配置:

    (1):首先配置application.yml:

    在这里插入图片描述

    (2***):重点:配置登录拦截器,设置虚拟路径,因为浏览器不可以直接访问电脑资源目录文件,所以需要设置虚拟路径!否则会报错:Not allowed to load local resource;这里的路径要跟application.yml中的路径相匹配

     @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/upload/**").addResourceLocations("file:G:/桌面/博客/mongo-blog-master/springboot/src/main/resources/upload/");
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    (3):策略枚举层:

    在这里插入图片描述

    package com.jjhroy.blog.enums;
    
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    
    /**
     * 上传模式枚举
     *
     * @author yezhiqiu
     * @date 2021/07/28
     */
    @Getter
    @AllArgsConstructor
    public enum UploadModeEnum {
        /**
         * oss
         */
        OSS("oss", "ossUploadStrategyImpl"),
        /**
         * Linux本地
         */
        LOCAL("linuxLocal", "localUploadStrategyImpl"),
    
        /**
         * Windows本地
         */
        WINDOWS("windowsLocal","windowsUploadStrategyImpl"),
    
        /**
         * cos
         */
        COS("cos", "cosUploadStrategyImpl");
    
        /**
         * 模式
         */
        private final String mode;
    
        /**
         * 策略
         */
        private final String strategy;
    
        /**
         * 获取策略
         *
         * @param mode 模式
         * @return {@link String} 搜索策略
         */
        public static String getStrategy(String mode) {
            for (UploadModeEnum value : UploadModeEnum.values()) {
                if (value.getMode().equals(mode)) {
                    return value.getStrategy();
                }
            }
            return null;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    (4):文件上传策略:

    在这里插入图片描述

    package com.jjhroy.blog.strategy.context;
    
    import com.jjhroy.blog.enums.UploadModeEnum;
    import com.jjhroy.blog.strategy.UploadStrategy;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
    import org.springframework.web.multipart.MultipartFile;
    
    import java.io.InputStream;
    import java.util.Map;
    
    
    /**
     * 上传策略上下文
     *
     * @author yezhiqiu
     * @date 2021/07/28
     */
    @Service
    public class UploadStrategyContext {
        /**
         * 上传模式
         */
        @Value("${upload.mode}")
        private String uploadMode;
    
        @Autowired
        private Map<String, UploadStrategy> uploadStrategyMap;
    
        /**
         * 执行上传策略
         *
         * @param file 文件
         * @param path 路径
         * @return {@link String} 文件地址
         */
        public String executeUploadStrategy(MultipartFile file, String path) {
            return uploadStrategyMap.get(UploadModeEnum.getStrategy(uploadMode)).uploadFile(file, path);
        }
    
    
        /**
         * 执行上传策略
         *
         * @param fileName    文件名称
         * @param inputStream 输入流
         * @param path        路径
         * @return {@link String} 文件地址
         */
        public String executeUploadStrategy(String fileName, InputStream inputStream, String path) {
            return uploadStrategyMap.get(UploadModeEnum.getStrategy(uploadMode)).uploadFile(fileName, inputStream, path);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    (5):本地路径上传策略方法实现层:WindowsUploadStrategyImpl:

    在这里插入图片描述

    package com.jjhroy.blog.strategy.impl;
    
    import com.jjhroy.blog.enums.FileExtEnum;
    import com.jjhroy.blog.exception.BizException;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
    
    import java.io.*;
    import java.nio.file.Files;
    import java.util.Objects;
    
    /**
     * @author ftz
     *
     * Windows本地上传策略
     *
     */
    @Service("windowsUploadStrategyImpl")
    public class WindowsUploadStrategyImpl extends AbstractUploadStrategyImpl  {
    
        /**
         * 本地路径
         */
        @Value("${upload.windowsLocal.path}")
        private String localPath;
    
        @Value("${upload.windowsLocal.url}")
        private String localUrl;
    
        @Override
        public Boolean exists(String filePath) {
            return new File(localPath + filePath).exists();
        }
    
        @Override
        public void upload(String path, String fileName, InputStream inputStream) throws IOException {
            // 判断目录是否存在
            File directory = new File(localPath + path);
            if (!directory.exists()) {
                if (!directory.mkdirs()) {
                    throw new BizException("创建目录失败");
                }
            }
            // 写入文件
            File file = new File(localPath + path + fileName);
            String ext = "." + fileName.split("\\.")[1];
            switch (Objects.requireNonNull(FileExtEnum.getFileExt(ext))) {
                case MD:
                case TXT:
                    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                    BufferedWriter writer = new BufferedWriter(new FileWriter(file));
                    while (reader.ready()) {
                        writer.write((char) reader.read());
                    }
                    writer.flush();
                    writer.close();
                    reader.close();
                    break;
                default:
                    BufferedInputStream bis = new BufferedInputStream(inputStream);
                    BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(file.toPath()));
                    byte[] bytes = new byte[1024];
                    int length;
                    while ((length = bis.read(bytes)) != -1) {
                        bos.write(bytes, 0, length);
                    }
                    bos.flush();
                    bos.close();
                    bis.close();
                    break;
            }
            inputStream.close();
        }
    
    
        @Override
        public String getFileAccessUrl(String filePath) {
            return localUrl+filePath;
        }
    
    
    
    
    
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87

    (6):controller层:更新用户头像为例:

    
        /**
         * 更新用户头像
         *
         * @param file 文件
         * @return {@link Result} 头像地址
         */
        @ApiOperation(value = "更新用户头像")
        @ApiImplicitParam(name = "file", value = "用户头像", required = true, dataType = "MultipartFile")
        @PostMapping("/users/avatar")
        public Result<String> updateUserAvatar(MultipartFile file) {
            return Result.ok(userInfoService.updateUserAvatar(file));
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    (7):userInfoService.updateUserAvatar层及其实现:

        @Transactional(rollbackFor = Exception.class)
        @Override
        public String updateUserAvatar(MultipartFile file) {
            // 头像上传
            String avatar = uploadStrategyContext.executeUploadStrategy(file, FilePathEnum.AVATAR.getPath());
            // 更新用户信息
            UserInfo userInfo = UserInfo.builder()
                    .id(UserUtils.getLoginUser().getUserInfoId())
                    .avatar(avatar)
                    .build();
            userInfoDao.updateById(userInfo);
            return avatar;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    (8):uploadStrategyContext.executeUploadStrategy:

    在这里插入图片描述

    package com.jjhroy.blog.strategy.context;
    
    import com.jjhroy.blog.enums.UploadModeEnum;
    import com.jjhroy.blog.strategy.UploadStrategy;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
    import org.springframework.web.multipart.MultipartFile;
    
    import java.io.InputStream;
    import java.util.Map;
    
    
    /**
     * 上传策略上下文
     *
     * @author yezhiqiu
     * @date 2021/07/28
     */
    @Service
    public class UploadStrategyContext {
        /**
         * 上传模式
         */
        @Value("${upload.mode}")
        private String uploadMode;
    
        @Autowired
        private Map<String, UploadStrategy> uploadStrategyMap;
    
        /**
         * 执行上传策略
         *
         * @param file 文件
         * @param path 路径
         * @return {@link String} 文件地址
         */
        public String executeUploadStrategy(MultipartFile file, String path) {
            return uploadStrategyMap.get(UploadModeEnum.getStrategy(uploadMode)).uploadFile(file, path);
        }
    
    
        /**
         * 执行上传策略
         *
         * @param fileName    文件名称
         * @param inputStream 输入流
         * @param path        路径
         * @return {@link String} 文件地址
         */
        public String executeUploadStrategy(String fileName, InputStream inputStream, String path) {
            return uploadStrategyMap.get(UploadModeEnum.getStrategy(uploadMode)).uploadFile(fileName, inputStream, path);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    (9):抽象上传模板

    在这里插入图片描述

    (10)文件上传工具类:

    package com.jjhroy.blog.util;
    
    import com.baomidou.mybatisplus.core.toolkit.StringUtils;
    import lombok.extern.log4j.Log4j2;
    import org.apache.commons.codec.binary.Hex;
    import org.springframework.web.multipart.MultipartFile;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.security.MessageDigest;
    import java.util.Objects;
    
    /**
     * 文件md5工具类
     *
     * @author yezhiqiu
     * @date 2021/07/28
     */
    @Log4j2
    public class FileUtils {
    
        /**
         * 获取文件md5值
         *
         * @param inputStream 文件输入流
         * @return {@link String} 文件md5值
         */
        public static String getMd5(InputStream inputStream) {
            try {
                MessageDigest md5 = MessageDigest.getInstance("md5");
                byte[] buffer = new byte[8192];
                int length;
                while ((length = inputStream.read(buffer)) != -1) {
                    md5.update(buffer, 0, length);
                }
                return new String(Hex.encodeHex(md5.digest()));
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            } finally {
                try {
                    if (inputStream != null) {
                        inputStream.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * 得到文件扩展名
         *
         * @param fileName 文件名称
         * @return {@link String} 文件后缀
         */
        public static String getExtName(String fileName) {
            if (StringUtils.isBlank(fileName)) {
                return "";
            }
            return fileName.substring(fileName.lastIndexOf("."));
        }
    
        /**
         * 转换file
         *
         * @param multipartFile 多部分文件
         * @return {@link File} file
         */
        public static File multipartFileToFile(MultipartFile multipartFile) {
            File file = null;
            try {
                String originalFilename = multipartFile.getOriginalFilename();
                String[] filename = Objects.requireNonNull(originalFilename).split("\\.");
                file = File.createTempFile(filename[0], filename[1]);
                multipartFile.transferTo(file);
                file.deleteOnExit();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return file;
        }
    
    
        /**
         * 自动调节精度(经验数值)
         *
         * @param size 源图片大小
         * @return 图片压缩质量比
         */
        private static double getAccuracy(long size) {
            double accuracy;
            if (size < 900) {
                accuracy = 0.85;
            } else if (size < 2048) {
                accuracy = 0.6;
            } else if (size < 3072) {
                accuracy = 0.44;
            } else {
                accuracy = 0.4;
            }
            return accuracy;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107

    3.2:其余三种类似,只需要改变一下application.yml就好

  • 相关阅读:
    2020最新Java面试题
    做自媒体一直没有收入,要不要放弃?
    基于域名的方式访问Istio服务网格中的多个应用程序
    MySQL分页查询的5种方法
    C语言算术随笔
    Visual Studio Code 1.73发布!
    WebKit Inside: CSS 样式表的匹配时机
    基于Mongodb分布式锁简单实现,解决定时任务并发执行问题
    Transformer预测 | Python实现基于Transformer的股票价格预测(tensorflow)
    2024水科技大会暨技术装备成果展览会——城镇雨污分流及污水处理提质增效论坛(五)
  • 原文地址:https://blog.csdn.net/justleavel/article/details/128146103