日光、空气和清水,锻炼身体三件宝。——佚名

使用 HTML FormData 发送文件及 Spring Boot 接收与转发的实践

在现代 Web 开发中,处理文件上传是一个常见需求。本文将分享一个完整的解决方案,包括使用 HTML FormData 发送文件和 Spring Boot 接收及转发的实现。


前端部分:使用 FormData 实现文件上传

以下是 HTML 和 JavaScript 代码示例,用于选择文件并通过 FormData 将其发送到服务器。

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Upload</title>
</head>
<body>
<h1>File Upload with Base64 Encoding</h1>
<form id="uploadForm">
<label for="audioFile">Select Audio File (wav):</label><br>
<input type="file" id="audioFile" name="audio" accept="audio/wav"><br><br>

<label for="imageFile">Select Image File (jpg):</label><br>
<input type="file" id="imageFile" name="image" accept="image/jpeg"><br><br>

<button type="button" onclick="sendFiles()">Upload</button>
</form>

<script>
async function sendFiles() {
const audioFile = document.getElementById('audioFile').files[0];
const imageFile = document.getElementById('imageFile').files[0];

if (!audioFile || !imageFile) {
alert('Please select both files.');
return;
}

const formData = new FormData();
formData.append('audio', audioFile);
formData.append('device_id', "ddd");

try {
const imageBase64 = await convertFileToBase64(imageFile);
const base64Clean = imageBase64.split(',')[1];
formData.append('image', base64Clean);

const response = await fetch('http://127.0.0.1:11010/chat_server', {
method: 'POST',
body: formData,
});

if (!response.ok) {
const errorText = await response.text();
throw new Error(`Server responded with ${response.status}: ${errorText}`);
}

const result = await response.json();
console.log(`Upload successful: ${JSON.stringify(result)}`);
} catch (error) {
console.error('Error:', error);
alert(`Upload failed: ${error.message}`);
}
}

function convertFileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(file);
});
}
</script>
</body>
</html>

说明

  • FormData 用于构建要发送到服务器的键值对。
  • FileReader 用于将图像文件转换为 Base64 编码。
  • 文件通过 fetch POST 到指定的 Spring Boot 服务器端点。

后端部分:Spring Boot 接收并转发文件

以下是后端的 Spring Boot 实现代码。该代码接收文件后,将文件及其他参数转发到目标服务。

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("/chat_server")
public class ChatController {

@PostMapping
public ResponseEntity<Map<String, Object>> forwardFiles(
@RequestParam("audio") MultipartFile audioFile,
@RequestParam("image") String imageBase64,
@RequestParam("device_id") String device_id) {

Map<String, Object> response = new HashMap<>();
try {
var targetResponse = forwardToTargetService(audioFile, imageBase64, device_id);
if (targetResponse.getStatusCode().is2xxSuccessful()) {
response.put("message", "Files forwarded successfully");
response.put("targetResponse", targetResponse.getBody());
return ResponseEntity.ok(response);
} else {
response.put("message", "Error forwarding files to target service");
return ResponseEntity.status(targetResponse.getStatusCode()).body(response);
}
} catch (Exception e) {
response.put("message", "Error: " + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
}
}

private ResponseEntity<List<String>> forwardToTargetService(
MultipartFile audioFile, String imageBase64, String device_id) throws Exception {

RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);

MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("audio", new MultipartFileResource(audioFile));
body.add("image", imageBase64);

HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
String TARGET_URL = "http://127.0.0.1:8200/chat_server?device_id=" + device_id;

return restTemplate.exchange(
TARGET_URL,
HttpMethod.POST,
requestEntity,
new ParameterizedTypeReference<>() {}
);
}

private static class MultipartFileResource extends org.springframework.core.io.ByteArrayResource {
private final MultipartFile file;

public MultipartFileResource(MultipartFile file) throws Exception {
super(file.getBytes());
this.file = file;
}

@Override
public String getFilename() {
return this.file.getOriginalFilename();
}
}
}

关键点

  1. 接收数据

    • 使用 @RequestParam 注解接收 MultipartFile 和其他参数。
    • 图像以 Base64 编码字符串形式传递。
  2. 转发数据

    • 通过 RestTemplate 将接收到的文件和参数转发到目标服务。
    • 自定义 MultipartFileResource 以适配 Spring 的资源接口。
  3. 目标服务 URL

    • 转发目标地址 http://127.0.0.1:8200/chat_server

总结

  • 前端使用 FormData 方便地组织并发送文件和其他数据。
  • 后端通过 Spring Boot 灵活接收和转发文件,满足不同场景需求。

这套实现适合需要在前后端协作下处理复杂文件上传的场景,如音频处理、图片识别等。