import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.MediaType;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.http.codec.multipart.FormFieldPart;
import org.springframework.http.codec.multipart.MultipartBody;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import java.io.File;
import java.nio.file.Path;
@SpringBootApplication
public class FileUploadApplication {
public static void main(String[] args) {
SpringApplication.run(FileUploadApplication.class, args);
}
}
@Service
class FileUploadService {
private final WebClient webClient;
public FileUploadService() {
this.webClient = WebClient.builder()
.baseUrl("https://api.example.com") // 替换为实际的第三方接口地址
.build();
}
/**
* 上传单个文件
* @param filePath 文件路径
* @param fieldName 表单字段名
* @return 上传结果
*/
public Mono<String> uploadFile(String filePath, String fieldName) {
FileSystemResource fileResource = new FileSystemResource(new File(filePath));
MultipartBody.Builder multipartBuilder = MultipartBody.builder()
.part(fieldName, fileResource)
.build();
return webClient.post()
.uri("/upload") // 替换为实际的上传接口路径
.contentType(MediaType.MULTIPART_FORM_DATA)
.bodyValue(multipartBuilder)
.retrieve()
.bodyToMono(String.class);
}
/**
* 上传文件并携带其他表单参数
* @param filePath 文件路径
* @param fieldName 文件字段名
* @param additionalParams 额外参数
* @return 上传结果
*/
public Mono<String> uploadFileWithParams(String filePath, String fieldName,
java.util.Map<String, String> additionalParams) {
FileSystemResource fileResource = new FileSystemResource(new File(filePath));
MultipartBody.Builder multipartBuilder = MultipartBody.builder()
.part(fieldName, fileResource);
// 添加额外的表单参数
if (additionalParams != null) {
for (java.util.Map.Entry<String, String> entry : additionalParams.entrySet()) {
multipartBuilder.part(entry.getKey(), BodyInserters.fromValue(entry.getValue()));
}
}
MultipartBody multipartBody = multipartBuilder.build();
return webClient.post()
.uri("/upload") // 替换为实际的上传接口路径
.contentType(MediaType.MULTIPART_FORM_DATA)
.bodyValue(multipartBody)
.retrieve()
.bodyToMono(String.class);
}
/**
* 上传多个文件
* @param filePaths 文件路径列表
* @param fieldName 文件字段名(通常为数组形式,如 files[])
* @return 上传结果
*/
public Mono<String> uploadMultipleFiles(java.util.List<String> filePaths, String fieldName) {
MultipartBody.Builder multipartBuilder = MultipartBody.builder();
for (String filePath : filePaths) {
FileSystemResource fileResource = new FileSystemResource(new File(filePath));
multipartBuilder.part(fieldName, fileResource);
}
MultipartBody multipartBody = multipartBuilder.build();
return webClient.post()
.uri("/upload") // 替换为实际的上传接口路径
.contentType(MediaType.MULTIPART_FORM_DATA)
.bodyValue(multipartBody)
.retrieve()
.bodyToMono(String.class);
}
/**
* 上传文件并接收响应对象
* @param filePath 文件路径
* @param fieldName 字段名
* @return 上传响应
*/
public Mono<UploadResponse> uploadFileWithResponse(String filePath, String fieldName) {
FileSystemResource fileResource = new FileSystemResource(new File(filePath));
MultipartBody multipartBody = MultipartBody.builder()
.part(fieldName, fileResource)
.build();
return webClient.post()
.uri("/upload")
.contentType(MediaType.MULTIPART_FORM_DATA)
.bodyValue(multipartBody)
.retrieve()
.bodyToMono(UploadResponse.class);
}
}
// 上传响应数据类
class UploadResponse {
private boolean success;
private String message;
private String fileId;
private String downloadUrl;
// 构造函数
public UploadResponse() {}
public UploadResponse(boolean success, String message, String fileId, String downloadUrl) {
this.success = success;
this.message = message;
this.fileId = fileId;
this.downloadUrl = downloadUrl;
}
// Getter 和 Setter 方法
public boolean isSuccess() { return success; }
public void setSuccess(boolean success) { this.success = success; }
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
public String getFileId() { return fileId; }
public void setFileId(String fileId) { this.fileId = fileId; }
public String getDownloadUrl() { return downloadUrl; }
public void setDownloadUrl(String downloadUrl) { this.downloadUrl = downloadUrl; }
}
// 控制器示例
import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.multipart.FilePart;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/api")
class FileUploadController {
private final FileUploadService fileUploadService;
public FileUploadController(FileUploadService fileUploadService) {
this.fileUploadService = fileUploadService;
}
@PostMapping("/upload-to-third-party")
public Mono<ResponseEntity<String>> uploadFileToThirdParty(
@RequestParam String filePath,
@RequestParam(defaultValue = "file") String fieldName) {
return fileUploadService.uploadFile(filePath, fieldName)
.map(response -> ResponseEntity.ok(response))
.onErrorReturn(ResponseEntity.status(500).body("Upload failed"));
}
@PostMapping("/upload-multiple-to-third-party")
public Mono<ResponseEntity<String>> uploadMultipleFilesToThirdParty(
@RequestParam java.util.List<String> filePaths,
@RequestParam(defaultValue = "files[]") String fieldName) {
return fileUploadService.uploadMultipleFiles(filePaths, fieldName)
.map(response -> ResponseEntity.ok(response))
.onErrorReturn(ResponseEntity.status(500).body("Upload failed"));
}
}