SpringBoot单文件与多文件上传

本次例子不基于第三方存储(如七牛云对象存储、阿里云对象存储、腾讯云对象存储等),仅基于本地存储。

单文件上传主要应用场景如上传头像、特定文件转换、授权文件验证等。
多文件上传主要应用场景如批量Excel文件数据录入等。
本文主要内容如下:

  • 公共文件存储代码;
  • 单文件上传代码;
  • 多文件上传代码。

一、公共文件存储代码

1.FileUploadUtils.java

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
package com.springcloud.blog.admin.util.file;

/**
* @description: 文件上传工具类
* @author: youcong
* @time: 2020/9/28 11:34
*/

import com.springcloud.blog.admin.exception.file.FileNameLengthLimitExceededException;
import com.springcloud.blog.admin.exception.file.FileSizeLimitExceededException;
import com.springcloud.blog.admin.exception.file.InvalidExtensionException;
import com.springcloud.blog.admin.util.DateUtils;
import com.springcloud.blog.admin.util.IdUtils;
import com.springcloud.blog.admin.util.StringUtils;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;

public class FileUploadUtils {
/**
* 默认大小 50M
*/
public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;

/**
* 默认的文件名最大长度 100
*/
public static final int DEFAULT_FILE_NAME_LENGTH = 100;

/**
* 默认上传的地址
*/
private static String defaultBaseDir = "D://test//";

/**
* 资源映射路径 前缀
*/
public static String resource_prefix = "D://test//";

public static void setDefaultBaseDir(String defaultBaseDir) {
FileUploadUtils.defaultBaseDir = defaultBaseDir;
}

public static String getDefaultBaseDir() {
return defaultBaseDir;
}

/**
* 以默认配置进行文件上传
*
* @param file 上传的文件
* @return 文件名称
* @throws Exception
*/
public static final String upload(MultipartFile file) throws IOException {
try {
return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
} catch (Exception e) {
throw new IOException(e.getMessage(), e);
}
}


/**
* 文件上传
*
* @param baseDir 相对应用的基目录
* @param file 上传的文件
* @param allowedExtension 上传文件类型
* @return 返回上传成功的文件名
* @throws FileSizeLimitExceededException 如果超出最大大小
* @throws FileNameLengthLimitExceededException 文件名太长
* @throws IOException 比如读写文件出错时
* @throws InvalidExtensionException 文件校验异常
*/
public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
throws FileUploadBase.FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
InvalidExtensionException {
int fileNamelength = file.getOriginalFilename().length();
if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
}

assertAllowed(file, allowedExtension);

String fileName = extractFilename(file);

File desc = getAbsoluteFile(baseDir, fileName);
file.transferTo(desc);
String pathFileName = getPathFileName(baseDir, fileName);
return pathFileName;
}

/**
* 编码文件名
*/
public static final String extractFilename(MultipartFile file) {
String fileName = file.getOriginalFilename();
String extension = getExtension(file);
fileName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
return fileName;
}

private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException {
File desc = new File(uploadDir + File.separator + fileName);

if (!desc.getParentFile().exists()) {
desc.getParentFile().mkdirs();
}
if (!desc.exists()) {
desc.createNewFile();
}
return desc;
}

private static final String getPathFileName(String uploadDir, String fileName) throws IOException {
int dirLastIndex = defaultBaseDir.length() + 1;
String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
String pathFileName = resource_prefix + "/" + currentDir + "/" + fileName;
return pathFileName;
}

/**
* 文件大小校验
*
* @param file 上传的文件
* @return
* @throws FileSizeLimitExceededException 如果超出最大大小
* @throws InvalidExtensionException
*/
public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
throws FileSizeLimitExceededException, InvalidExtensionException {
long size = file.getSize();
if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE) {
throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
}

String fileName = file.getOriginalFilename();
String extension = getExtension(file);
if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) {
if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) {
throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
fileName);
} else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) {
throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
fileName);
} else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) {
throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
fileName);
} else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) {
throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
fileName);
} else {
throw new InvalidExtensionException(allowedExtension, extension, fileName);
}
}

}

/**
* 判断MIME类型是否是允许的MIME类型
*
* @param extension
* @param allowedExtension
* @return
*/
public static final boolean isAllowedExtension(String extension, String[] allowedExtension) {
for (String str : allowedExtension) {
if (str.equalsIgnoreCase(extension)) {
return true;
}
}
return false;
}

/**
* 获取文件名的后缀
*
* @param file 表单文件
* @return 后缀名
*/
public static final String getExtension(MultipartFile file) {
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
if (StringUtils.isEmpty(extension)) {
extension = MimeTypeUtils.getExtension(file.getContentType());
}
return extension;
}
}

