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 defaultHeaders; private final Map 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 defaultHeaders, Map 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 customHeaders, Map customParams) throws IOException, UploadException { // 验证文件 validateFile(excelFile); try { // 准备请求 HttpEntity> requestEntity = prepareRequest(excelFile, targetDir, customHeaders, customParams); // 执行上传 ResponseEntity 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> prepareRequest(File file, String targetDir, Map customHeaders, Map customParams) { // 设置请求头 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); // 添加默认和自定义请求头 defaultHeaders.forEach(headers::set); customHeaders.forEach(headers::set); // 准备请求体 MultiValueMap 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 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); } } }