|
|
|
@ -11,6 +11,8 @@ import org.springframework.http.client.SimpleClientHttpRequestFactory; |
|
|
|
import org.springframework.stereotype.Component; |
|
|
|
import org.springframework.util.LinkedMultiValueMap; |
|
|
|
import org.springframework.util.MultiValueMap; |
|
|
|
import org.springframework.util.StringUtils; |
|
|
|
import org.springframework.web.client.HttpClientErrorException; |
|
|
|
import org.springframework.web.client.RestTemplate; |
|
|
|
|
|
|
|
import javax.annotation.PostConstruct; |
|
|
|
@ -36,6 +38,12 @@ public class FileUploadUtil { |
|
|
|
@Value("${ftp-sync.oss.base-url:http://53.1.211.7:8090}") |
|
|
|
private String ossBaseUrl; |
|
|
|
|
|
|
|
@Value("${ftp-sync.oss.upload-max-attempts:3}") |
|
|
|
private int uploadMaxAttempts; |
|
|
|
|
|
|
|
@Value("${ftp-sync.oss.upload-retry-delay-ms:1000}") |
|
|
|
private long uploadRetryDelayMs; |
|
|
|
|
|
|
|
private RestTemplate restTemplate; |
|
|
|
|
|
|
|
@PostConstruct |
|
|
|
@ -56,6 +64,10 @@ public class FileUploadUtil { |
|
|
|
* @return 完整的文件访问URL |
|
|
|
*/ |
|
|
|
public String uploadWav(String ossPath, String fileName, byte[] fileData) { |
|
|
|
if (fileData == null || fileData.length == 0) { |
|
|
|
throw new IllegalArgumentException("待上传录音文件为空: " + fileName); |
|
|
|
} |
|
|
|
|
|
|
|
String path = "voice/" + ossPath; |
|
|
|
if (fileName != null && !fileName.isEmpty() && path.endsWith(fileName)) { |
|
|
|
path = path.substring(0, path.length() - fileName.length()); |
|
|
|
@ -65,6 +77,38 @@ public class FileUploadUtil { |
|
|
|
} |
|
|
|
logger.debug("上传文件到OSS, path={}, 大小={} bytes", path, fileData.length); |
|
|
|
|
|
|
|
int attempts = Math.max(1, uploadMaxAttempts); |
|
|
|
Exception lastError = null; |
|
|
|
for (int attempt = 1; attempt <= attempts; attempt++) { |
|
|
|
try { |
|
|
|
return doUpload(path, fileName, fileData); |
|
|
|
} catch (HttpClientErrorException e) { |
|
|
|
// 4xx通常是文件大小、权限或请求参数问题,重试无意义。
|
|
|
|
logger.error("OSS拒绝上传,不再重试: fileName={}, status={}", fileName, e.getStatusCode()); |
|
|
|
throw new RuntimeException("文件上传失败: " + e.getMessage(), e); |
|
|
|
} catch (Exception e) { |
|
|
|
lastError = e; |
|
|
|
if (attempt >= attempts) { |
|
|
|
break; |
|
|
|
} |
|
|
|
long delay = Math.max(0L, uploadRetryDelayMs) * attempt; |
|
|
|
logger.warn("OSS上传失败,准备重试: fileName={}, attempt={}/{}, delay={}ms, 原因={}", |
|
|
|
fileName, attempt, attempts, delay, e.getMessage()); |
|
|
|
try { |
|
|
|
Thread.sleep(delay); |
|
|
|
} catch (InterruptedException interrupted) { |
|
|
|
Thread.currentThread().interrupt(); |
|
|
|
throw new RuntimeException("OSS上传重试被中断", interrupted); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
logger.error("OSS上传最终失败: fileName={}, attempts={}", fileName, attempts, lastError); |
|
|
|
throw new RuntimeException("文件上传失败: " |
|
|
|
+ (lastError == null ? "未知异常" : lastError.getMessage()), lastError); |
|
|
|
} |
|
|
|
|
|
|
|
private String doUpload(String path, String fileName, byte[] fileData) { |
|
|
|
try { |
|
|
|
HttpHeaders headers = new HttpHeaders(); |
|
|
|
headers.setContentType(MediaType.MULTIPART_FORM_DATA); |
|
|
|
@ -99,6 +143,7 @@ public class FileUploadUtil { |
|
|
|
Map<?, ?> map = JSON.parseObject(responseBody, Map.class); |
|
|
|
if (map != null && (map.containsKey("fileUrl") || map.containsKey("url"))) { |
|
|
|
String fileUrl = parseFileUrl(responseBody); |
|
|
|
validateFileUrl(fileUrl, fileName); |
|
|
|
logger.info("文件上传完成 (扁平格式), URL: {}", fileUrl); |
|
|
|
return fileUrl; |
|
|
|
} |
|
|
|
@ -111,6 +156,7 @@ public class FileUploadUtil { |
|
|
|
ResultEntity result = JSON.parseObject(responseBody, ResultEntity.class); |
|
|
|
if (result != null && result.getCode() != null && result.getCode() == ResultEntity.StatusCode.SUCCESS.getCode()) { |
|
|
|
String fileUrl = parseFileUrl(result.getContent()); |
|
|
|
validateFileUrl(fileUrl, fileName); |
|
|
|
logger.info("文件上传完成 (包装格式), URL: {}", fileUrl); |
|
|
|
return fileUrl; |
|
|
|
} else { |
|
|
|
@ -127,6 +173,12 @@ public class FileUploadUtil { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void validateFileUrl(String fileUrl, String fileName) { |
|
|
|
if (!StringUtils.hasText(fileUrl)) { |
|
|
|
throw new RuntimeException("OSS上传成功但未返回文件地址: " + fileName); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 从响应 content 中解析 fileUrl |
|
|
|
* |
|
|
|
|