2.FileUtils.java

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
package com.springcloud.blog.admin.util.file;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URLEncoder;

/**
* 文件处理工具类
*
* @author youcong
*/
public class FileUtils extends org.apache.commons.io.FileUtils {
public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";

/**
* 输出指定文件的byte数组
*
* @param filePath 文件路径
* @param os 输出流
* @return
*/
public static void writeBytes(String filePath, OutputStream os) throws IOException {
FileInputStream fis = null;
try {
File file = new File(filePath);
if (!file.exists()) {
throw new FileNotFoundException(filePath);
}
fis = new FileInputStream(file);
byte[] b = new byte[1024];
int length;
while ((length = fis.read(b)) > 0) {
os.write(b, 0, length);
}
} catch (IOException e) {
throw e;
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}

/**
* 删除文件
*
* @param filePath 文件
* @return
*/
public static boolean deleteFile(String filePath) {
boolean flag = false;
File file = new File(filePath);
// 路径为文件且不为空则进行删除
if (file.isFile() && file.exists()) {
file.delete();
flag = true;
}
return flag;
}

/**
* 文件名称验证
*
* @param filename 文件名称
* @return true 正常 false 非法
*/
public static boolean isValidFilename(String filename) {
return filename.matches(FILENAME_PATTERN);
}

/**
* 下载文件名重新编码
*
* @param request 请求对象
* @param fileName 文件名
* @return 编码后的文件名
*/
public static String setFileDownloadHeader(HttpServletRequest request, String fileName)
throws UnsupportedEncodingException {
final String agent = request.getHeader("USER-AGENT");
String filename = fileName;
if (agent.contains("MSIE")) {
// IE浏览器
filename = URLEncoder.encode(filename, "utf-8");
filename = filename.replace("+", " ");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
filename = new String(fileName.getBytes(), "ISO8859-1");
} else if (agent.contains("Chrome")) {
// google浏览器
filename = URLEncoder.encode(filename, "utf-8");
} else {
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
return filename;
}
}

3.MimeTypeUtils.java

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
package com.springcloud.blog.admin.util.file;

/**
* @description:
* @author: youcong
* @time: 2020/9/28 11:37
*/
public class MimeTypeUtils {
public static final String IMAGE_PNG = "image/png";

public static final String IMAGE_JPG = "image/jpg";

public static final String IMAGE_JPEG = "image/jpeg";

public static final String IMAGE_BMP = "image/bmp";

public static final String IMAGE_GIF = "image/gif";

public static final String[] IMAGE_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"};

public static final String[] FLASH_EXTENSION = {"swf", "flv"};

public static final String[] MEDIA_EXTENSION = {"swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
"asf", "rm", "rmvb"};

public static final String[] VIDEO_EXTENSION = {"mp4", "avi", "rmvb"};

public static final String[] DEFAULT_ALLOWED_EXTENSION = {
// 图片
"bmp", "gif", "jpg", "jpeg", "png",
// word excel powerpoint
"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
// 压缩文件
"rar", "zip", "gz", "bz2",
// 视频格式
"mp4", "avi", "rmvb",
// pdf
"pdf"};

public static String getExtension(String prefix) {
switch (prefix) {
case IMAGE_PNG:
return "png";
case IMAGE_JPG:
return "jpg";
case IMAGE_JPEG:
return "jpeg";
case IMAGE_BMP:
return "bmp";
case IMAGE_GIF:
return "gif";
default:
return "";
}
}
}

4.FileException.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.springcloud.blog.admin.exception.file;

import com.springcloud.blog.admin.exception.BaseException;

/**
* @description: 文件信息异常类
* @author: youcong
* @time: 2020/9/28 11:41
*/
public class FileException extends BaseException {
private static final long serialVersionUID = 1L;

public FileException(String code, Object[] args) {
super("file", code, args, null);
}

}

5.FileNameLengthLimitExceededException.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.springcloud.blog.admin.exception.file;

/**
* @description:文件名称超长限制异常类
* @author: youcong
* @time: 2020/9/28 11:41
*/
public class FileNameLengthLimitExceededException extends FileException {
private static final long serialVersionUID = 1L;

public FileNameLengthLimitExceededException(int defaultFileNameLength) {
super("upload.filename.exceed.length", new Object[]{defaultFileNameLength});
}
}

6.FileSizeLimitExceededException.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.springcloud.blog.admin.exception.file;

/**
* @description: 文件名大小限制异常类
* @author: youcong
* @time: 2020/9/28 11:42
*/
public class FileSizeLimitExceededException extends FileException {
private static final long serialVersionUID = 1L;

public FileSizeLimitExceededException(long defaultMaxSize) {
super("upload.exceed.maxSize", new Object[]{defaultMaxSize});
}
}

7.InvalidExtensionException.java

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
package com.springcloud.blog.admin.exception.file;

/**
* @description: 文件上传错误异常类
* @author: youcong
* @time: 2020/9/28 11:42
*/

import org.apache.commons.fileupload.FileUploadException;

import java.util.Arrays;

public class InvalidExtensionException extends FileUploadException {
private static final long serialVersionUID = 1L;

private String[] allowedExtension;
private String extension;
private String filename;

public InvalidExtensionException(String[] allowedExtension, String extension, String filename) {
super("filename : [" + filename + "], extension : [" + extension + "], allowed extension : [" + Arrays.toString(allowedExtension) + "]");
this.allowedExtension = allowedExtension;
this.extension = extension;
this.filename = filename;
}

public String[] getAllowedExtension() {
return allowedExtension;
}

public String getExtension() {
return extension;
}

public String getFilename() {
return filename;
}

public static class InvalidImageExtensionException extends InvalidExtensionException {
private static final long serialVersionUID = 1L;

public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename) {
super(allowedExtension, extension, filename);
}
}

public static class InvalidFlashExtensionException extends InvalidExtensionException {
private static final long serialVersionUID = 1L;

public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename) {
super(allowedExtension, extension, filename);
}
}

public static class InvalidMediaExtensionException extends InvalidExtensionException {
private static final long serialVersionUID = 1L;

public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename) {
super(allowedExtension, extension, filename);
}
}

