最近项目业务要求上传文件,网上版本适用性太差,就自己花时间写了一个简单版本的。
不过我写的批量上传并不是多线程同时上传,而是遍历依次上传的,所以存在一些显而易见的问题。但对于本次业务已经足够了,后续完善。
一. 创建maven项目,并添加依赖
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>upload</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
二. 建立结构
简单结构大致如此。其中,需要注意Application启动类要在所有包和类的外层;
Application:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
/**
* 文件上传配置
*
* @return
*/
@Bean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
//文件最大 KB,MB
factory.setMaxFileSize("20480KB");
// 设置总上传数据总大小
factory.setMaxRequestSize("51200KB");
//防止客户端被分配访问未被清理临时目录的服务器时不能正常上传文件
if (System.getProperty("os.name").toLowerCase().contains("window")) {
String tmpPath = "c:/myFile/";
File file = new File(tmpPath);
if (!file.exists()) {
file.mkdirs();
}
factory.setLocation(tmpPath);
}
return factory.createMultipartConfig();
}
}
虚拟路径映射:
比如服务器存放的真实路径是 192.168.1.1:8080/usr/myFile/a.txt,但这样就暴露了服务器上的真实位置。因此,可以将 /usr/myFile/ 文件夹映射为想要的虚拟路径,如/uploads。访问时路径映射为 192.168.1.1:8080/uploads/a.txt。
/**
* @Author :
* @Desoription :
*/
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
/**
* 添加路径映射,将真实路径映射为虚拟路径
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
String os = System.getProperty("os.name");
if(os.toLowerCase().contains("window")){
//若当前系统是window系统
registry.addResourceHandler("/uploads/**").addResourceLocations("file:c:/myFile/");
}else {
registry.addResourceHandler("/uploads/**").addResourceLocations("file:/usr/myFile/");
}
super.addResourceHandlers(registry);
}
}
其中, System.getProperty("os.name") 会自动获取你的操作系统, 如
public static void main(String[] args) {
System.out.println(System.getProperty("os.name"));
}
输出结果:
Windows 7
application.yml:
server:
port: 8080
spring:
resources:
static-locations: classpath:/templates #访问静态页面
# 防止因linux系统文件结构不同造成错误.根据操作系统的不同上传到不同的目录
file:
uploadWindow: c:/myFile/
uploadLinux: /usr/myFile/
index.html:需要注意上传条件的“三要素” :enctype,method,type
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>批量文件上传</title>
</head>
<body>
<!--<form action="/upload/singleFile" enctype="multipart/form-data" method="post">-->
<form action="/upload/multiFile" enctype="multipart/form-data" method="post">
<p>文件1:<input type="file" name="file" /></p>
<p>文件2:<input type="file" name="file" /></p>
<p><input type="submit" value="上传" /></p>
</form>
</body>
</html>
FileUtils:
/**
* @author
* @Desoription : 文件上传工具类
*/
@Component
public class FileUtils {
@Value("${file.uploadWindow}")
private String UPLOAD_WINDOW;
@Value("${file.uploadLinux}")
private String UPLOAD_LINUX;
public String singleFile(MultipartFile file) {
if (Objects.isNull(file) || file.isEmpty()) {
return "文件为空!";
}
try {
byte[] bytes = file.getBytes();
String UPLOAD_FOLDER;
//若当前系统是window系统
if(System.getProperty("os.name").toLowerCase().contains("windows")) {
UPLOAD_FOLDER = UPLOAD_WINDOW;
}else{
//若当前系统是linux系统
UPLOAD_FOLDER = UPLOAD_LINUX;
}
//File.separator表示分隔符
//file.getOriginalFilename()表示文件全名(包括后缀名)
Path path = Paths.get(UPLOAD_FOLDER + File.separator + getFilename(file.getOriginalFilename()));
//如果没有此文件夹,则创建
if (!Files.isWritable(path)) {
Files.createDirectories(Paths.get(UPLOAD_FOLDER));
}
//文件写入指定路径
Files.write(path, bytes);
//若上传成功
return "上传成功";
} catch (IOException e) {
//若发生异常
return "发生异常";
}
}
/**
* 上传多个文件
*
* @return string
* @param: file 和标签name对应,否则无响应
*/
public String multiFile(MultipartFile[] file) {
try {
for (int i = 0; i < file.length; i++) {
if (file[i] != null) {
singleFile(file[i]);
}
}
return "上传成功";
} catch (Exception e) {
return e.getMessage();
}
}
/**
* 设置文件名,防止相同文件名冲突
* 原名称+时间(年月日)+后缀
* @param originalFilename 原名称
* @return string
*/
private String getFilename(String originalFilename) {
//后缀名 如 .txt
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
//后缀名之前的名称
String prefix = originalFilename.substring(0, originalFilename.lastIndexOf("."));
DateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
// 将此时时间转换为字符串
String formatDate = format.format(new Date());
// 拼接文件名
String filename = new StringBuffer().append(prefix).append("_").append(formatDate).append(suffix).toString();
return filename;
}
}
FileController:
/**
* @author
* @Desoription :文件上传controller
*/
@RestController
public class FileController {
@Autowired
private FileUtils fileUtils;
@RequestMapping(value = "/upload/singleFile", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public String singleFile(MultipartFile file){
return fileUtils.singleFile(file);
}
@RequestMapping(value = "/upload/multiFile", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public String multiFile(MultipartFile[] file){
return fileUtils.multiFile(file);
}
}
实现效果
打开页面,
选择文件,
点击上传
欢迎留言探讨!