一、单个或者批量上传文件
前端:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文件上传示例</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
line-height: 1.6;
}
button {
padding: 10px 15px;
background-color: #4CAF50;
color: white;
border: none;
cursor: pointer;
font-size: 16px;
}
button:hover {
background-color: #45a049;
}
#result {
margin-top: 20px;
padding: 10px;
border: 1px solid #ddd;
background-color: #f9f9f9;
}
</style>
</head>
<body>
<h1>文件上传</h1>
<h2>单个文件上传</h2>
<form id="singleUploadForm">
<input type="file" id="singleFileInput" name="file" required>
<button type="button" onclick="uploadSingleFile()">上传文件</button>
</form>
<h2>批量文件上传</h2>
<form id="batchUploadForm">
<input type="file" id="batchFileInput" name="files" multiple required>
<button type="button" onclick="uploadBatchFiles()">上传文件</button>
</form>
<div id="result"></div>
<script>
function uploadSingleFile() {
const fileInput = document.getElementById('singleFileInput');
const file = fileInput.files[0];
if (!file) {
alert('请选择一个文件');
return;
}
const formData = new FormData();
formData.append('file', file);
fetch('http://localhost:8888/test/uploadFile', {
method: 'POST',
body: formData
})
.then(response => response.text())
.then(data => {
document.getElementById('result').innerHTML = data;
})
.catch(error => {
document.getElementById('result').innerHTML = '上传失败: ' + error.message;
});
}
function uploadBatchFiles() {
const fileInput = document.getElementById('batchFileInput');
const files = fileInput.files;
if (!files || files.length === 0) {
alert('请选择至少一个文件');
return;
}
const formData = new FormData();
for (let i = 0; i < files.length; i++) {
formData.append('files', files[i]);
}
fetch('http://localhost:8888/test/uploadFiles', {
method: 'POST',
body: formData
})
.then(response => response.text())
.then(data => {
document.getElementById('result').innerHTML = data;
})
.catch(error => {
document.getElementById('result').innerHTML = '上传失败: ' + error.message;
});
}
</script>
</body>
</html>

