一、文件上传

(1)后台代码

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
package com.yyzy.controller; // 声明包名

import org.springframework.web.bind.annotation.*; // 导入Spring框架的注解
import org.springframework.web.multipart.MultipartFile; // 导入处理文件上传的类
import java.io.File; // 导入File类
import java.io.IOException; // 导入IO异常类
import java.util.UUID; // 导入UUID类,用于生成唯一标识符

@RestController // 表明该类是一个RESTful控制器
public class FileUploadController {

// 递归删除目录及其所有子文件和子目录
public void deleteDirectory(File directory) {
if (directory.isDirectory()) { // 判断是否为目录
for (File sub : directory.listFiles()) { // 遍历目录中的所有文件和子目录
deleteDirectory(sub); // 递归调用删除子文件和子目录
}
}
directory.delete(); // 删除目录或文件
}

// 处理文件上传的POST请求
@PostMapping("/upload") // 映射上传文件的URL路径
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
System.out.println("进入文件上传"); // 打印日志
if (file.isEmpty()) { // 检查文件是否为空
return "Please select a file to upload."; // 返回提示信息
}
try {
byte[] bytes = file.getBytes(); // 获取文件的字节数据
String uploadDir = "D:\\项目单\\图书管理系统\\Library\\src\\main\\resources\\file\\"; // 设置上传目录的路径
File creatfile = new File(uploadDir); // 创建指向上传目录的File对象

// 删除路径及其所有内容(被注释掉的部分)
// if (creatfile.exists()) {
// System.out.println("删除签前");
// deleteDirectory(creatfile);
// System.out.println("删除签后");
// }

// 创建路径,如果不存在
if (!creatfile.exists()) {
creatfile.mkdirs(); // 创建目录
}

UUID uuid = UUID.randomUUID(); // 生成一个随机的UUID

File uploadedFile = new File(uploadDir + uuid + ".png"); // 创建上传文件的File对象

System.out.println(uploadedFile); // 打印上传文件的路径
file.transferTo(uploadedFile); // 将上传的文件保存到指定的路径
System.out.println("成功文件上传"); // 打印日志
return "File uploaded successfully!"; // 返回成功上传的信息
} catch (IOException e) { // 捕获IO异常
e.printStackTrace(); // 打印异常堆栈信息
return "File upload failed!"; // 返回文件上传失败的信息
}
}
}

(2)前台代码

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
<template>
<!-- el-upload 组件,用于文件上传 -->
<div>
<el-upload
class="upload-demo"
action="http://localhost:8081/upload" <!-- 上传文件的后端接口地址 -->
:on-preview="handlePreview" <!-- 文件预览触发的函数 -->
:on-remove="handleRemove" <!-- 文件移除触发的函数 -->
:before-remove="beforeRemove" <!-- 文件移除前触发的函数,返回一个布尔值,决定是否执行移除操作 -->
multiple <!-- 允许选择多个文件 -->
:limit="3" <!-- 文件数量限制 -->
:on-exceed="handleExceed" <!-- 文件超过数量限制时触发的函数 -->
:file-list="fileList"> <!-- 文件列表数据 -->
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png 文件,且不超过 500kb</div>
</el-upload>
</div>
</template>

<script>
export default {
data() {
return {
fileList: [ <!-- 文件列表初始数据 -->
{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'},
{name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}
]
};
},
methods: {
handleRemove(file, fileList) { <!-- 文件移除触发的函数,打印移除的文件和文件列表 -->
console.log(file, fileList);
},
handlePreview(file) { <!-- 文件预览触发的函数,打印预览的文件 -->
console.log(file);
},
handleExceed(files, fileList) { <!-- 文件超过数量限制时触发的函数,打印警告信息 -->
this.$message.warning(`当前限制选择 3 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);
},
beforeRemove(file, fileList) { <!-- 文件移除前触发的函数,弹出确认框 -->
return this.$confirm(`确定移除 ${ file.name }?`);
}
}
}
</script>

注意

前端代码中确实没有显式地传递 file 参数,但这是因为 el-upload 组件会自动处理文件上传的细节,包括将文件作为 multipart/form-data 请求的一部分发送到后端。

在 Element UI 的 el-upload 组件中,action 属性指定了上传文件的目标 URL,el-upload 组件会自动将选择的文件作为 multipart/form-data 请求的主体发送到指定的 URL。这个过程中,文件数据会被自动包含在请求中,并作为 file 参数传递给后端。

因此,尽管在前端代码中没有显式地看到传递 file 参数的代码,但实际上 el-upload 组件会处理这一切。您只需要确保 action 属性指向的后端接口地址是正确的,并且后端接口能够正确接收和处理这个文件参数。

以下是确保前端和后端正确配合的一些关键点:

  1. 前端 action 属性:确保 action 属性指向正确的后端接口地址,例如 http://localhost:8081/upload
  2. 后端接口参数:确保后端接口方法的参数使用 @RequestParam("file") MultipartFile file 接收文件数据。
1
2
3
4
@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
// 处理文件上传逻辑
}
  1. 文件类型和大小限制:虽然前端做了文件类型和大小的限制,但最好在后端也进行相应的验证,以确保安全性。
1
2
3
if (file.isEmpty() || file.getSize() > 500 * 1024) {
return "File is empty or exceeds the size limit.";
}
  1. CORS 配置:如果您在本地开发环境中遇到跨域问题,请确保您的后端配置了 CORS(跨源资源共享)支持。
1
2
3
4
5
@CrossOrigin(origins = "http://localhost:8080")
@RestController
public class FileUploadController {
// 其他代码
}

二、文件下载

(1)后端代码

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
package com.yyzy.controller;

import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;

@Controller // 定义为控制器类
public class FileDownloadController {

private static final String FILE_DIRECTORY = "D:\\项目单\\图书管理系统\\Library\\src\\main\\resources\\file\\"; // 文件目录

@GetMapping("/download/{fileName:.+}") // 处理 /download/{fileName} 的 GET 请求
@ResponseBody // 将响应体作为方法返回值
public ResponseEntity<Resource> downloadFile(@PathVariable String fileName) {
// 获取文件路径,将请求中的文件名与文件目录组合
Path filePath = Paths.get(FILE_DIRECTORY).resolve(fileName).normalize();
try {
Resource resource = new org.springframework.core.io.UrlResource(filePath.toUri());
// 创建资源对象
if (resource.exists() || resource.isReadable()) {
// 检查资源是否存在且可读
return ResponseEntity.ok()
// 返回 200 响应
.contentType(MediaType.APPLICATION_OCTET_STREAM)
// 设置内容类型为二进制流
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
// 设置下载文件的文件名
.body(resource);
// 返回资源
} else {
return ResponseEntity.notFound().build();
// 如果资源不存在或不可读,返回 404 响应
}
} catch (IOException ex) {
ex.printStackTrace();
// 打印异常信息
return ResponseEntity.status(500).build();
// 发生异常时返回 500 响应
}
}
}