java Springboot + Vue 文件上传

java Springboot + Vue 文件上传

前端

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
<input type="file" accept="application/pdf"
class="mt-4"
@change="onFileChange"/>

<button @click="upload" :disabled="!selectedFile || uploading"
class="mt-4 bg-blue-600 hover:bg-blue-700 disabled:bg-blue-300
text-white text-sm font-medium px-6 py-2 rounded">
{{ uploading ? '上传中…' : '开始上传' }}
</button>

<p v-if="message" class="mt-3 text-sm"
:class="ok ? 'text-green-600' : 'text-red-600'">
{{ message }}
</p>


<script>
const {createApp, ref} = Vue;
createApp({
setup() {
const selectedFile = ref(null);
const uploading = ref(false);
const message = ref('');
const ok = ref(false);

function onFileChange(e) {
selectedFile.value = e.target.files[0];
message.value = '';
}

async function upload() {
if (!selectedFile.value) return;
uploading.value = true;
message.value = '';

const form = new FormData();
form.append('file', selectedFile.value); // 字段名必须和后端 @RequestParam("file") 一致

try {
const res = await fetch('/upload', {
method: 'POST',
body: form
// 注意:不要手动设 Content-Type,浏览器会自动带 boundary
});
const data = await res.json();
if (data.code === 0) {
ok.value = true;
message.value = '上传成功,PID = ' + data.pid;
setTimeout(() => {
location.reload();
}, 1000);
} else {
ok.value = false;
message.value = data.msg || '上传失败';
}
} catch (e) {
ok.value = false;
message.value = '网络错误:' + e.message;
} finally {
uploading.value = false;
}
}

return {selectedFile, uploading, message, ok, onFileChange, upload};
}
}).mount('#app');
</script>

后端

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
@RestController
@RequestMapping("/upload")
public class UploadController {

@Autowired
private PdfMapper pdfMapper;

private String uploadDir = "./pdf";

/**
* 上传 PDF
* 前端:<input type="file" name="file" accept="application/pdf">
* 用 FormData 提交,字段名必须是 "file"
*/
@PostMapping
public Map<String, Object> upload(@RequestParam("file") MultipartFile file,
HttpSession session) throws IOException {
System.out.println("上传文件: " + file.getOriginalFilename());
Map<String, Object> resp = new HashMap<>();

// 1. 基本校验
if (file.isEmpty()) {
resp.put("code", 1);
resp.put("msg", "请选择文件");
return resp;
}
String originalName = file.getOriginalFilename();
if (originalName == null || !originalName.toLowerCase().endsWith(".pdf")) {
resp.put("code", 1);
resp.put("msg", "只允许上传 PDF 文件");
return resp;
}

// 2. 准备目录 ./pdf/
Path dirPath = Paths.get(uploadDir).toAbsolutePath().normalize();
if (!Files.exists(dirPath)) {
Files.createDirectories(dirPath);
}

// 3. 生成 uuid 文件名,保留 .pdf 后缀
String uuidName = UUID.randomUUID().toString().replace("-", "") + ".pdf";
Path target = dirPath.resolve(uuidName);

// 4. 落盘
file.transferTo(target.toFile());

// 5. 写数据库
Pdf pdf = new Pdf();
pdf.setUuidName(uuidName);
pdf.setRealName(originalName);
pdf.setFilePath(target.toString()); // 绝对路径,方便后续读取
pdf.setFileSize(file.getSize());
pdf.setMimeType(file.getContentType());
pdf.setParseStatus(0); // 待 AI 解析
pdfMapper.insert(pdf);

resp.put("code", 0);
resp.put("msg", "上传成功");
resp.put("pid", pdf.getPid());
resp.put("realName", originalName);
return resp;
}
}

java Springboot + Vue 文件上传
https://taylorandtony.github.io/2026/10/19/java-Springboot-Vue-文件上传/
作者
TaylorAndTony
发布于
2026年10月19日
许可协议