tj
2025-06-05 2d549a04870d1315868a7cf19952b64e8071e711
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
package com.cloudroam.module.file;
 
import io.github.talelin.autoconfigure.exception.*;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartFile;
 
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
 
/**
 * 文件上传类的基类
 * 模版模式
 *
 * @author 
 * @author 
 * @author 
 */
public abstract class AbstractUploader implements Uploader {
 
    private UploadHandler uploadHandler;
 
    @Override
    public List<File> upload(MultiValueMap<String, MultipartFile> fileMap) {
        checkFileMap(fileMap);
        // 得到单个文件的大小限制
        // 本地存储需先初始化存储文件夹
        return handleMultipartFiles(fileMap);
    }
 
    @Override
    public List<File> upload(MultiValueMap<String, MultipartFile> fileMap, UploadHandler uploadHandler) {
        this.uploadHandler = uploadHandler;
        return this.upload(fileMap);
    }
 
    protected List<File> handleMultipartFiles(MultiValueMap<String, MultipartFile> fileMap) {
        long singleFileLimit = getSingleFileLimit();
        List<File> res = new ArrayList<>();
        fileMap.keySet().forEach(key -> fileMap.get(key).forEach(file -> {
            if (!file.isEmpty()) {
                handleOneFile0(res, singleFileLimit, file);
            }
        }));
        return res;
    }
 
    private void handleOneFile0(List<File> res, long singleFileLimit, MultipartFile file) {
        byte[] bytes = getFileBytes(file);
        String[] include = getFileProperties().getInclude();
        String[] exclude = getFileProperties().getExclude();
        String ext = checkOneFile(include, exclude, singleFileLimit, file.getOriginalFilename(), bytes.length);
        String newFilename = getNewFilename(ext);
        String storePath = getStorePath(newFilename);
        // 生成文件的md5值
        String md5 = FileUtil.getFileMD5(bytes);
        File fileData = File.builder().
//                name(newFilename).
                name(file.getOriginalFilename()).
                md5(md5).
                key(file.getName()).
                path(storePath).
                size(bytes.length).
                type(getFileType()).
                extension(ext).
                build();
        // 如果预处理器不为空,且处理结果为false,直接返回, 否则处理
        if (uploadHandler != null && !uploadHandler.preHandle(fileData)) {
            return;
        }
        boolean ok = handleOneFile(bytes, newFilename);
        if (ok) {
            res.add(fileData);
            // 上传到本地或云上成功之后,调用afterHandle
            if (uploadHandler != null) {
                uploadHandler.afterHandle(fileData);
            }
        }
    }
 
    private long getSingleFileLimit() {
        String singleLimit = getFileProperties().getSingleLimit();
        return FileUtil.parseSize(singleLimit);
    }
 
    /**
     * 得到文件配置
     *
     * @return 文件配置
     */
    protected abstract FileProperties getFileProperties();
 
    /**
     * 处理一个文件
     */
    protected abstract boolean handleOneFile(byte[] bytes, String newFilename);
 
    /**
     * 返回文件路径
     *
     * @param newFilename 文件名
     * @return 文件路径
     */
    protected abstract String getStorePath(String newFilename);
 
    /**
     * 返回文件存储位置类型
     *
     * @return LOCAL | REMOTE
     */
    protected abstract String getFileType();
 
    /**
     * 获得新文件的名称
     *
     * @param ext 文件后缀
     * @return 新名称
     */
    protected String getNewFilename(String ext) {
        String uuid = UUID.randomUUID().toString().replace("-", "");
        return uuid + ext;
    }
 
    /**
     * 检查文件
     */
    protected void checkFileMap(MultiValueMap<String, MultipartFile> fileMap) {
        if (fileMap.isEmpty()) {
            throw new NotFoundException(10026);
        }
        int nums = getFileProperties().getNums();
        AtomicInteger sizes = new AtomicInteger();
        fileMap.keySet().forEach(key -> fileMap.get(key).forEach(file -> {
            if (!file.isEmpty()) {
                sizes.getAndIncrement();
            }
        }));
        if (sizes.get() > nums) {
            throw new FileTooManyException(10121);
        }
    }
 
    /**
     * 获得文件的字节
     *
     * @param file 文件
     * @return 字节
     */
    protected byte[] getFileBytes(MultipartFile file) {
        byte[] bytes;
        try {
            bytes = file.getBytes();
        } catch (Exception e) {
            throw new FailedException(10190, "read file date failed");
        }
        return bytes;
    }
 
    /**
     * 单个文件检查
     *
     * @param singleFileLimit 单个文件大小限制
     * @param originName      文件原始名称
     * @param length          文件大小
     * @return 文件的扩展名,例如: .jpg
     */
    protected String checkOneFile(String[] include, String[] exclude, long singleFileLimit, String originName, int length) {
        // 写到了本地
        String ext = FileUtil.getFileExt(originName);
        // 检测扩展
        if (!this.checkExt(include, exclude, ext)) {
            throw new FileExtensionException(ext + "文件类型不支持");
        }
        // 检测单个大小
        if (length > singleFileLimit) {
            throw new FileTooLargeException(originName + "文件不能超过" + singleFileLimit);
        }
        return ext;
    }
 
    /**
     * 检查文件后缀
     *
     * @param ext 后缀名
     * @return 是否通过
     */
    protected boolean checkExt(String[] include, String[] exclude, String ext) {
        int inLen = include == null ? 0 : include.length;
        int exLen = exclude == null ? 0 : exclude.length;
        // 如果两者都有取 include,有一者则用一者
        if (inLen > 0 && exLen > 0) {
            return this.findInInclude(include, ext);
        } else if (inLen > 0) {
            // 有include,无exclude
            return this.findInInclude(include, ext);
        } else if (exLen > 0) {
            // 有exclude,无include
            return this.findInExclude(exclude, ext);
        } else {
            // 二者都没有
            return true;
        }
    }
 
    protected boolean findInInclude(String[] include, String ext) {
        for (String s : include) {
            if (s.equals(ext)) {
                return true;
            }
        }
        return false;
    }
 
    protected boolean findInExclude(String[] exclude, String ext) {
        for (String s : exclude) {
            if (s.equals(ext)) {
                return true;
            }
        }
        return false;
    }
}