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
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);
|
|
}
|
|
}
|
|
}
|