mirror of
https://gitee.com/kekingcn/file-online-preview.git
synced 2026-04-08 09:17:36 +00:00
5.0版本 发布 优化下载方法 修复office 重复转换方法错误
This commit is contained in:
@@ -67,7 +67,10 @@ public class OfficeFilePreviewImpl implements FilePreview {
|
|||||||
String outFilePath = fileAttribute.getOutFilePath(); //转换后生成文件的路径
|
String outFilePath = fileAttribute.getOutFilePath(); //转换后生成文件的路径
|
||||||
|
|
||||||
// 查询转换状态
|
// 查询转换状态
|
||||||
checkAndHandleConvertStatus(model, fileName, cacheName,fileAttribute);
|
String convertStatusResult = checkAndHandleConvertStatus(model, fileName, cacheName, fileAttribute);
|
||||||
|
if (convertStatusResult != null) {
|
||||||
|
return convertStatusResult;
|
||||||
|
}
|
||||||
|
|
||||||
if (!officePreviewType.equalsIgnoreCase("html")) {
|
if (!officePreviewType.equalsIgnoreCase("html")) {
|
||||||
if (ConfigConstants.getOfficeTypeWeb().equalsIgnoreCase("web")) {
|
if (ConfigConstants.getOfficeTypeWeb().equalsIgnoreCase("web")) {
|
||||||
@@ -307,9 +310,11 @@ public class OfficeFilePreviewImpl implements FilePreview {
|
|||||||
/**
|
/**
|
||||||
* 异步方法
|
* 异步方法
|
||||||
*/
|
*/
|
||||||
public String checkAndHandleConvertStatus(Model model, String fileName, String cacheName, FileAttribute fileAttribute){
|
public String checkAndHandleConvertStatus(Model model, String fileName, String cacheName, FileAttribute fileAttribute) {
|
||||||
FileConvertStatusManager.ConvertStatus status = FileConvertStatusManager.getConvertStatus(cacheName);
|
FileConvertStatusManager.ConvertStatus status = FileConvertStatusManager.getConvertStatus(cacheName);
|
||||||
int refreshSchedule = ConfigConstants.getTime();
|
int refreshSchedule = ConfigConstants.getTime();
|
||||||
|
boolean forceUpdatedCache = fileAttribute.forceUpdatedCache();
|
||||||
|
|
||||||
if (status != null) {
|
if (status != null) {
|
||||||
if (status.getStatus() == FileConvertStatusManager.Status.CONVERTING) {
|
if (status.getStatus() == FileConvertStatusManager.Status.CONVERTING) {
|
||||||
// 正在转换中,返回等待页面
|
// 正在转换中,返回等待页面
|
||||||
@@ -318,11 +323,27 @@ public class OfficeFilePreviewImpl implements FilePreview {
|
|||||||
model.addAttribute("message", status.getRealTimeMessage());
|
model.addAttribute("message", status.getRealTimeMessage());
|
||||||
return WAITING_FILE_PREVIEW_PAGE;
|
return WAITING_FILE_PREVIEW_PAGE;
|
||||||
} else if (status.getStatus() == FileConvertStatusManager.Status.TIMEOUT) {
|
} else if (status.getStatus() == FileConvertStatusManager.Status.TIMEOUT) {
|
||||||
// 超时状态,不允许重新转换
|
// 超时状态,检查是否有强制更新命令
|
||||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "文件转换已超时,无法继续转换");
|
if (forceUpdatedCache) {
|
||||||
|
// 强制更新命令,清除状态,允许重新转换
|
||||||
|
FileConvertStatusManager.convertSuccess(cacheName);
|
||||||
|
logger.info("强制更新命令跳过超时状态,允许重新转换: {}", cacheName);
|
||||||
|
return null; // 返回null表示继续执行
|
||||||
|
} else {
|
||||||
|
// 没有强制更新,不允许重新转换
|
||||||
|
return otherFilePreview.notSupportedFile(model, fileAttribute, "文件转换已超时,无法继续转换");
|
||||||
|
}
|
||||||
} else if (status.getStatus() == FileConvertStatusManager.Status.FAILED) {
|
} else if (status.getStatus() == FileConvertStatusManager.Status.FAILED) {
|
||||||
// 失败状态,不允许重新转换
|
// 失败状态,检查是否有强制更新命令
|
||||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "文件转换失败,无法继续转换");
|
if (forceUpdatedCache) {
|
||||||
|
// 强制更新命令,清除状态,允许重新转换
|
||||||
|
FileConvertStatusManager.convertSuccess(cacheName);
|
||||||
|
logger.info("强制更新命令跳过失败状态,允许重新转换: {}", cacheName);
|
||||||
|
return null; // 返回null表示继续执行
|
||||||
|
} else {
|
||||||
|
// 没有强制更新,不允许重新转换
|
||||||
|
return otherFilePreview.notSupportedFile(model, fileAttribute, "文件转换失败,无法继续转换");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -7,8 +7,18 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import com.fasterxml.jackson.databind.type.TypeFactory;
|
import com.fasterxml.jackson.databind.type.TypeFactory;
|
||||||
import io.mola.galimatias.GalimatiasParseException;
|
import io.mola.galimatias.GalimatiasParseException;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
|
||||||
|
import org.apache.hc.client5.http.config.ConnectionConfig;
|
||||||
|
import org.apache.hc.client5.http.config.RequestConfig;
|
||||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||||
|
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
||||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||||
|
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||||
|
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
|
||||||
|
import org.apache.hc.core5.http.HttpResponse;
|
||||||
|
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||||
|
import org.apache.hc.core5.util.TimeValue;
|
||||||
|
import org.apache.hc.core5.util.Timeout;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
@@ -27,6 +37,7 @@ import java.nio.file.StandardCopyOption;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static cn.keking.utils.KkFileUtils.*;
|
import static cn.keking.utils.KkFileUtils.*;
|
||||||
|
|
||||||
@@ -41,10 +52,56 @@ public class DownloadUtils {
|
|||||||
private static final String URL_PARAM_FTP_PASSWORD = "ftp.password";
|
private static final String URL_PARAM_FTP_PASSWORD = "ftp.password";
|
||||||
private static final String URL_PARAM_FTP_CONTROL_ENCODING = "ftp.control.encoding";
|
private static final String URL_PARAM_FTP_CONTROL_ENCODING = "ftp.control.encoding";
|
||||||
private static final String URL_PARAM_FTP_PORT = "ftp.control.port";
|
private static final String URL_PARAM_FTP_PORT = "ftp.control.port";
|
||||||
private static final RestTemplate restTemplate = new RestTemplate();
|
|
||||||
private static final HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
|
|
||||||
private static final ObjectMapper mapper = new ObjectMapper();
|
private static final ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
|
// 使用静态单例的HttpClient和RestTemplate,实现连接复用
|
||||||
|
private static volatile CloseableHttpClient httpClient;
|
||||||
|
private static volatile RestTemplate restTemplate;
|
||||||
|
|
||||||
|
// 获取单例HttpClient(线程安全)
|
||||||
|
private static CloseableHttpClient getHttpClient() throws Exception {
|
||||||
|
if (httpClient == null) {
|
||||||
|
synchronized (DownloadUtils.class) {
|
||||||
|
if (httpClient == null) {
|
||||||
|
httpClient = createConfiguredHttpClient();
|
||||||
|
logger.info("HttpClient初始化完成,已启用连接池和超时配置");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取单例RestTemplate
|
||||||
|
private static RestTemplate getRestTemplate() throws Exception {
|
||||||
|
if (restTemplate == null) {
|
||||||
|
synchronized (DownloadUtils.class) {
|
||||||
|
if (restTemplate == null) {
|
||||||
|
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
|
||||||
|
factory.setHttpClient(getHttpClient());
|
||||||
|
|
||||||
|
// 设置连接和读取超时(毫秒)
|
||||||
|
factory.setConnectTimeout(10000); // 10秒连接超时
|
||||||
|
factory.setReadTimeout(30000); // 30秒读取超时
|
||||||
|
factory.setConnectionRequestTimeout(5000); // 5秒获取连接超时
|
||||||
|
|
||||||
|
restTemplate = new RestTemplate(factory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return restTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用关闭时清理资源
|
||||||
|
public static void shutdown() {
|
||||||
|
if (httpClient != null) {
|
||||||
|
try {
|
||||||
|
httpClient.close();
|
||||||
|
logger.info("HttpClient已关闭");
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.warn("关闭HttpClient失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param fileAttribute fileAttribute
|
* @param fileAttribute fileAttribute
|
||||||
@@ -61,7 +118,8 @@ public class DownloadUtils {
|
|||||||
}
|
}
|
||||||
ReturnResponse<String> response = new ReturnResponse<>(0, "下载成功!!!", "");
|
ReturnResponse<String> response = new ReturnResponse<>(0, "下载成功!!!", "");
|
||||||
String realPath = getRelFilePath(fileName, fileAttribute);
|
String realPath = getRelFilePath(fileName, fileAttribute);
|
||||||
|
// 获取文件后缀用于校验
|
||||||
|
final String fileSuffix = fileAttribute.getSuffix();
|
||||||
// 判断是否非法地址
|
// 判断是否非法地址
|
||||||
if (KkFileUtils.isIllegalFileName(realPath)) {
|
if (KkFileUtils.isIllegalFileName(realPath)) {
|
||||||
response.setCode(1);
|
response.setCode(1);
|
||||||
@@ -92,11 +150,8 @@ public class DownloadUtils {
|
|||||||
if (isHttpUrl(url)) {
|
if (isHttpUrl(url)) {
|
||||||
File realFile = new File(realPath);
|
File realFile = new File(realPath);
|
||||||
|
|
||||||
// 创建配置好的HttpClient
|
// 使用单例的RestTemplate,复用连接池
|
||||||
CloseableHttpClient httpClient = createConfiguredHttpClient();
|
RestTemplate template = getRestTemplate();
|
||||||
|
|
||||||
factory.setHttpClient(httpClient);
|
|
||||||
restTemplate.setRequestFactory(factory);
|
|
||||||
String finalUrlStr = urlStr;
|
String finalUrlStr = urlStr;
|
||||||
RequestCallback requestCallback = request -> {
|
RequestCallback requestCallback = request -> {
|
||||||
request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
|
request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
|
||||||
@@ -111,10 +166,41 @@ public class DownloadUtils {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
restTemplate.execute(url.toURI(), HttpMethod.GET, requestCallback, fileResponse -> {
|
final boolean[] hasError = {false};
|
||||||
FileUtils.copyToFile(fileResponse.getBody(), realFile);
|
String finalUrlStr1 = urlStr;
|
||||||
|
template.execute(url.toURI(), HttpMethod.GET, requestCallback, fileResponse -> {
|
||||||
|
try {
|
||||||
|
// 获取响应头中的Content-Type
|
||||||
|
String contentType = WebUtils.headersType(fileResponse);
|
||||||
|
|
||||||
|
// 如果是Office/设计文件,需要校验MIME类型
|
||||||
|
if ( WebUtils.isMimeCheckRequired(fileSuffix)) {
|
||||||
|
if (! WebUtils.isValidMimeType(contentType, fileSuffix)) {
|
||||||
|
logger.error("文件类型错误,期望二进制文件但接收到文本类型,url: {}, Content-Type: {}",
|
||||||
|
finalUrlStr1, contentType);
|
||||||
|
hasError[0] = true;
|
||||||
|
// 重要:关闭响应流,不读取后续数据
|
||||||
|
fileResponse.close();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存文件
|
||||||
|
FileUtils.copyToFile(fileResponse.getBody(), realFile);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("处理文件响应时出错", e);
|
||||||
|
hasError[0] = true;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 如果下载过程中出现错误
|
||||||
|
if (hasError[0]) {
|
||||||
|
response.setCode(1);
|
||||||
|
response.setContent(null);
|
||||||
|
response.setMsg("文件类型校验失败");
|
||||||
|
return response;
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// 如果是SSL证书错误,给出建议
|
// 如果是SSL证书错误,给出建议
|
||||||
if (e.getMessage() != null &&
|
if (e.getMessage() != null &&
|
||||||
@@ -126,16 +212,10 @@ public class DownloadUtils {
|
|||||||
}
|
}
|
||||||
response.setCode(1);
|
response.setCode(1);
|
||||||
response.setContent(null);
|
response.setContent(null);
|
||||||
response.setMsg("下载失败:" + e);
|
response.setMsg("下载失败:" + e.getMessage());
|
||||||
return response;
|
return response;
|
||||||
} finally {
|
|
||||||
// 确保HttpClient被关闭
|
|
||||||
try {
|
|
||||||
httpClient.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.warn("关闭HttpClient失败", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// 不再需要finally块中关闭HttpClient,因为复用
|
||||||
} else if (isFtpUrl(url)) {
|
} else if (isFtpUrl(url)) {
|
||||||
String ftpUsername = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_USERNAME);
|
String ftpUsername = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_USERNAME);
|
||||||
String ftpPassword = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_PASSWORD);
|
String ftpPassword = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_PASSWORD);
|
||||||
@@ -153,7 +233,7 @@ public class DownloadUtils {
|
|||||||
response.setMsg(fileName);
|
response.setMsg(fileName);
|
||||||
return response;
|
return response;
|
||||||
} catch (IOException | GalimatiasParseException e) {
|
} catch (IOException | GalimatiasParseException e) {
|
||||||
logger.error("文件下载失败,url:{}", urlStr);
|
logger.error("文件下载失败,url:{}", urlStr, e);
|
||||||
response.setCode(1);
|
response.setCode(1);
|
||||||
response.setContent(null);
|
response.setContent(null);
|
||||||
if (e instanceof FileNotFoundException) {
|
if (e instanceof FileNotFoundException) {
|
||||||
@@ -163,22 +243,53 @@ public class DownloadUtils {
|
|||||||
}
|
}
|
||||||
return response;
|
return response;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
logger.error("下载过程发生未知异常", e);
|
||||||
|
response.setCode(1);
|
||||||
|
response.setContent(null);
|
||||||
|
response.setMsg("下载失败:" + e.getMessage());
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建根据配置定制的HttpClient
|
* 创建根据配置定制的HttpClient(连接池版本)
|
||||||
*/
|
*/
|
||||||
private static CloseableHttpClient createConfiguredHttpClient() throws Exception {
|
private static CloseableHttpClient createConfiguredHttpClient() throws Exception {
|
||||||
org.apache.hc.client5.http.impl.classic.HttpClientBuilder builder = HttpClients.custom();
|
// 使用新的Builder API创建连接池管理器
|
||||||
|
PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
|
||||||
|
.setMaxConnTotal(100) // 最大连接数
|
||||||
|
.setMaxConnPerRoute(20) // 每个路由最大连接数
|
||||||
|
.setDefaultConnectionConfig(ConnectionConfig.custom()
|
||||||
|
.setConnectTimeout(Timeout.ofSeconds(10)) // 连接超时10秒
|
||||||
|
.setSocketTimeout(Timeout.ofSeconds(30)) // Socket超时30秒
|
||||||
|
.setTimeToLive(TimeValue.ofMinutes(10)) // 连接存活时间10分钟
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 创建请求配置
|
||||||
|
RequestConfig requestConfig = RequestConfig.custom()
|
||||||
|
.setResponseTimeout(Timeout.ofSeconds(30)) // 响应超时30秒
|
||||||
|
.setConnectionRequestTimeout(Timeout.ofSeconds(5)) // 获取连接超时5秒
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 创建HttpClientBuilder
|
||||||
|
HttpClientBuilder builder = HttpClients.custom()
|
||||||
|
.setConnectionManager(connectionManager)
|
||||||
|
.setDefaultRequestConfig(requestConfig);
|
||||||
|
|
||||||
|
// 配置Keep-Alive策略
|
||||||
|
ConnectionKeepAliveStrategy keepAliveStrategy = (response, context) -> {
|
||||||
|
// 默认保持30秒
|
||||||
|
return TimeValue.ofSeconds(30);
|
||||||
|
};
|
||||||
|
builder.setKeepAliveStrategy(keepAliveStrategy);
|
||||||
|
|
||||||
// 配置SSL
|
// 配置SSL
|
||||||
if (ConfigConstants.isIgnoreSSL()) {
|
if (ConfigConstants.isIgnoreSSL()) {
|
||||||
logger.debug("创建忽略SSL验证的HttpClient");
|
logger.debug("创建忽略SSL验证的HttpClient");
|
||||||
// 如果SslUtils有创建builder的方法就更好了,这里假设我们直接使用SslUtils
|
// 如果SslUtils支持HttpClient5,则使用它来创建client
|
||||||
// 或者我们可以创建一个新的方法来返回配置了忽略SSL的builder
|
// 否则,我们需要在这里配置忽略SSL
|
||||||
return createHttpClientWithConfig();
|
return createHttpClientWithConfig(builder);
|
||||||
} else {
|
} else {
|
||||||
logger.debug("创建标准HttpClient");
|
logger.debug("创建标准HttpClient");
|
||||||
}
|
}
|
||||||
@@ -195,10 +306,17 @@ public class DownloadUtils {
|
|||||||
/**
|
/**
|
||||||
* 创建配置了忽略SSL的HttpClient
|
* 创建配置了忽略SSL的HttpClient
|
||||||
*/
|
*/
|
||||||
private static CloseableHttpClient createHttpClientWithConfig() throws Exception {
|
private static CloseableHttpClient createHttpClientWithConfig(HttpClientBuilder builder) throws Exception {
|
||||||
return SslUtils.createHttpClientIgnoreSsl();
|
// 如果SslUtils支持直接配置builder,则:
|
||||||
}
|
// SslUtils.configureIgnoreSsl(builder);
|
||||||
|
// return builder.build();
|
||||||
|
|
||||||
|
// 否则,使用SslUtils创建client
|
||||||
|
CloseableHttpClient sslIgnoredClient = SslUtils.createHttpClientIgnoreSsl();
|
||||||
|
|
||||||
|
logger.warn("SslUtils.createHttpClientIgnoreSsl()可能没有连接池配置,建议修改SslUtils以支持builder配置");
|
||||||
|
return sslIgnoredClient;
|
||||||
|
}
|
||||||
|
|
||||||
// 处理file协议的文件下载
|
// 处理file协议的文件下载
|
||||||
private static void handleFileProtocol(URL url, String targetPath) throws IOException {
|
private static void handleFileProtocol(URL url, String targetPath) throws IOException {
|
||||||
@@ -280,5 +398,4 @@ public class DownloadUtils {
|
|||||||
}
|
}
|
||||||
return realPath;
|
return realPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,8 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.client.ClientHttpResponse;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.util.HtmlUtils;
|
import org.springframework.web.util.HtmlUtils;
|
||||||
@@ -461,6 +463,78 @@ public class WebUtils {
|
|||||||
return parts;
|
return parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Content-Type
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static String headersType(ClientHttpResponse fileResponse) {
|
||||||
|
if (fileResponse == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
HttpHeaders headers = fileResponse.getHeaders();
|
||||||
|
if (headers == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String contentTypeStr = null;
|
||||||
|
try {
|
||||||
|
// 直接获取Content-Type头字符串
|
||||||
|
contentTypeStr = headers.getFirst(HttpHeaders.CONTENT_TYPE);
|
||||||
|
if (contentTypeStr == null || contentTypeStr.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 解析为MediaType对象
|
||||||
|
MediaType mediaType = MediaType.parseMediaType(contentTypeStr);
|
||||||
|
// 返回主类型和子类型,忽略参数
|
||||||
|
return mediaType.getType() + "/" + mediaType.getSubtype();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 如果解析失败,尝试简单的字符串处理
|
||||||
|
if (contentTypeStr != null) {
|
||||||
|
// 移除分号及后面的参数
|
||||||
|
int semicolonIndex = contentTypeStr.indexOf(';');
|
||||||
|
if (semicolonIndex > 0) {
|
||||||
|
return contentTypeStr.substring(0, semicolonIndex).trim();
|
||||||
|
}
|
||||||
|
return contentTypeStr.trim();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断文件是否需要校验MIME类型
|
||||||
|
* @param suffix 文件后缀
|
||||||
|
* @return 是否需要校验
|
||||||
|
*/
|
||||||
|
public static boolean isMimeCheckRequired(String suffix) {
|
||||||
|
if (suffix == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String lowerSuffix = suffix.toLowerCase();
|
||||||
|
return Arrays.asList(
|
||||||
|
"doc", "docx", "ppt", "pptx", "pdf", "dwg",
|
||||||
|
"dxf", "dwf", "psd", "wps", "xlsx", "xls",
|
||||||
|
"rar", "zip"
|
||||||
|
).contains(lowerSuffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验文件MIME类型是否有效
|
||||||
|
* @param contentType 响应头中的Content-Type
|
||||||
|
* @param suffix 文件后缀
|
||||||
|
* @return 是否有效
|
||||||
|
*/
|
||||||
|
public static boolean isValidMimeType(String contentType, String suffix) {
|
||||||
|
if (contentType == null || suffix == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果检测到是HTML、文本或JSON格式,则认为是错误响应
|
||||||
|
String lowerContentType = contentType.toLowerCase();
|
||||||
|
return !lowerContentType.contains("text/html")
|
||||||
|
&& !lowerContentType.contains("text/plain")
|
||||||
|
&& !lowerContentType.contains("application/json");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支持basic 下载方法
|
* 支持basic 下载方法
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -60,8 +60,7 @@
|
|||||||
9. 新增 防重复转换 <br>
|
9. 新增 防重复转换 <br>
|
||||||
10. 新增 异步等待 <br>
|
10. 新增 异步等待 <br>
|
||||||
11. 新增 上传限制不支持的文件禁止上传 <br>
|
11. 新增 上传限制不支持的文件禁止上传 <br>
|
||||||
12. 新增 异步等待 <br>
|
12. 新增 cadviewer转换方法<br>
|
||||||
13. 新增 cadviewer转换方法<br>
|
|
||||||
<h4>修复</h4>
|
<h4>修复</h4>
|
||||||
1. 压缩包路径问题 <br>
|
1. 压缩包路径问题 <br>
|
||||||
2. 安全问题 <br>
|
2. 安全问题 <br>
|
||||||
|
|||||||
Reference in New Issue
Block a user