You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

200 lines
7.0 KiB

package com.example.demo.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.*;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
/**
* Excel文件上传工具类
*/
public class ExcelUploadUtil {
private static final Logger logger = LoggerFactory.getLogger(ExcelUploadUtil.class);
// 默认配置
private static final int DEFAULT_CONNECT_TIMEOUT = 30000; // 30秒
private static final int DEFAULT_READ_TIMEOUT = 60000; // 60秒
private final RestTemplate restTemplate;
private final String uploadUrl;
private final Map<String, String> defaultHeaders;
private final Map<String, String> defaultParams;
/**
* 构造方法
*
* @param uploadUrl 上传接口URL
*/
public ExcelUploadUtil(String uploadUrl) {
this(uploadUrl, new HashMap<>(), new HashMap<>());
}
/**
* 构造方法
*
* @param uploadUrl 上传接口URL
* @param defaultHeaders 默认请求头
* @param defaultParams 默认请求参数
*/
public ExcelUploadUtil(String uploadUrl, Map<String, String> defaultHeaders, Map<String, String> defaultParams) {
this.uploadUrl = uploadUrl;
this.defaultHeaders = new HashMap<>(defaultHeaders);
this.defaultParams = new HashMap<>(defaultParams);
this.restTemplate = createRestTemplate(DEFAULT_CONNECT_TIMEOUT, DEFAULT_READ_TIMEOUT);
}
/**
* 创建RestTemplate (Spring Boot 1.x 兼容版本)
*/
private RestTemplate createRestTemplate(int connectTimeout, int readTimeout) {
RestTemplate restTemplate = new RestTemplate();
// 添加字符串消息转换器 (Spring 1.x 使用Charset而不是StandardCharsets)
restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
// 设置超时 (Spring 1.x 方式)
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(connectTimeout);
factory.setReadTimeout(readTimeout);
restTemplate.setRequestFactory(factory);
return restTemplate;
}
/**
* 上传Excel文件
*
* @param excelFile Excel文件
* @param targetDir 目标目录
* @return 上传结果
* @throws IOException 文件操作异常
* @throws UploadException 上传异常
*/
public String uploadExcel(File excelFile, String targetDir) throws IOException, UploadException {
return uploadExcel(excelFile, targetDir, new HashMap<>(), new HashMap<>());
}
/**
* 上传Excel文件(带自定义参数)
*
* @param excelFile Excel文件
* @param targetDir 目标目录
* @param customHeaders 自定义请求头
* @param customParams 自定义请求参数
* @return 上传结果
* @throws IOException 文件操作异常
* @throws UploadException 上传异常
*/
public String uploadExcel(File excelFile, String targetDir,
Map<String, String> customHeaders,
Map<String, String> customParams) throws IOException, UploadException {
// 验证文件
validateFile(excelFile);
try {
// 准备请求
HttpEntity<MultiValueMap<String, Object>> requestEntity = prepareRequest(excelFile, targetDir, customHeaders, customParams);
// 执行上传
ResponseEntity<String> response = restTemplate.exchange(
uploadUrl,
HttpMethod.POST,
requestEntity,
String.class
);
// 处理响应
return handleResponse(response, excelFile.getName());
} catch (Exception e) {
logger.error("Excel文件上传失败: {}", excelFile.getAbsolutePath(), e);
throw new UploadException("文件上传失败: " + e.getMessage(), e);
}
}
/**
* 验证文件
*/
private void validateFile(File file) throws IOException {
if (file == null) {
throw new IOException("文件不能为null");
}
if (!file.exists()) {
throw new IOException("文件不存在: " + file.getAbsolutePath());
}
if (!file.isFile()) {
throw new IOException("不是有效的文件: " + file.getAbsolutePath());
}
if (file.length() == 0) {
throw new IOException("文件内容为空: " + file.getAbsolutePath());
}
if (!file.getName().toLowerCase().endsWith(".xlsx") &&
!file.getName().toLowerCase().endsWith(".xls")) {
throw new IOException("仅支持Excel文件(.xlsx, .xls)");
}
}
/**
* 准备请求
*/
private HttpEntity<MultiValueMap<String, Object>> prepareRequest(File file, String targetDir,
Map<String, String> customHeaders,
Map<String, String> customParams) {
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
// 添加默认和自定义请求头
defaultHeaders.forEach(headers::set);
customHeaders.forEach(headers::set);
// 准备请求体
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file", new FileSystemResource(file));
body.add("dir", targetDir);
// 添加默认和自定义参数
defaultParams.forEach(body::add);
customParams.forEach(body::add);
return new HttpEntity<>(body, headers);
}
/**
* 处理响应
*/
private String handleResponse(ResponseEntity<String> response, String filename) throws UploadException {
if (response.getStatusCode() == HttpStatus.OK) {
logger.info("文件上传成功: {}", filename);
return response.getBody();
} else {
String errorMsg = String.format("上传接口返回错误状态码: %d, 响应: %s",
response.getStatusCodeValue(), response.getBody());
logger.error(errorMsg);
throw new UploadException(errorMsg);
}
}
/**
* 自定义上传异常
*/
public static class UploadException extends Exception {
public UploadException(String message) {
super(message);
}
public UploadException(String message, Throwable cause) {
super(message, cause);
}
}
}