import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
public class ExcelUploadService {
private final WebClient webClient;
public ExcelUploadService(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder.build();
}
/**
* 上传Excel文件到第三方接口 - 使用Multipart方式
* @param workbook Excel工作簿对象
* @param fileName 文件名
* @param uploadUrl 上传接口URL
* @return 上传结果
*/
public Mono<String> uploadExcelFile(org.apache.poi.ss.usermodel.Workbook workbook,
String fileName, String uploadUrl) {
return Mono.fromCallable(() -> {
// 将Workbook转换为字节数组
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
byte[] fileBytes = outputStream.toByteArray();
outputStream.close();
return fileBytes;
})
.flatMap(fileBytes -> {
// 创建Multipart表单数据
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<>();
ByteArrayResource fileResource = new ByteArrayResource(fileBytes) {
@Override
public String getFilename() {
return fileName;
}
};
formData.add("file", fileResource);
formData.add("filename", fileName);
return webClient.post()
.uri(uploadUrl)
.contentType(MediaType.MULTIPART_FORM_DATA)
.bodyValue(formData) // 这里是正确的用法
.retrieve()
.bodyToMono(String.class)
.onErrorMap(WebClientResponseException.class, ex ->
new RuntimeException("上传失败: " + ex.getResponseBodyAsString(), ex));
});
}
/**
* 使用BodyInserters.multipartData的方式上传
*/
public Mono<String> uploadExcelWithBodyInserters(org.apache.poi.ss.usermodel.Workbook workbook,
String fileName, String uploadUrl) {
return Mono.fromCallable(() -> {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
return outputStream.toByteArray();
})
.flatMap(fileBytes -> {
ByteArrayResource fileResource = new ByteArrayResource(fileBytes) {
@Override
public String getFilename() {
return fileName;
}
};
var multipartBuilder = BodyInserters
.fromMultipartData("file", fileResource)
.with("filename", fileName);
return webClient.post()
.uri(uploadUrl)
.body(multipartBuilder)
.retrieve()
.bodyToMono(String.class);
});
}
/**
* 使用Base64编码的方式上传
*/
public Mono<String> uploadExcelAsBase64(org.apache.poi.ss.usermodel.Workbook workbook,
String fileName, String uploadUrl) {
return Mono.fromCallable(() -> {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
byte[] fileBytes = outputStream.toByteArray();
String base64Content = Base64.getEncoder().encodeToString(fileBytes);
return base64Content;
})
.flatMap(base64Content -> {
var requestObject = new UploadRequest();
requestObject.setFileName(fileName);
requestObject.setFileContent(base64Content);
requestObject.setFileType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
return webClient.post()
.uri(uploadUrl)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(requestObject) // JSON请求体
.retrieve()
.bodyToMono(String.class);
});
}
// 上传请求对象
static class UploadRequest {
private String fileName;
private String fileContent;
private String fileType;
// Getters and Setters
public String getFileName() { return fileName; }
public void setFileName(String fileName) { this.fileName = fileName; }
public String getFileContent() { return fileContent; }
public void setFileContent(String fileContent) { this.fileContent = fileContent; }
public String getFileType() { return fileType; }
public void setFileType(String fileType) { this.fileType = fileType; }
}
}
======================================
// 使用示例
public class Example {
public static void main(String[] args) {
// 假设你已经有了Workbook对象和文件名
Workbook workbook = ...; // 你的POI Workbook对象
String fileName = "example.xlsx";
String uploadUrl = "https://api.example.com/upload";
ExcelUploadService uploadService = new ExcelUploadService("https://api.example.com");
// 上传文件
uploadService.uploadExcelFile(workbook, fileName, uploadUrl)
.subscribe(
response -> System.out.println("上传成功: " + response),
error -> System.err.println("上传失败: " + error.getMessage())
);
}
}
=====================================
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.MediaType;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.mock.web.reactive.function.multipart.DefaultFilePart;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import io.netty.handler.codec.http.multipart.HttpData;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class ExcelUploadService {
private final WebClient webClient;
public ExcelUploadService(String baseUrl) {
this.webClient = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(
HttpClient.create().responseTimeout(Duration.ofMinutes(5))
))
.build();
}
/**
* 上传Excel文件到第三方接口
* @param workbook POI Workbook对象
* @param fileName 文件名
* @param uploadUrl 上传接口URL
* @return 响应结果
*/
public Mono<String> uploadExcelFile(Workbook workbook, String fileName, String uploadUrl) {
return Mono.fromCallable(() -> {
// 将Workbook转换为字节数组
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
byte[] fileBytes = outputStream.toByteArray();
outputStream.close();
return fileBytes;
})
.flatMap(fileBytes -> {
// 创建WebClient请求
return webClient.post()
.uri(uploadUrl)
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromMultipartData()
.part("file",
org.springframework.core.io.ByteArrayResource(fileBytes, fileName))
.part("filename", fileName))
.retrieve()
.bodyToMono(String.class);
});
}
/**
* 使用ReactiveHttpClient的另一种实现方式
*/
public Mono<String> uploadExcelWithReactiveClient(Workbook workbook, String fileName, String uploadUrl) {
try {
// 将Workbook转换为字节数组
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
byte[] fileBytes = outputStream.toByteArray();
// 使用WebClient构建multipart请求
return webClient.post()
.uri(uploadUrl)
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromValue(
MultipartBodyBuilder()
.part("file", new org.springframework.core.io.ByteArrayResource(fileBytes) {
@Override
public String getFilename() {
return fileName;
}
})
.part("fileName", fileName)
.build()
))
.retrieve()
.bodyToMono(String.class);
} catch (IOException e) {
return Mono.error(e);
}
}
/**
* 更完整的上传实现,包含错误处理和进度监控
*/
public Mono<UploadResponse> uploadExcelWithProgress(Workbook workbook, String fileName, String uploadUrl) {
return Mono.fromCallable(() -> {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
return outputStream.toByteArray();
})
.flatMap(fileBytes -> {
return webClient.post()
.uri(uploadUrl)
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromMultipartData(builder -> {
builder.part("file",
new org.springframework.core.io.ByteArrayResource(fileBytes) {
@Override
public String getFilename() {
return fileName;
}
})
.part("originalFileName", fileName)
.part("size", String.valueOf(fileBytes.length));
}))
.retrieve()
.onStatus(HttpStatus::isError, clientResponse -> {
return clientResponse.bodyToMono(String.class)
.flatMap(errorBody -> Mono.error(
new UploadException("Upload failed: " + errorBody)
));
})
.bodyToMono(String.class)
.map(responseBody -> UploadResponse.success(responseBody))
.onErrorMap(UploadException.class, ex -> ex)
.onErrorMap(Exception.class, ex -> new UploadException("Upload error", ex));
});
}
// 响应包装类
public static class UploadResponse {
private boolean success;
private String message;
private Object data;
public static UploadResponse success(String message) {
UploadResponse response = new UploadResponse();
response.success = true;
response.message = message;
return response;
}
public static UploadResponse error(String message) {
UploadResponse response = new UploadResponse();
response.success = false;
response.message = message;
return response;
}
// 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 Object getData() { return data; }
public void setData(Object data) { this.data = data; }
}
// 自定义异常类
public static class UploadException extends Exception {
public UploadException(String message) {
super(message);
}
public UploadException(String message, Throwable cause) {
super(message, cause);
}
}
}