后端:
java
@PostMapping("test/uploadFile")
public String upload(@RequestParam("file") MultipartFile file) {
try {
// 指定保存路径
String savePath = "C:\\Users\\test\\Desktop\\";
// 获取原始文件名
String originalFilename = file.getOriginalFilename();
if (originalFilename == null || originalFilename.isEmpty()) {
return "文件名不能为空!";
}
// 构建完整路径
Path targetPath = Paths.get(savePath + originalFilename);
// 确保目录存在
Files.createDirectories(targetPath.getParent());
// 保存文件(替换已存在文件)
Files.copy(file.getInputStream(), targetPath, StandardCopyOption.REPLACE_EXISTING);
return "文件上传成功!保存路径: " + targetPath.toString();
} catch (IOException e) {
e.printStackTrace();
return "文件上传失败: " + e.getMessage();
}
}
@PostMapping("/test/uploadFiles")
public String uploadFiles(@RequestParam("files") MultipartFile[] files) {
try {
String savePath = "C:\\Users\\test\\Desktop\\";
List<String> uploadedFiles = Arrays.stream(files)
.map(file -> {
try {
String originalFilename = file.getOriginalFilename();
if (originalFilename == null || originalFilename.isEmpty()) {
return "文件名不能为空!";
}
Path targetPath = Paths.get(savePath + originalFilename);
Files.createDirectories(targetPath.getParent());
Files.copy(file.getInputStream(), targetPath, StandardCopyOption.REPLACE_EXISTING);
return "文件上传成功!保存路径: " + targetPath.toString();
} catch (IOException e) {
return "文件上传失败: " + e.getMessage();
}
})
.collect(Collectors.toList());
return String.join("<br>", uploadedFiles);
} catch (Exception e) {
e.printStackTrace();
return "文件上传失败: " + e.getMessage();
}
}
springboot要配置下文件上传大小限制:
properties
# 设置单个文件的最大上传大小 (默认是1M)
spring.servlet.multipart.max-file-size=50MB
# 设置请求中所有文件的最大上传大小 (默认是10M)
spring.servlet.multipart.max-request-size=1000MB
二、后端上传文件
小文件处理,全部加载到内存
java
@GetMapping("/test/backUpload")
public void backUpload() {
String uploadUrl = "http://localhost:8888/test/uploadFile";
String sourcePath = "C:\\Users\\test\\Desktop\\ttt\\666.txt";
Path filePath = Paths.get(sourcePath);
if (!Files.exists(filePath)) {
System.out.println("文件不存在!");
return;
}
try {
byte[] fileBytes = Files.readAllBytes(filePath); // NIO读取文件内容到byte数组
ByteArrayResource resource = new ByteArrayResource(fileBytes) {
@Override
public String getFilename() {
return filePath.getFileName().toString();
}
};
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file", resource);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
ResponseEntity<String> response = new RestTemplate().postForEntity(uploadUrl, requestEntity, String.class);
System.out.println("上传结果:" + response.getBody());
} catch (IOException e) {
e.printStackTrace();
}
}
大文件处理使用webflux流式处理
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
java
@GetMapping("/test/backUploadNew")
public void backUploadNew() {
String uploadUrl = "http://localhost:8888/test/uploadFile";
String sourcePath = "C:\\Users\\test\\Desktop\\ttt\\666.txt";
Path filePath = Paths.get(sourcePath);
if (!Files.exists(filePath)) {
System.out.println("文件不存在!");
return;
}
try {
InputStream inputStream = Files.newInputStream(filePath);
InputStreamResource resource = new InputStreamResource(inputStream) {
@Override
public String getFilename() {
return filePath.getFileName().toString();
}
@Override
public long contentLength() throws IOException {
return Files.size(filePath);
}
};
MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("file", resource)
.header("Content-Disposition", "form-data; name=file; filename=" + filePath.getFileName());
HttpClient httpClient = HttpClient.create();
ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
WebClient webClient = WebClient.builder()
.clientConnector(connector)
.build();
webClient.method(HttpMethod.POST)
.uri(uploadUrl)
.contentType(MediaType.MULTIPART_FORM_DATA)
.bodyValue(builder.build())
.retrieve()
.bodyToMono(String.class)
.doOnNext(result -> System.out.println("上传结果:" + result))
.block(); // 等待上传完成
} catch (IOException e) {
e.printStackTrace();
}
}
三、前端下载文件
前端直接访问接口 /test/download 下载
java
@GetMapping("/test/download")
public void download(HttpServletResponse response) throws IOException {
// 文件路径
Path filePath = Paths.get("C:\\Users\\test\\Desktop\\哈哈+ +c.txt"); // 替换成你的实际路径
if (Files.exists(filePath)) {
response.setContentType("application/octet-stream");
String fileName = filePath.getFileName().toString();
// 处理中文文件名:防止下载时乱码
String encodedFileName = java.net.URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-Disposition",
"attachment; filename=\"" + new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1) + "\"; filename*=UTF-8''" + encodedFileName);
// 直接用 Files.copy,拷贝文件到 response 的输出流
Files.copy(filePath, response.getOutputStream());
response.flushBuffer(); // 刷新缓冲区,确保数据发出去
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND, "文件未找到!");
}
}
四、后端下载文件
java
@GetMapping("/test/backDownload")
public void backDownload() {
String url = "http://localhost:8888/test/download";
String destinationPath = "C:\\Users\\test\\Desktop\\ttt\\666.txt";
try {
ResponseEntity<Resource> response = new RestTemplate().getForEntity(url, Resource.class);
if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
Path path = Paths.get(destinationPath);
Files.createDirectories(path.getParent()); // 确保父目录存在
Files.copy(response.getBody().getInputStream(), path);
System.out.println("下载完成!");
} else {
System.out.println("下载失败,状态码:" + response.getStatusCode());
}
} catch (IOException e) {
e.printStackTrace();
}
}