public static class InvalidVideoExtensionException extends InvalidExtensionException {
private static final long serialVersionUID = 1L;

public InvalidVideoExtensionException(String[] allowedExtension, String extension, String filename) {
super(allowedExtension, extension, filename);
}
}
}

8.BaseException.java

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
package com.springcloud.blog.admin.exception;

/**
* 基础异常
*
* @author youcong
*/
public class BaseException extends RuntimeException {
private static final long serialVersionUID = 1L;

/**
* 所属模块
*/
private String module;

/**
* 错误码
*/
private String code;

/**
* 错误码对应的参数
*/
private Object[] args;

/**
* 错误消息
*/
private String defaultMessage;

public BaseException(String module, String code, Object[] args, String defaultMessage) {
this.module = module;
this.code = code;
this.args = args;
this.defaultMessage = defaultMessage;
}

public BaseException(String module, String code, Object[] args) {
this(module, code, args, null);
}

public BaseException(String module, String defaultMessage) {
this(module, null, null, defaultMessage);
}

public BaseException(String code, Object[] args) {
this(null, code, args, null);
}

public BaseException(String defaultMessage) {
this(null, null, null, defaultMessage);
}

public String getModule() {
return module;
}

public String getCode() {
return code;
}

public Object[] getArgs() {
return args;
}

public String getDefaultMessage() {
return defaultMessage;
}
}

二、单文件上传代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@PostMapping("/post/uploadFile")
@ApiOperation("文章上传特色图片")
public ResponseBaseDTO<String> uploadFile(@RequestParam("file") MultipartFile file) {
logger.info("/post/uploadFile");
try {

String fileUrl = FileUploadUtils.upload(file);
if (fileUrl != null) {
return ResponseBaseDTO.createSuccResp(fileUrl);
}
return ResponseBaseDTO.createFailResp(fileUrl);
} catch (Exception e) {
logger.error("/post/uploadFile", e);
return ResponseBaseDTO.createFailResp(e.getMessage());
}
}

三、多文件上传代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@PostMapping("/batchImportsUsers")
@ApiOperation("批量导入用户数据小时")
public ResponseBaseDTO<String> batchImportsUsers(MultipartFile[] uploadFiles) {
if (uploadFiles.length > 0) {
for (int i = 0; i < uploadFiles.length; i++) {
try {
importUserExcelData(uploadFiles[i]);
} catch (Exception e) {
e.printStackTrace();
}
}
return ResponseBaseDTO.createSuccResp();
}
return ResponseBaseDTO.createFailResp(e.getMessage());
}
文章目录
  1. 一、公共文件存储代码
    1. 1.FileUploadUtils.java
    2. 2.FileUtils.java
    3. 3.MimeTypeUtils.java
    4. 4.FileException.java
    5. 5.FileNameLengthLimitExceededException.java
    6. 6.FileSizeLimitExceededException.java
    7. 7.InvalidExtensionException.java
    8. 8.BaseException.java
  2. 二、单文件上传代码
  3. 三、多文件上传代码