Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yd-oss
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
xingmin
yd-oss
Commits
9d272e55
Commit
9d272e55
authored
Sep 10, 2026
by
zhangxingmin
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/dev' into prod
parents
09071518
1af53b23
Show whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
976 additions
and
47 deletions
+976
-47
yd-oss-api/Dockerfile
+14
-6
yd-oss-api/src/main/java/com/yd/oss/api/config/OfficeManagerHolder.java
+43
-0
yd-oss-api/src/main/java/com/yd/oss/api/controller/ApiChunkedUploadContextController.java
+51
-0
yd-oss-api/src/main/java/com/yd/oss/api/controller/ApiOssController.java
+20
-0
yd-oss-api/src/main/java/com/yd/oss/api/controller/DocumentConvertController.java
+98
-0
yd-oss-api/src/main/java/com/yd/oss/api/service/ApiChunkedUploadContextService.java
+12
-0
yd-oss-api/src/main/java/com/yd/oss/api/service/impl/ApiChunkedUploadContextServiceImpl.java
+265
-0
yd-oss-api/src/main/java/com/yd/oss/api/utils/LocalDocumentConversionService.java
+110
-0
yd-oss-api/yd-oss-api.iml
+34
-10
yd-oss-feign/src/main/java/com/yd/oss/feign/client/ApiChunkedUploadContextFeignClient.java
+45
-0
yd-oss-feign/src/main/java/com/yd/oss/feign/client/ApiOssFeignClient.java
+7
-4
yd-oss-feign/src/main/java/com/yd/oss/feign/fallback/ApiChunkedUploadContextFeignFallbackFactory.java
+32
-0
yd-oss-feign/src/main/java/com/yd/oss/feign/fallback/ApiExcelFeignFallbackFactory.java
+0
-1
yd-oss-feign/src/main/java/com/yd/oss/feign/fallback/ApiOssFeignFallbackFactory.java
+5
-0
yd-oss-feign/src/main/java/com/yd/oss/feign/request/ApiUploadFileRequest.java
+5
-0
yd-oss-feign/src/main/java/com/yd/oss/feign/response/ApiUploadResponse.java
+1
-1
yd-oss-feign/yd-oss-feign.iml
+6
-8
yd-oss-service/pom.xml
+25
-0
yd-oss-service/src/main/java/com/yd/oss/service/dao/ChunkedUploadContextMapper.java
+16
-0
yd-oss-service/src/main/java/com/yd/oss/service/dto/OssUploadFileReqDto.java
+5
-0
yd-oss-service/src/main/java/com/yd/oss/service/model/ChunkedUploadContext.java
+98
-0
yd-oss-service/src/main/java/com/yd/oss/service/service/IChunkedUploadContextService.java
+16
-0
yd-oss-service/src/main/java/com/yd/oss/service/service/impl/AliYunOssServiceImpl.java
+15
-5
yd-oss-service/src/main/java/com/yd/oss/service/service/impl/ChunkedUploadContextServiceImpl.java
+20
-0
yd-oss-service/src/main/java/com/yd/oss/service/utils/MyBatisPlusCodeGenerator.java
+1
-1
yd-oss-service/src/main/resources/mappers/ChunkedUploadContextMapper.xml
+5
-0
yd-oss-service/yd-oss-service.iml
+27
-11
No files found.
yd-oss-api/Dockerfile
View file @
9d272e55
# 构建阶段 - 创建包含LibreOffice的基础镜像
# ============================================================
FROM
openjdk:8-jre-slim as base-builder
# 构建阶段 - 创建包含 LibreOffice 的基础镜像
# ============================================================
FROM
eclipse-temurin:8-jre-jammy as base-builder
ENV
LANG=zh_CN.UTF-8 \
ENV
LANG=zh_CN.UTF-8 \
LANGUAGE=zh_CN:zh \
LANGUAGE=zh_CN:zh \
LC_ALL=zh_CN.UTF-8 \
LC_ALL=zh_CN.UTF-8 \
DEBIAN_FRONTEND=noninteractive
DEBIAN_FRONTEND=noninteractive
RUN
sed
-i
's/deb.debian.org/mirrors.aliyun.com/g'
/etc/apt/sources.list
&&
\
# 替换为阿里云 Ubuntu 源(jammy = 22.04)
sed
-i
's/security.debian.org/mirrors.aliyun.com/g'
/etc/apt/sources.list
RUN
sed
-i
's|archive.ubuntu.com|mirrors.aliyun.com|g'
/etc/apt/sources.list
&&
\
sed
-i
's|security.ubuntu.com|mirrors.aliyun.com|g'
/etc/apt/sources.list
# 安装字体、LibreOffice 及中文语言包
RUN
apt-get update
&&
\
RUN
apt-get update
&&
\
apt-get install
-y
--no-install-recommends
\
apt-get install
-y
--no-install-recommends
\
fonts-liberation
\
fonts-liberation
\
...
@@ -29,12 +33,15 @@ RUN apt-get update && \
...
@@ -29,12 +33,15 @@ RUN apt-get update && \
RUN
mkdir
-p
/home/app
RUN
mkdir
-p
/home/app
WORKDIR
/home/app
WORKDIR
/home/app
# ============================================================
# 最终阶段
# 最终阶段
# ============================================================
FROM
base-builder
FROM
base-builder
#
只拷贝jar包
#
拷贝 Spring Boot 可执行 JAR
COPY
target/yd-oss-api-1.0-SNAPSHOT-exec.jar /home/app/yd-oss-api.jar
COPY
target/yd-oss-api-1.0-SNAPSHOT-exec.jar /home/app/yd-oss-api.jar
#
执行命令启动jar,并设置JVM
内存参数
#
启动命令,设置 JVM
内存参数
ENTRYPOINT
["java", "-Xmx1024m", "-Xms512m", "-jar", "/home/app/yd-oss-api.jar"]
ENTRYPOINT
["java", "-Xmx1024m", "-Xms512m", "-jar", "/home/app/yd-oss-api.jar"]
EXPOSE
9106
EXPOSE
9106
\ No newline at end of file
yd-oss-api/src/main/java/com/yd/oss/api/config/OfficeManagerHolder.java
0 → 100644
View file @
9d272e55
package
com
.
yd
.
oss
.
api
.
config
;
import
org.jodconverter.core.office.OfficeManager
;
import
org.jodconverter.local.office.LocalOfficeManager
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
java.io.File
;
public
class
OfficeManagerHolder
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
OfficeManagerHolder
.
class
);
private
static
OfficeManager
instance
=
null
;
private
static
final
Object
lock
=
new
Object
();
public
static
OfficeManager
getInstance
(
String
libreOfficeHome
)
throws
Exception
{
if
(
instance
==
null
)
{
synchronized
(
lock
)
{
if
(
instance
==
null
)
{
logger
.
info
(
"正在启动 LibreOffice (home: {}) ..."
,
libreOfficeHome
);
instance
=
LocalOfficeManager
.
builder
()
.
officeHome
(
new
File
(
libreOfficeHome
))
.
build
();
instance
.
start
();
logger
.
info
(
"LibreOffice 启动成功"
);
}
}
}
return
instance
;
}
public
static
void
stop
()
{
if
(
instance
!=
null
)
{
try
{
instance
.
stop
();
logger
.
info
(
"LibreOffice 已停止"
);
}
catch
(
Exception
e
)
{
logger
.
error
(
"停止 LibreOffice 失败"
,
e
);
}
instance
=
null
;
}
}
}
\ No newline at end of file
yd-oss-api/src/main/java/com/yd/oss/api/controller/ApiChunkedUploadContextController.java
0 → 100644
View file @
9d272e55
package
com
.
yd
.
oss
.
api
.
controller
;
import
com.yd.common.result.Result
;
import
com.yd.oss.api.service.ApiChunkedUploadContextService
;
import
com.yd.oss.feign.client.ApiChunkedUploadContextFeignClient
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.multipart.MultipartFile
;
import
javax.annotation.Resource
;
import
java.util.Map
;
/**
* 分片上传上下文信息
* (一个任务上传文件信息拆分成多个ETag上传存储,任务执行完毕,阿里云合并ETag列表为完整的文件信息)
* @author zxm
* @since 2026-08-05
*/
@Slf4j
@RestController
@RequestMapping
(
"/chunkedUploadContext"
)
@Validated
public
class
ApiChunkedUploadContextController
implements
ApiChunkedUploadContextFeignClient
{
@Resource
private
ApiChunkedUploadContextService
apiChunkedUploadContextService
;
/**
* 上传单个分片
* @param chunk
* @param taskId
* @param chunkIndex
* @param projectBizId
* @param source
* @return
*/
@Override
public
Result
<
Void
>
uploadChunk
(
MultipartFile
chunk
,
String
taskId
,
Integer
chunkIndex
,
String
projectBizId
,
String
source
)
{
apiChunkedUploadContextService
.
uploadChunk
(
taskId
,
chunkIndex
,
chunk
,
projectBizId
,
source
);
return
Result
.
success
();
}
/**
* 完成分片上传(合并)
*/
public
Result
<
Map
<
String
,
Object
>>
finishChunks
(
String
taskId
,
String
projectBizId
)
{
return
apiChunkedUploadContextService
.
finishChunks
(
taskId
,
projectBizId
);
}
}
yd-oss-api/src/main/java/com/yd/oss/api/controller/ApiOssController.java
View file @
9d272e55
package
com
.
yd
.
oss
.
api
.
controller
;
package
com
.
yd
.
oss
.
api
.
controller
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.yd.common.result.Result
;
import
com.yd.common.result.Result
;
import
com.yd.oss.api.service.ApiOssService
;
import
com.yd.oss.api.service.ApiOssService
;
import
com.yd.oss.feign.client.ApiOssFeignClient
;
import
com.yd.oss.feign.client.ApiOssFeignClient
;
...
@@ -7,9 +8,13 @@ import com.yd.oss.feign.request.ApiUploadFileRequest;
...
@@ -7,9 +8,13 @@ import com.yd.oss.feign.request.ApiUploadFileRequest;
import
com.yd.oss.feign.response.ApiBatchUploadResponse
;
import
com.yd.oss.feign.response.ApiBatchUploadResponse
;
import
com.yd.oss.feign.response.ApiFileMetadataResponse
;
import
com.yd.oss.feign.response.ApiFileMetadataResponse
;
import
com.yd.oss.feign.response.ApiUploadResponse
;
import
com.yd.oss.feign.response.ApiUploadResponse
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.MediaType
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestPart
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.multipart.MultipartFile
;
import
org.springframework.web.multipart.MultipartFile
;
...
@@ -21,6 +26,7 @@ import java.util.List;
...
@@ -21,6 +26,7 @@ import java.util.List;
* @author zxm
* @author zxm
* @since 2025-07-31
* @since 2025-07-31
*/
*/
@Slf4j
@RestController
@RestController
@RequestMapping
(
"/oss"
)
@RequestMapping
(
"/oss"
)
@Validated
@Validated
...
@@ -29,6 +35,9 @@ public class ApiOssController implements ApiOssFeignClient {
...
@@ -29,6 +35,9 @@ public class ApiOssController implements ApiOssFeignClient {
@Autowired
@Autowired
private
ApiOssService
apiOssService
;
private
ApiOssService
apiOssService
;
@Autowired
private
ObjectMapper
objectMapper
;
/**
/**
* 上传文件
* 上传文件
* @param file 上传的文件
* @param file 上传的文件
...
@@ -50,6 +59,17 @@ public class ApiOssController implements ApiOssFeignClient {
...
@@ -50,6 +59,17 @@ public class ApiOssController implements ApiOssFeignClient {
return
apiOssService
.
uploadFileBody
(
file
,
request
);
return
apiOssService
.
uploadFileBody
(
file
,
request
);
}
}
public
Result
<
ApiUploadResponse
>
uploadFileBodyWithJson
(
MultipartFile
file
,
String
requestJson
)
{
try
{
// 反序列化 JSON 为 ApiUploadFileRequest
ApiUploadFileRequest
request
=
objectMapper
.
readValue
(
requestJson
,
ApiUploadFileRequest
.
class
);
return
apiOssService
.
uploadFileBody
(
file
,
request
);
}
catch
(
Exception
e
)
{
log
.
error
(
"解析请求参数失败"
,
e
);
return
Result
.
fail
(
"请求参数格式错误"
);
}
}
/**
/**
* 下载文件
* 下载文件
* @param fileKey 文件唯一标识
* @param fileKey 文件唯一标识
...
...
yd-oss-api/src/main/java/com/yd/oss/api/controller/DocumentConvertController.java
0 → 100644
View file @
9d272e55
package
com
.
yd
.
oss
.
api
.
controller
;
import
com.yd.oss.api.utils.LocalDocumentConversionService
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.web.bind.annotation.*
;
import
java.io.UnsupportedEncodingException
;
import
java.net.URLEncoder
;
import
java.nio.charset.StandardCharsets
;
/**
* 文档转换接口
* 提供将 Office 文档(Word/Excel/PPT)转换为 PDF/HTML/图片等格式的 HTTP 接口。
* 供其他微服务通过内网调用。
*/
@RestController
@RequestMapping
(
"/convert"
)
public
class
DocumentConvertController
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
DocumentConvertController
.
class
);
@Autowired
private
LocalDocumentConversionService
conversionService
;
/**
* 将指定 URL 的文档转换为目标格式,并返回字节流。
*
* @param fileUrl 源文件 URL(支持 HTTP/HTTPS/OSS)
* @param targetFormat 目标格式,如 pdf、html、png、jpg 等,默认 pdf
* @return 转换后的文件字节流,Content-Type 根据格式自动设置
*/
@PostMapping
(
"/file"
)
public
ResponseEntity
<
byte
[]>
convert
(
@RequestParam
(
"fileUrl"
)
String
fileUrl
,
@RequestParam
(
value
=
"targetFormat"
,
defaultValue
=
"pdf"
)
String
targetFormat
)
{
logger
.
info
(
"收到转换请求: fileUrl={}, targetFormat={}"
,
fileUrl
,
targetFormat
);
try
{
byte
[]
result
=
conversionService
.
convertToBytes
(
fileUrl
,
targetFormat
);
HttpHeaders
headers
=
new
HttpHeaders
();
// 根据目标格式设置 Content-Type
MediaType
mediaType
=
getMediaType
(
targetFormat
);
headers
.
setContentType
(
mediaType
);
// 可选:设置下载文件名
String
filename
=
extractFileName
(
fileUrl
)
+
"."
+
targetFormat
;
try
{
headers
.
setContentDispositionFormData
(
"attachment"
,
URLEncoder
.
encode
(
filename
,
StandardCharsets
.
UTF_8
.
name
()));
}
catch
(
UnsupportedEncodingException
e
)
{
// 忽略
}
logger
.
info
(
"转换成功,返回字节数: {}"
,
result
.
length
);
return
new
ResponseEntity
<>(
result
,
headers
,
HttpStatus
.
OK
);
}
catch
(
Exception
e
)
{
logger
.
error
(
"文档转换失败: fileUrl={}, targetFormat={}"
,
fileUrl
,
targetFormat
,
e
);
return
ResponseEntity
.
status
(
HttpStatus
.
INTERNAL_SERVER_ERROR
)
.
body
((
"转换失败: "
+
e
.
getMessage
()).
getBytes
(
StandardCharsets
.
UTF_8
));
}
}
private
MediaType
getMediaType
(
String
format
)
{
if
(
format
==
null
)
return
MediaType
.
APPLICATION_OCTET_STREAM
;
switch
(
format
.
toLowerCase
())
{
case
"pdf"
:
return
MediaType
.
APPLICATION_PDF
;
case
"html"
:
return
MediaType
.
TEXT_HTML
;
case
"png"
:
return
MediaType
.
IMAGE_PNG
;
case
"jpg"
:
case
"jpeg"
:
return
MediaType
.
IMAGE_JPEG
;
default
:
return
MediaType
.
APPLICATION_OCTET_STREAM
;
}
}
private
String
extractFileName
(
String
url
)
{
if
(
url
==
null
)
return
"converted"
;
int
lastSlash
=
url
.
lastIndexOf
(
'/'
);
if
(
lastSlash
>=
0
&&
lastSlash
<
url
.
length
()
-
1
)
{
String
name
=
url
.
substring
(
lastSlash
+
1
);
int
dot
=
name
.
lastIndexOf
(
'.'
);
return
dot
>
0
?
name
.
substring
(
0
,
dot
)
:
name
;
}
return
"converted"
;
}
}
\ No newline at end of file
yd-oss-api/src/main/java/com/yd/oss/api/service/ApiChunkedUploadContextService.java
0 → 100644
View file @
9d272e55
package
com
.
yd
.
oss
.
api
.
service
;
import
com.yd.common.result.Result
;
import
org.springframework.web.multipart.MultipartFile
;
import
java.util.Map
;
public
interface
ApiChunkedUploadContextService
{
void
uploadChunk
(
String
taskId
,
Integer
chunkIndex
,
MultipartFile
chunk
,
String
projectBizId
,
String
source
);
Result
<
Map
<
String
,
Object
>>
finishChunks
(
String
taskId
,
String
projectBizId
);
}
yd-oss-api/src/main/java/com/yd/oss/api/service/impl/ApiChunkedUploadContextServiceImpl.java
0 → 100644
View file @
9d272e55
package
com
.
yd
.
oss
.
api
.
service
.
impl
;
import
com.aliyun.oss.OSS
;
import
com.aliyun.oss.model.*
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
com.fasterxml.jackson.core.type.TypeReference
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.yd.common.exception.BusinessException
;
import
com.yd.common.result.Result
;
import
com.yd.oss.api.service.ApiChunkedUploadContextService
;
import
com.yd.oss.service.config.OssClientFactory
;
import
com.yd.oss.service.dao.ChunkedUploadContextMapper
;
import
com.yd.oss.service.model.ChunkedUploadContext
;
import
com.yd.oss.service.model.OssProvider
;
import
com.yd.oss.service.service.IOssProviderService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.redisson.api.RLock
;
import
org.redisson.api.RedissonClient
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.web.multipart.MultipartFile
;
import
javax.annotation.Resource
;
import
java.time.LocalDateTime
;
import
java.util.*
;
import
java.util.concurrent.TimeUnit
;
@Slf4j
@Service
public
class
ApiChunkedUploadContextServiceImpl
implements
ApiChunkedUploadContextService
{
@Resource
private
ChunkedUploadContextMapper
contextMapper
;
@Resource
private
ObjectMapper
objectMapper
;
@Resource
private
OssClientFactory
ossClientFactory
;
@Resource
private
IOssProviderService
ossProviderService
;
@Resource
private
RedissonClient
redissonClient
;
private
static
final
String
LOCK_KEY_PREFIX
=
"chunked:upload:lock:"
;
/**
* 上传单个分片(使用分布式锁保护上下文初始化 + Map存储ETag)
*/
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
uploadChunk
(
String
taskId
,
Integer
chunkIndex
,
MultipartFile
chunk
,
String
projectBizId
,
String
source
)
{
log
.
info
(
"【uploadChunk】开始处理, taskId={}, chunkIndex={}, projectBizId={}, source={}, fileSize={}"
,
taskId
,
chunkIndex
,
projectBizId
,
source
,
chunk
!=
null
?
chunk
.
getSize
()
:
0
);
// 获取OSS服务商
OssProvider
provider
=
ossProviderService
.
getProviderByProjectId
(
projectBizId
);
if
(
provider
==
null
)
{
log
.
error
(
"【uploadChunk】未找到OSS服务商, projectBizId={}"
,
projectBizId
);
throw
new
BusinessException
(
"未找到对应的OSS服务商配置"
);
}
OSS
ossClient
=
ossClientFactory
.
createOssClient
(
provider
);
// 获取或创建上下文(仅初始化时加锁)
ChunkedUploadContext
context
=
getOrCreateContext
(
taskId
,
provider
,
source
,
ossClient
);
// 上传分片并更新ETag(使用Map存储,避免PartETag反序列化问题)
try
{
int
partNumber
=
chunkIndex
+
1
;
log
.
info
(
"【uploadChunk】开始上传分片, taskId={}, partNumber={}, chunkSize={}"
,
taskId
,
partNumber
,
chunk
.
getSize
());
UploadPartRequest
uploadPartRequest
=
new
UploadPartRequest
();
uploadPartRequest
.
setBucketName
(
provider
.
getBucketName
());
uploadPartRequest
.
setKey
(
context
.
getObjectKey
());
uploadPartRequest
.
setUploadId
(
context
.
getUploadId
());
uploadPartRequest
.
setPartNumber
(
partNumber
);
uploadPartRequest
.
setInputStream
(
chunk
.
getInputStream
());
uploadPartRequest
.
setPartSize
(
chunk
.
getSize
());
UploadPartResult
uploadResult
=
ossClient
.
uploadPart
(
uploadPartRequest
);
// 读取现有ETag列表(存储为List<Map>)
String
json
=
context
.
getPartEtagsJson
();
List
<
Map
<
String
,
Object
>>
partInfoList
;
if
(
StringUtils
.
isBlank
(
json
)
||
"[]"
.
equals
(
json
))
{
partInfoList
=
new
ArrayList
<>();
}
else
{
partInfoList
=
objectMapper
.
readValue
(
json
,
new
TypeReference
<
List
<
Map
<
String
,
Object
>>>()
{});
}
// 添加新分片信息
Map
<
String
,
Object
>
newPart
=
new
HashMap
<>();
newPart
.
put
(
"partNumber"
,
partNumber
);
newPart
.
put
(
"etag"
,
uploadResult
.
getETag
());
partInfoList
.
add
(
newPart
);
// 按partNumber排序
partInfoList
.
sort
(
Comparator
.
comparingInt
(
m
->
(
Integer
)
m
.
get
(
"partNumber"
)));
// 序列化并更新数据库
context
.
setPartEtagsJson
(
objectMapper
.
writeValueAsString
(
partInfoList
));
context
.
setUpdateTime
(
LocalDateTime
.
now
());
contextMapper
.
updateById
(
context
);
log
.
info
(
"【uploadChunk】分片上传成功, taskId={}, partNumber={}, ETag={}, 当前总分片数={}"
,
taskId
,
partNumber
,
uploadResult
.
getETag
(),
partInfoList
.
size
());
}
catch
(
Exception
e
)
{
log
.
error
(
"【uploadChunk】分片上传或更新ETag失败, taskId={}, chunkIndex={}"
,
taskId
,
chunkIndex
,
e
);
throw
new
BusinessException
(
"分片上传失败: "
+
e
.
getMessage
());
}
}
/**
* 获取或创建上传上下文(使用分布式锁保证唯一性)
*/
private
ChunkedUploadContext
getOrCreateContext
(
String
taskId
,
OssProvider
provider
,
String
source
,
OSS
ossClient
)
{
String
lockKey
=
LOCK_KEY_PREFIX
+
taskId
;
RLock
lock
=
redissonClient
.
getLock
(
lockKey
);
boolean
locked
=
false
;
try
{
locked
=
lock
.
tryLock
(
5
,
10
,
TimeUnit
.
SECONDS
);
if
(!
locked
)
{
throw
new
BusinessException
(
"系统繁忙,请稍后重试"
);
}
ChunkedUploadContext
context
=
contextMapper
.
selectOne
(
new
LambdaQueryWrapper
<
ChunkedUploadContext
>()
.
eq
(
ChunkedUploadContext:
:
getTaskId
,
taskId
)
);
if
(
context
==
null
)
{
log
.
info
(
"【getOrCreateContext】上下文不存在,初始化新上传, taskId={}"
,
taskId
);
context
=
new
ChunkedUploadContext
();
context
.
setTaskId
(
taskId
);
String
objectKey
=
String
.
format
(
"sharding/"
+
source
+
"/%tY/%tm/%s_%d.webm"
,
new
Date
(),
new
Date
(),
taskId
,
System
.
currentTimeMillis
());
context
.
setObjectKey
(
objectKey
);
InitiateMultipartUploadRequest
initRequest
=
new
InitiateMultipartUploadRequest
(
provider
.
getBucketName
(),
objectKey
);
InitiateMultipartUploadResult
initResult
=
ossClient
.
initiateMultipartUpload
(
initRequest
);
context
.
setUploadId
(
initResult
.
getUploadId
());
context
.
setPartEtagsJson
(
"[]"
);
// 初始为空数组
context
.
setStatus
(
1
);
// 上传中
int
insertResult
=
contextMapper
.
insert
(
context
);
log
.
info
(
"【getOrCreateContext】初始化分片上传并入库, taskId={}, uploadId={}, objectKey={}, insertResult={}"
,
taskId
,
context
.
getUploadId
(),
objectKey
,
insertResult
);
}
else
{
log
.
info
(
"【getOrCreateContext】找到已存在的上下文, taskId={}, uploadId={}, status={}"
,
taskId
,
context
.
getUploadId
(),
context
.
getStatus
());
}
return
context
;
}
catch
(
InterruptedException
e
)
{
Thread
.
currentThread
().
interrupt
();
log
.
error
(
"【getOrCreateContext】获取锁被中断, taskId={}"
,
taskId
,
e
);
throw
new
BusinessException
(
"系统中断,请重试"
);
}
finally
{
if
(
locked
&&
lock
.
isHeldByCurrentThread
())
{
lock
.
unlock
();
log
.
debug
(
"【getOrCreateContext】释放锁, taskId={}"
,
taskId
);
}
}
}
/**
* 完成分片上传(合并)
*/
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
Result
<
Map
<
String
,
Object
>>
finishChunks
(
String
taskId
,
String
projectBizId
)
{
log
.
info
(
"【finishChunks】开始完成分片上传, taskId={}, projectBizId={}"
,
taskId
,
projectBizId
);
// 1. 查询上下文
ChunkedUploadContext
context
=
contextMapper
.
selectOne
(
new
LambdaQueryWrapper
<
ChunkedUploadContext
>()
.
eq
(
ChunkedUploadContext:
:
getTaskId
,
taskId
)
);
if
(
context
==
null
)
{
log
.
error
(
"【finishChunks】未找到分片上传上下文, taskId={}"
,
taskId
);
throw
new
BusinessException
(
"未找到分片上传上下文,请检查 taskId 是否正确"
);
}
log
.
info
(
"【finishChunks】找到上下文, taskId={}, uploadId={}, status={}, objectKey={}"
,
taskId
,
context
.
getUploadId
(),
context
.
getStatus
(),
context
.
getObjectKey
());
// 2. 解析分片列表(从Map列表转为PartETag列表)
String
json
=
context
.
getPartEtagsJson
();
List
<
Map
<
String
,
Object
>>
partInfoList
;
try
{
partInfoList
=
objectMapper
.
readValue
(
json
,
new
TypeReference
<
List
<
Map
<
String
,
Object
>>>()
{});
}
catch
(
Exception
e
)
{
log
.
error
(
"【finishChunks】解析分片数据失败, taskId={}, json={}"
,
taskId
,
json
,
e
);
throw
new
BusinessException
(
"数据异常,无法合并"
);
}
if
(
partInfoList
.
isEmpty
())
{
log
.
error
(
"【finishChunks】没有分片数据, taskId={}"
,
taskId
);
throw
new
BusinessException
(
"没有分片数据,无法合并"
);
}
List
<
PartETag
>
partETags
=
new
ArrayList
<>();
for
(
Map
<
String
,
Object
>
map
:
partInfoList
)
{
Integer
partNumber
=
(
Integer
)
map
.
get
(
"partNumber"
);
String
etag
=
(
String
)
map
.
get
(
"etag"
);
if
(
partNumber
==
null
||
etag
==
null
)
{
log
.
warn
(
"【finishChunks】分片数据不完整,跳过: {}"
,
map
);
continue
;
}
partETags
.
add
(
new
PartETag
(
partNumber
,
etag
));
}
if
(
partETags
.
isEmpty
())
{
throw
new
BusinessException
(
"没有有效的分片数据,无法合并"
);
}
log
.
info
(
"【finishChunks】解析到 {} 个分片, taskId={}"
,
partETags
.
size
(),
taskId
);
// 3. 获取OSS服务商
OssProvider
provider
=
ossProviderService
.
getProviderByProjectId
(
projectBizId
);
if
(
provider
==
null
)
{
log
.
error
(
"【finishChunks】未找到OSS服务商, projectBizId={}"
,
projectBizId
);
throw
new
BusinessException
(
"未找到对应的OSS服务商配置"
);
}
OSS
ossClient
=
ossClientFactory
.
createOssClient
(
provider
);
// 4. 执行合并
CompleteMultipartUploadRequest
completeRequest
=
new
CompleteMultipartUploadRequest
(
provider
.
getBucketName
(),
context
.
getObjectKey
(),
context
.
getUploadId
(),
partETags
);
CompleteMultipartUploadResult
completeResult
=
ossClient
.
completeMultipartUpload
(
completeRequest
);
log
.
info
(
"【finishChunks】合并成功, taskId={}, location={}"
,
taskId
,
completeResult
.
getLocation
());
// 5. 构建文件URL和大小
String
fileUrl
=
String
.
format
(
"https://%s.%s/%s"
,
provider
.
getBucketName
(),
provider
.
getEndpoint
().
replace
(
"https://"
,
""
),
context
.
getObjectKey
()
);
ObjectMetadata
metadata
=
ossClient
.
getObjectMetadata
(
provider
.
getBucketName
(),
context
.
getObjectKey
());
long
fileSize
=
metadata
.
getContentLength
();
// 6. 更新上下文状态为已完成
context
.
setStatus
(
2
);
contextMapper
.
updateById
(
context
);
log
.
info
(
"【finishChunks】上下文状态更新为已完成, taskId={}"
,
taskId
);
// 7. 返回结果
Map
<
String
,
Object
>
result
=
new
HashMap
<>();
result
.
put
(
"taskId"
,
taskId
);
result
.
put
(
"fileUrl"
,
fileUrl
);
result
.
put
(
"fileKey"
,
context
.
getObjectKey
());
result
.
put
(
"fileSize"
,
fileSize
);
log
.
info
(
"【finishChunks】完成, taskId={}, fileUrl={}"
,
taskId
,
fileUrl
);
return
Result
.
success
(
result
);
}
}
\ No newline at end of file
yd-oss-api/src/main/java/com/yd/oss/api/utils/LocalDocumentConversionService.java
0 → 100644
View file @
9d272e55
package
com
.
yd
.
oss
.
api
.
utils
;
import
com.yd.oss.api.config.OfficeManagerHolder
;
import
org.jodconverter.core.DocumentConverter
;
import
org.jodconverter.core.office.OfficeException
;
import
org.jodconverter.local.LocalConverter
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Service
;
import
javax.annotation.PostConstruct
;
import
javax.annotation.PreDestroy
;
import
java.io.InputStream
;
import
java.net.URL
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.nio.file.StandardCopyOption
;
import
java.util.UUID
;
@Service
public
class
LocalDocumentConversionService
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
LocalDocumentConversionService
.
class
);
@Value
(
"${jodconverter.libreoffice.home:}"
)
private
String
libreOfficeHome
;
private
DocumentConverter
converter
;
@PostConstruct
public
void
init
()
{
if
(
libreOfficeHome
==
null
||
libreOfficeHome
.
trim
().
isEmpty
())
{
libreOfficeHome
=
System
.
getenv
(
"LIBREOFFICE_HOME"
);
}
if
(
libreOfficeHome
==
null
||
libreOfficeHome
.
trim
().
isEmpty
())
{
String
os
=
System
.
getProperty
(
"os.name"
).
toLowerCase
();
if
(
os
.
contains
(
"win"
))
{
libreOfficeHome
=
"D:/LibreOffice"
;
}
else
if
(
os
.
contains
(
"linux"
))
{
libreOfficeHome
=
"/opt/libreoffice_standalone/libreoffice7.4"
;
}
else
if
(
os
.
contains
(
"mac"
))
{
libreOfficeHome
=
"/Applications/LibreOffice.app/Contents"
;
}
else
{
throw
new
RuntimeException
(
"无法确定 LibreOffice 安装路径,请通过配置或环境变量设置"
);
}
logger
.
warn
(
"未配置 libreOfficeHome,使用默认路径: {}"
,
libreOfficeHome
);
}
try
{
OfficeManagerHolder
.
getInstance
(
libreOfficeHome
);
converter
=
LocalConverter
.
builder
()
.
officeManager
(
OfficeManagerHolder
.
getInstance
(
libreOfficeHome
))
.
build
();
logger
.
info
(
"JodConverter 初始化成功,LibreOffice 路径: {}"
,
libreOfficeHome
);
}
catch
(
Exception
e
)
{
logger
.
error
(
"JodConverter 初始化失败,请检查 LibreOffice 安装"
,
e
);
throw
new
RuntimeException
(
"JodConverter 初始化失败"
,
e
);
}
}
public
byte
[]
convertToPdfBytes
(
String
fileUrl
)
throws
Exception
{
return
convertToBytes
(
fileUrl
,
"pdf"
);
}
public
byte
[]
convertToBytes
(
String
fileUrl
,
String
targetExtension
)
throws
Exception
{
if
(
targetExtension
.
startsWith
(
"."
))
{
targetExtension
=
targetExtension
.
substring
(
1
);
}
if
(
targetExtension
==
null
||
targetExtension
.
trim
().
isEmpty
())
{
throw
new
IllegalArgumentException
(
"目标扩展名不能为空"
);
}
logger
.
info
(
"开始转换文档: {} -> 格式: {}"
,
fileUrl
,
targetExtension
);
Path
tempInput
=
Files
.
createTempFile
(
"convert_"
,
"_"
+
UUID
.
randomUUID
());
try
(
InputStream
in
=
new
URL
(
fileUrl
).
openStream
())
{
Files
.
copy
(
in
,
tempInput
,
StandardCopyOption
.
REPLACE_EXISTING
);
}
logger
.
info
(
"源文件下载到临时路径: {}"
,
tempInput
.
toAbsolutePath
());
Path
tempOutput
=
Files
.
createTempFile
(
"converted_"
,
"."
+
targetExtension
);
try
{
converter
.
convert
(
tempInput
.
toFile
())
.
to
(
tempOutput
.
toFile
())
.
execute
();
logger
.
info
(
"转换完成,临时输出: {}"
,
tempOutput
.
toAbsolutePath
());
byte
[]
resultBytes
=
Files
.
readAllBytes
(
tempOutput
);
logger
.
info
(
"转换结果大小: {} bytes"
,
resultBytes
.
length
);
return
resultBytes
;
}
catch
(
OfficeException
e
)
{
logger
.
error
(
"转换失败 (格式: {})"
,
targetExtension
,
e
);
throw
new
Exception
(
"文档转换失败 (格式: "
+
targetExtension
+
"): "
+
e
.
getMessage
(),
e
);
}
finally
{
try
{
Files
.
deleteIfExists
(
tempInput
);
Files
.
deleteIfExists
(
tempOutput
);
}
catch
(
Exception
ignored
)
{
logger
.
warn
(
"清理临时文件失败"
);
}
}
}
@PreDestroy
public
void
destroy
()
{
OfficeManagerHolder
.
stop
();
}
}
\ No newline at end of file
yd-oss-api/yd-oss-api.iml
View file @
9d272e55
...
@@ -26,6 +26,21 @@
...
@@ -26,6 +26,21 @@
</content>
</content>
<orderEntry
type=
"jdk"
jdkName=
"1.8"
jdkType=
"JavaSDK"
/>
<orderEntry
type=
"jdk"
jdkName=
"1.8"
jdkType=
"JavaSDK"
/>
<orderEntry
type=
"sourceFolder"
forTests=
"false"
/>
<orderEntry
type=
"sourceFolder"
forTests=
"false"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-crypto:5.6.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-config:5.6.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-web:5.6.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-resource-server:5.6.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-core:5.6.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-jose:5.6.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-core:5.6.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.jodconverter:jodconverter-core:4.4.7"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.jodconverter:jodconverter-local:4.4.7"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.openoffice:juh:4.1.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.openoffice:jurt:4.1.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.openoffice:ridl:4.1.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.openoffice:unoil:4.1.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.itextpdf:itextpdf:5.5.13"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.itextpdf:itext-asian:5.2.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:2021.0.1.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:2021.0.1.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.cloud:spring-cloud-alibaba-commons:2021.0.1.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.cloud:spring-cloud-alibaba-commons:2021.0.1.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.nacos:nacos-client:1.4.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.nacos:nacos-client:1.4.2"
level=
"project"
/>
...
@@ -41,7 +56,7 @@
...
@@ -41,7 +56,7 @@
<orderEntry
type=
"library"
name=
"Maven: io.prometheus:simpleclient_tracer_otel_agent:0.12.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.prometheus:simpleclient_tracer_otel_agent:0.12.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.spring:spring-context-support:1.0.11"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.spring:spring-context-support:1.0.11"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-commons:3.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-commons:3.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-crypto:5.6.
2
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-crypto:5.6.
9
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-context:3.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-context:3.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config:2021.0.1.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config:2021.0.1.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.boot:spring-boot-starter-web:2.6.6"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.boot:spring-boot-starter-web:2.6.6"
level=
"project"
/>
...
@@ -184,11 +199,11 @@
...
@@ -184,11 +199,11 @@
<orderEntry
type=
"library"
name=
"Maven: io.swagger.core.v3:swagger-models:2.2.9"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.swagger.core.v3:swagger-models:2.2.9"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.webjars:swagger-ui:4.18.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.webjars:swagger-ui:4.18.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.boot:spring-boot-starter-security:2.6.6"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.boot:spring-boot-starter-security:2.6.6"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-config:5.6.
2
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-config:5.6.
9
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-web:5.6.
2
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-web:5.6.
9
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-resource-server:5.6.
2
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-resource-server:5.6.
9
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-core:5.6.
2
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-core:5.6.
9
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-jose:5.6.
2
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-jose:5.6.
9
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.nimbusds:nimbus-jose-jwt:9.14"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.nimbusds:nimbus-jose-jwt:9.14"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.github.stephenc.jcip:jcip-annotations:1.0-1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.github.stephenc.jcip:jcip-annotations:1.0-1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.jsonwebtoken:jjwt-api:0.11.5"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.jsonwebtoken:jjwt-api:0.11.5"
level=
"project"
/>
...
@@ -208,7 +223,7 @@
...
@@ -208,7 +223,7 @@
<orderEntry
type=
"library"
name=
"Maven: org.springframework.boot:spring-boot-starter-aop:2.6.6"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.boot:spring-boot-starter-aop:2.6.6"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.aspectj:aspectjweaver:1.9.7"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.aspectj:aspectjweaver:1.9.7"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.projectlombok:lombok:1.18.16"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.projectlombok:lombok:1.18.16"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-core:5.6.
2
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-core:5.6.
9
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.redisson:redisson:3.20.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.redisson:redisson:3.20.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.netty:netty-common:4.1.69.Final"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.netty:netty-common:4.1.69.Final"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.netty:netty-codec:4.1.69.Final"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.netty:netty-codec:4.1.69.Final"
level=
"project"
/>
...
@@ -232,11 +247,11 @@
...
@@ -232,11 +247,11 @@
<orderEntry
type=
"library"
name=
"Maven: com.yd:yd-feign:1.0-SNAPSHOT"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.yd:yd-feign:1.0-SNAPSHOT"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-starter-openfeign:3.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-starter-openfeign:3.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-openfeign-core:3.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-openfeign-core:3.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign.form:feign-form-spring:3.8.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign.form:feign-form:3.8.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: commons-fileupload:commons-fileupload:1.3.3"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign:feign-core:11.8"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign:feign-core:11.8"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign:feign-slf4j:11.8"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign:feign-slf4j:11.8"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign.form:feign-form-spring:3.8.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: commons-fileupload:commons-fileupload:1.3.3"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign.form:feign-form:3.8.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.aliyun.oss:aliyun-sdk-oss:3.15.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.aliyun.oss:aliyun-sdk-oss:3.15.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.apache.httpcomponents:httpclient:4.5.13"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.apache.httpcomponents:httpclient:4.5.13"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.jdom:jdom2:2.0.6.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.jdom:jdom2:2.0.6.1"
level=
"project"
/>
...
@@ -284,5 +299,13 @@
...
@@ -284,5 +299,13 @@
<orderEntry
type=
"library"
name=
"Maven: org.apache.commons:commons-compress:1.19"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.apache.commons:commons-compress:1.19"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.github.virtuald:curvesapi:1.06"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.github.virtuald:curvesapi:1.06"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.apache.xmlbeans:xmlbeans:3.1.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.apache.xmlbeans:xmlbeans:3.1.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.jodconverter:jodconverter-core:4.4.7"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.jodconverter:jodconverter-local:4.4.7"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.openoffice:juh:4.1.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.openoffice:jurt:4.1.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.openoffice:ridl:4.1.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.openoffice:unoil:4.1.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.itextpdf:itextpdf:5.5.13"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.itextpdf:itext-asian:5.2.0"
level=
"project"
/>
</component>
</component>
</module>
</module>
\ No newline at end of file
yd-oss-feign/src/main/java/com/yd/oss/feign/client/ApiChunkedUploadContextFeignClient.java
0 → 100644
View file @
9d272e55
package
com
.
yd
.
oss
.
feign
.
client
;
import
com.yd.common.result.Result
;
import
com.yd.oss.feign.fallback.ApiChunkedUploadContextFeignFallbackFactory
;
import
org.springframework.cloud.openfeign.FeignClient
;
import
org.springframework.http.MediaType
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestParam
;
import
org.springframework.web.bind.annotation.RequestPart
;
import
org.springframework.web.multipart.MultipartFile
;
import
java.util.Map
;
/**
* 分片上传上下文信息Feign客户端
*/
@FeignClient
(
name
=
"yd-oss-api"
,
path
=
"/oss/api/chunkedUploadContext"
,
fallbackFactory
=
ApiChunkedUploadContextFeignFallbackFactory
.
class
)
public
interface
ApiChunkedUploadContextFeignClient
{
/**
* 上传单个分片
* @param chunk
* @param taskId
* @param chunkIndex
* @param projectBizId
* @param source
* @return
*/
@PostMapping
(
value
=
"/uploadChunk"
,
consumes
=
MediaType
.
MULTIPART_FORM_DATA_VALUE
)
Result
<
Void
>
uploadChunk
(
@RequestPart
(
"chunk"
)
MultipartFile
chunk
,
@RequestParam
(
"taskId"
)
String
taskId
,
@RequestParam
(
"chunkIndex"
)
Integer
chunkIndex
,
@RequestParam
(
"projectBizId"
)
String
projectBizId
,
@RequestParam
(
"source"
)
String
source
);
/**
* 完成分片上传(合并)
*/
@PostMapping
(
"/finishChunks"
)
Result
<
Map
<
String
,
Object
>>
finishChunks
(
@RequestParam
(
"taskId"
)
String
taskId
,
@RequestParam
(
"projectBizId"
)
String
projectBizId
);
}
yd-oss-feign/src/main/java/com/yd/oss/feign/client/ApiOssFeignClient.java
View file @
9d272e55
...
@@ -10,14 +10,14 @@ import org.springframework.cloud.openfeign.FeignClient;
...
@@ -10,14 +10,14 @@ import org.springframework.cloud.openfeign.FeignClient;
import
org.springframework.http.MediaType
;
import
org.springframework.http.MediaType
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.multipart.MultipartFile
;
import
org.springframework.web.multipart.MultipartFile
;
import
javax.validation.constraints.NotBlank
;
import
java.util.List
;
import
java.util.List
;
/**
/**
* OSS服务信息Feign客户端
* OSS服务信息Feign客户端
*/
*/
@FeignClient
(
name
=
"yd-oss-api"
,
fallbackFactory
=
ApiOssFeignFallbackFactory
.
class
)
@FeignClient
(
name
=
"yd-oss-api"
,
path
=
"/oss/api/oss"
,
fallbackFactory
=
ApiOssFeignFallbackFactory
.
class
)
public
interface
ApiOssFeignClient
{
public
interface
ApiOssFeignClient
{
/**
/**
...
@@ -42,7 +42,10 @@ public interface ApiOssFeignClient {
...
@@ -42,7 +42,10 @@ public interface ApiOssFeignClient {
Result
<
ApiUploadResponse
>
uploadFileBody
(
@RequestPart
(
"file"
)
MultipartFile
file
,
Result
<
ApiUploadResponse
>
uploadFileBody
(
@RequestPart
(
"file"
)
MultipartFile
file
,
@RequestPart
(
"request"
)
ApiUploadFileRequest
request
);
@RequestPart
(
"request"
)
ApiUploadFileRequest
request
);
@PostMapping
(
value
=
"/upload/body/json"
,
consumes
=
MediaType
.
MULTIPART_FORM_DATA_VALUE
)
Result
<
ApiUploadResponse
>
uploadFileBodyWithJson
(
@RequestPart
(
"file"
)
MultipartFile
file
,
@RequestPart
(
"request"
)
String
requestJson
);
/**
/**
* 下载文件
* 下载文件
...
...
yd-oss-feign/src/main/java/com/yd/oss/feign/fallback/ApiChunkedUploadContextFeignFallbackFactory.java
0 → 100644
View file @
9d272e55
package
com
.
yd
.
oss
.
feign
.
fallback
;
import
com.yd.common.result.Result
;
import
com.yd.oss.feign.client.ApiChunkedUploadContextFeignClient
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.cloud.openfeign.FallbackFactory
;
import
org.springframework.stereotype.Component
;
import
org.springframework.web.multipart.MultipartFile
;
import
java.util.Map
;
/**
* 分片上传上下文信息Feign降级处理
*/
@Slf4j
@Component
public
class
ApiChunkedUploadContextFeignFallbackFactory
implements
FallbackFactory
<
ApiChunkedUploadContextFeignClient
>
{
@Override
public
ApiChunkedUploadContextFeignClient
create
(
Throwable
cause
)
{
return
new
ApiChunkedUploadContextFeignClient
()
{
@Override
public
Result
<
Void
>
uploadChunk
(
MultipartFile
chunk
,
String
taskId
,
Integer
chunkIndex
,
String
projectBizId
,
String
source
)
{
return
null
;
}
@Override
public
Result
<
Map
<
String
,
Object
>>
finishChunks
(
String
taskId
,
String
projectBizId
)
{
return
null
;
}
};
}
}
yd-oss-feign/src/main/java/com/yd/oss/feign/fallback/ApiExcelFeignFallbackFactory.java
View file @
9d272e55
...
@@ -4,7 +4,6 @@ import com.yd.common.result.Result;
...
@@ -4,7 +4,6 @@ import com.yd.common.result.Result;
import
com.yd.oss.feign.client.ApiExcelFeignClient
;
import
com.yd.oss.feign.client.ApiExcelFeignClient
;
import
com.yd.oss.feign.dto.ExportResult
;
import
com.yd.oss.feign.dto.ExportResult
;
import
com.yd.oss.feign.request.ApiExportRequest
;
import
com.yd.oss.feign.request.ApiExportRequest
;
import
com.yd.oss.feign.request.ApiOssExcelParseRequest
;
import
com.yd.oss.feign.request.ApiOssExportAppointmentExcelRequest
;
import
com.yd.oss.feign.request.ApiOssExportAppointmentExcelRequest
;
import
com.yd.oss.feign.request.MultiSheetExportRequest
;
import
com.yd.oss.feign.request.MultiSheetExportRequest
;
import
com.yd.oss.feign.response.ApiOssExcelParseResponse
;
import
com.yd.oss.feign.response.ApiOssExcelParseResponse
;
...
...
yd-oss-feign/src/main/java/com/yd/oss/feign/fallback/ApiOssFeignFallbackFactory.java
View file @
9d272e55
...
@@ -33,6 +33,11 @@ public class ApiOssFeignFallbackFactory implements FallbackFactory<ApiOssFeignCl
...
@@ -33,6 +33,11 @@ public class ApiOssFeignFallbackFactory implements FallbackFactory<ApiOssFeignCl
}
}
@Override
@Override
public
Result
<
ApiUploadResponse
>
uploadFileBodyWithJson
(
MultipartFile
file
,
String
requestJson
)
{
return
null
;
}
@Override
public
Result
downloadFile
(
String
fileKey
)
{
public
Result
downloadFile
(
String
fileKey
)
{
return
null
;
return
null
;
}
}
...
...
yd-oss-feign/src/main/java/com/yd/oss/feign/request/ApiUploadFileRequest.java
View file @
9d272e55
...
@@ -8,6 +8,11 @@ import javax.validation.constraints.NotBlank;
...
@@ -8,6 +8,11 @@ import javax.validation.constraints.NotBlank;
public
class
ApiUploadFileRequest
{
public
class
ApiUploadFileRequest
{
/**
/**
* 租户唯一标识(业务ID)
*/
private
String
tenantBizId
;
/**
* 项目ID
* 项目ID
*/
*/
private
String
projectBizId
;
private
String
projectBizId
;
...
...
yd-oss-feign/src/main/java/com/yd/oss/feign/response/ApiUploadResponse.java
View file @
9d272e55
...
@@ -61,6 +61,6 @@ public class ApiUploadResponse {
...
@@ -61,6 +61,6 @@ public class ApiUploadResponse {
/**
/**
* 创建时间
* 创建时间
*/
*/
@JsonFormat
(
pattern
=
"yyyy-MM-dd"
,
timezone
=
"GMT+8"
)
@JsonFormat
(
pattern
=
"yyyy-MM-dd
HH:mm:ss
"
,
timezone
=
"GMT+8"
)
private
LocalDateTime
createTime
;
private
LocalDateTime
createTime
;
}
}
yd-oss-feign/yd-oss-feign.iml
View file @
9d272e55
...
@@ -17,9 +17,7 @@
...
@@ -17,9 +17,7 @@
</content>
</content>
<orderEntry
type=
"jdk"
jdkName=
"1.8"
jdkType=
"JavaSDK"
/>
<orderEntry
type=
"jdk"
jdkName=
"1.8"
jdkType=
"JavaSDK"
/>
<orderEntry
type=
"sourceFolder"
forTests=
"false"
/>
<orderEntry
type=
"sourceFolder"
forTests=
"false"
/>
<orderEntry
type=
"library"
name=
"Maven: org.apache.poi:poi-ooxml-schemas:4.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-crypto:5.6.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.google.guava:guava:16.0.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.apache.commons:commons-compress:1.21"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.yd:yd-feign:1.0-SNAPSHOT"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.yd:yd-feign:1.0-SNAPSHOT"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-starter-openfeign:3.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-starter-openfeign:3.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-starter:3.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-starter:3.1.1"
level=
"project"
/>
...
@@ -31,15 +29,15 @@
...
@@ -31,15 +29,15 @@
<orderEntry
type=
"library"
name=
"Maven: org.springframework.boot:spring-boot-autoconfigure:2.6.6"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.boot:spring-boot-autoconfigure:2.6.6"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.boot:spring-boot-starter-aop:2.6.6"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.boot:spring-boot-starter-aop:2.6.6"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.aspectj:aspectjweaver:1.9.7"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.aspectj:aspectjweaver:1.9.7"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign.form:feign-form-spring:3.8.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign.form:feign-form:3.8.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: commons-fileupload:commons-fileupload:1.3.3"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: commons-io:commons-io:2.11.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-commons:3.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-commons:3.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-crypto:5.6.
2
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-crypto:5.6.
9
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign:feign-core:11.8"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign:feign-core:11.8"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign:feign-slf4j:11.8"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign:feign-slf4j:11.8"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.projectlombok:lombok:1.18.16"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.projectlombok:lombok:1.18.16"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign.form:feign-form-spring:3.8.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: commons-fileupload:commons-fileupload:1.3.3"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: commons-io:commons-io:2.11.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign.form:feign-form:3.8.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.yd:yd-common:1.0-SNAPSHOT"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.yd:yd-common:1.0-SNAPSHOT"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.github.xiaoymin:knife4j-openapi3-spring-boot-starter:4.3.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.github.xiaoymin:knife4j-openapi3-spring-boot-starter:4.3.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.github.xiaoymin:knife4j-core:4.3.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.github.xiaoymin:knife4j-core:4.3.0"
level=
"project"
/>
...
...
yd-oss-service/pom.xml
View file @
9d272e55
...
@@ -120,5 +120,30 @@
...
@@ -120,5 +120,30 @@
<artifactId>
xmlbeans
</artifactId>
<artifactId>
xmlbeans
</artifactId>
</dependency>
</dependency>
<!-- JodConverter 文档转换 -->
<dependency>
<groupId>
org.jodconverter
</groupId>
<artifactId>
jodconverter-core
</artifactId>
<version>
4.4.7
</version>
</dependency>
<dependency>
<groupId>
org.jodconverter
</groupId>
<artifactId>
jodconverter-local
</artifactId>
<version>
4.4.7
</version>
</dependency>
<!-- iText PDF 处理 -->
<dependency>
<groupId>
com.itextpdf
</groupId>
<artifactId>
itextpdf
</artifactId>
<version>
5.5.13
</version>
</dependency>
<dependency>
<groupId>
com.itextpdf
</groupId>
<artifactId>
itext-asian
</artifactId>
<version>
5.2.0
</version>
</dependency>
</dependencies>
</dependencies>
</project>
</project>
yd-oss-service/src/main/java/com/yd/oss/service/dao/ChunkedUploadContextMapper.java
0 → 100644
View file @
9d272e55
package
com
.
yd
.
oss
.
service
.
dao
;
import
com.yd.oss.service.model.ChunkedUploadContext
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
/**
* <p>
* 分片上传上下文表(一个任务上传文件信息拆分成多个ETag上传存储,任务执行完毕,阿里云合并ETag列表为完整的文件信息) Mapper 接口
* </p>
*
* @author zxm
* @since 2026-08-05
*/
public
interface
ChunkedUploadContextMapper
extends
BaseMapper
<
ChunkedUploadContext
>
{
}
yd-oss-service/src/main/java/com/yd/oss/service/dto/OssUploadFileReqDto.java
View file @
9d272e55
...
@@ -15,6 +15,11 @@ import lombok.NoArgsConstructor;
...
@@ -15,6 +15,11 @@ import lombok.NoArgsConstructor;
public
class
OssUploadFileReqDto
{
public
class
OssUploadFileReqDto
{
/**
/**
* 租户唯一标识(业务ID)
*/
private
String
tenantBizId
;
/**
* 项目ID
* 项目ID
*/
*/
private
String
projectBizId
;
private
String
projectBizId
;
...
...
yd-oss-service/src/main/java/com/yd/oss/service/model/ChunkedUploadContext.java
0 → 100644
View file @
9d272e55
package
com
.
yd
.
oss
.
service
.
model
;
import
com.baomidou.mybatisplus.annotation.IdType
;
import
com.baomidou.mybatisplus.annotation.TableField
;
import
com.baomidou.mybatisplus.annotation.TableId
;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
java.io.Serializable
;
import
java.time.LocalDateTime
;
import
lombok.Getter
;
import
lombok.Setter
;
/**
* <p>
* 分片上传上下文表(一个任务上传文件信息拆分成多个ETag上传存储,任务执行完毕,阿里云合并ETag列表为完整的文件信息)
* </p>
*
* @author zxm
* @since 2026-08-05
*/
@Getter
@Setter
@TableName
(
"chunked_upload_context"
)
public
class
ChunkedUploadContext
implements
Serializable
{
private
static
final
long
serialVersionUID
=
1L
;
/**
* 主键
*/
@TableId
(
value
=
"id"
,
type
=
IdType
.
AUTO
)
private
Long
id
;
/**
* 任务ID
*/
@TableField
(
"task_id"
)
private
String
taskId
;
/**
* OSS 分片上传 ID(由 OSS 初始化时返回)
*/
@TableField
(
"upload_id"
)
private
String
uploadId
;
/**
* 文件在 OSS 中的完整路径(不含 Bucket 名称)
*/
@TableField
(
"object_key"
)
private
String
objectKey
;
/**
* 已上传分片的 ETag 列表(JSON 数组格式,如 [{"partNumber":1,"eTag":"xxx"}])
*/
@TableField
(
"part_etags_json"
)
private
String
partEtagsJson
;
/**
* 状态:0-初始化,1-上传中,2-已完成,3-已取消
*/
@TableField
(
"status"
)
private
Integer
status
;
/**
* 通用备注
*/
@TableField
(
"remark"
)
private
String
remark
;
/**
* 删除标识: 0-正常, 1-删除
*/
@TableField
(
"is_deleted"
)
private
Integer
isDeleted
;
/**
* 创建人ID
*/
@TableField
(
"creator_id"
)
private
String
creatorId
;
/**
* 更新人ID
*/
@TableField
(
"updater_id"
)
private
String
updaterId
;
/**
* 创建时间
*/
@TableField
(
"create_time"
)
private
LocalDateTime
createTime
;
/**
* 更新时间
*/
@TableField
(
"update_time"
)
private
LocalDateTime
updateTime
;
}
yd-oss-service/src/main/java/com/yd/oss/service/service/IChunkedUploadContextService.java
0 → 100644
View file @
9d272e55
package
com
.
yd
.
oss
.
service
.
service
;
import
com.yd.oss.service.model.ChunkedUploadContext
;
import
com.baomidou.mybatisplus.extension.service.IService
;
/**
* <p>
* 分片上传上下文表(一个任务上传文件信息拆分成多个ETag上传存储,任务执行完毕,阿里云合并ETag列表为完整的文件信息) 服务类
* </p>
*
* @author zxm
* @since 2026-08-05
*/
public
interface
IChunkedUploadContextService
extends
IService
<
ChunkedUploadContext
>
{
}
yd-oss-service/src/main/java/com/yd/oss/service/service/impl/AliYunOssServiceImpl.java
View file @
9d272e55
package
com
.
yd
.
oss
.
service
.
service
.
impl
;
package
com
.
yd
.
oss
.
service
.
service
.
impl
;
import
com.alibaba.fastjson2.JSON
;
import
com.aliyun.oss.OSS
;
import
com.aliyun.oss.OSS
;
import
com.aliyun.oss.model.CannedAccessControlList
;
import
com.aliyun.oss.model.CannedAccessControlList
;
import
com.aliyun.oss.model.OSSObject
;
import
com.aliyun.oss.model.OSSObject
;
...
@@ -83,7 +84,7 @@ public class AliYunOssServiceImpl implements OssService {
...
@@ -83,7 +84,7 @@ public class AliYunOssServiceImpl implements OssService {
OSS
ossClient
=
null
;
OSS
ossClient
=
null
;
try
{
try
{
ossClient
=
ossClientFactory
.
createOssClient
(
provider
);
ossClient
=
ossClientFactory
.
createOssClient
(
provider
);
return
doUploadFile
(
ossClient
,
provider
,
inputStream
,
fileName
,
bucketName
,
uploadUser
,
type
,
null
,
null
,
null
,
null
,
null
,
null
);
return
doUploadFile
(
ossClient
,
provider
,
inputStream
,
fileName
,
bucketName
,
uploadUser
,
type
,
null
,
null
,
null
,
null
,
null
,
null
,
null
,
null
);
}
finally
{
}
finally
{
if
(
ossClient
!=
null
)
{
if
(
ossClient
!=
null
)
{
ossClient
.
shutdown
();
ossClient
.
shutdown
();
...
@@ -115,7 +116,8 @@ public class AliYunOssServiceImpl implements OssService {
...
@@ -115,7 +116,8 @@ public class AliYunOssServiceImpl implements OssService {
FileUtil
.
getFileType
(
file
.
getOriginalFilename
()),
FileUtil
.
getFileType
(
file
.
getOriginalFilename
()),
reqDto
.
getObjectBizId
(),
reqDto
.
getObjectName
(),
reqDto
.
getObjectBizId
(),
reqDto
.
getObjectName
(),
reqDto
.
getObjectTableName
(),
reqDto
.
getObjectType
(),
reqDto
.
getObjectTableName
(),
reqDto
.
getObjectType
(),
reqDto
.
getObjectBizId
(),
reqDto
.
getObjectName
());
// 这里需要根据实际情况调整,原代码中存储了object信息
reqDto
.
getObjectBizId
(),
reqDto
.
getObjectName
(),
reqDto
.
getTenantBizId
(),
reqDto
.
getProjectBizId
());
// 这里需要根据实际情况调整,原代码中存储了object信息
}
catch
(
IOException
e
)
{
}
catch
(
IOException
e
)
{
log
.
error
(
"文件输入流解析异常"
,
e
);
log
.
error
(
"文件输入流解析异常"
,
e
);
throw
new
BusinessException
(
"文件输入流解析异常"
);
throw
new
BusinessException
(
"文件输入流解析异常"
);
...
@@ -142,7 +144,7 @@ public class AliYunOssServiceImpl implements OssService {
...
@@ -142,7 +144,7 @@ public class AliYunOssServiceImpl implements OssService {
try
{
try
{
ossClient
=
ossClientFactory
.
createOssClient
(
defaultProvider
);
ossClient
=
ossClientFactory
.
createOssClient
(
defaultProvider
);
OssUploadFileResDto
result
=
doUploadFile
(
ossClient
,
defaultProvider
,
inputStream
,
fileName
,
OssUploadFileResDto
result
=
doUploadFile
(
ossClient
,
defaultProvider
,
inputStream
,
fileName
,
defaultProvider
.
getBucketName
(),
uploadUser
,
null
,
null
,
null
,
null
,
null
,
null
,
null
);
defaultProvider
.
getBucketName
(),
uploadUser
,
null
,
null
,
null
,
null
,
null
,
null
,
null
,
null
,
null
);
return
result
.
getUrl
();
return
result
.
getUrl
();
}
finally
{
}
finally
{
if
(
ossClient
!=
null
)
{
if
(
ossClient
!=
null
)
{
...
@@ -159,7 +161,8 @@ public class AliYunOssServiceImpl implements OssService {
...
@@ -159,7 +161,8 @@ public class AliYunOssServiceImpl implements OssService {
String
bucketName
,
String
uploadUser
,
String
type
,
String
bucketName
,
String
uploadUser
,
String
type
,
String
objectBizId
,
String
objectName
,
String
objectBizId
,
String
objectName
,
String
objectTableName
,
String
objectType
,
String
objectTableName
,
String
objectType
,
String
creatorId
,
String
creatorName
)
{
String
creatorId
,
String
creatorName
,
String
tenantBizId
,
String
projectBizId
)
{
LocalDateTime
now
=
LocalDateTime
.
now
();
LocalDateTime
now
=
LocalDateTime
.
now
();
long
startTime
=
System
.
currentTimeMillis
();
long
startTime
=
System
.
currentTimeMillis
();
String
operationResult
=
"success"
;
String
operationResult
=
"success"
;
...
@@ -203,8 +206,15 @@ public class AliYunOssServiceImpl implements OssService {
...
@@ -203,8 +206,15 @@ public class AliYunOssServiceImpl implements OssService {
ossFile
.
setObjectName
(
objectName
);
ossFile
.
setObjectName
(
objectName
);
ossFile
.
setObjectTableName
(
objectTableName
);
ossFile
.
setObjectTableName
(
objectTableName
);
ossFile
.
setObjectType
(
objectType
);
ossFile
.
setObjectType
(
objectType
);
ossFile
.
setTenantBizId
(
tenantBizId
);
ossFile
.
setProjectBizId
(
projectBizId
);
// 获取当前登录用户信息(如果存在)
// 获取当前登录用户信息(如果存在)
AuthUserDto
authUserDto
=
SecurityUtil
.
getCurrentLoginUser
();
AuthUserDto
authUserDto
=
null
;
try
{
authUserDto
=
SecurityUtil
.
getCurrentLoginUser
();
}
catch
(
Exception
e
){
log
.
info
(
"获取当前登录用户信息失败:{}"
,
e
.
getMessage
());
}
if
(
authUserDto
!=
null
)
{
if
(
authUserDto
!=
null
)
{
ossFile
.
setCreatorId
(
authUserDto
.
getUserBizId
());
ossFile
.
setCreatorId
(
authUserDto
.
getUserBizId
());
ossFile
.
setCreatorName
(
authUserDto
.
getRealName
());
ossFile
.
setCreatorName
(
authUserDto
.
getRealName
());
...
...
yd-oss-service/src/main/java/com/yd/oss/service/service/impl/ChunkedUploadContextServiceImpl.java
0 → 100644
View file @
9d272e55
package
com
.
yd
.
oss
.
service
.
service
.
impl
;
import
com.yd.oss.service.model.ChunkedUploadContext
;
import
com.yd.oss.service.dao.ChunkedUploadContextMapper
;
import
com.yd.oss.service.service.IChunkedUploadContextService
;
import
com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
;
import
org.springframework.stereotype.Service
;
/**
* <p>
* 分片上传上下文表(一个任务上传文件信息拆分成多个ETag上传存储,任务执行完毕,阿里云合并ETag列表为完整的文件信息) 服务实现类
* </p>
*
* @author zxm
* @since 2026-08-05
*/
@Service
public
class
ChunkedUploadContextServiceImpl
extends
ServiceImpl
<
ChunkedUploadContextMapper
,
ChunkedUploadContext
>
implements
IChunkedUploadContextService
{
}
yd-oss-service/src/main/java/com/yd/oss/service/utils/MyBatisPlusCodeGenerator.java
View file @
9d272e55
...
@@ -21,7 +21,7 @@ public class MyBatisPlusCodeGenerator {
...
@@ -21,7 +21,7 @@ public class MyBatisPlusCodeGenerator {
})
})
.
strategyConfig
(
builder
->
{
.
strategyConfig
(
builder
->
{
builder
.
addInclude
(
builder
.
addInclude
(
"
material"
,
"rel_object_material
"
"
chunked_upload_context
"
)
)
.
entityBuilder
()
.
entityBuilder
()
.
enableLombok
()
.
enableLombok
()
...
...
yd-oss-service/src/main/resources/mappers/ChunkedUploadContextMapper.xml
0 → 100644
View file @
9d272e55
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace=
"com.yd.oss.service.dao.ChunkedUploadContextMapper"
>
</mapper>
yd-oss-service/yd-oss-service.iml
View file @
9d272e55
...
@@ -26,6 +26,13 @@
...
@@ -26,6 +26,13 @@
</content>
</content>
<orderEntry
type=
"jdk"
jdkName=
"1.8"
jdkType=
"JavaSDK"
/>
<orderEntry
type=
"jdk"
jdkName=
"1.8"
jdkType=
"JavaSDK"
/>
<orderEntry
type=
"sourceFolder"
forTests=
"false"
/>
<orderEntry
type=
"sourceFolder"
forTests=
"false"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-config:5.6.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-web:5.6.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-resource-server:5.6.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-core:5.6.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-jose:5.6.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-core:5.6.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-crypto:5.6.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.baomidou:mybatis-plus-boot-starter:3.5.5"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.baomidou:mybatis-plus-boot-starter:3.5.5"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.baomidou:mybatis-plus:3.5.5"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.baomidou:mybatis-plus:3.5.5"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.baomidou:mybatis-plus-annotation:3.5.5"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.baomidou:mybatis-plus-annotation:3.5.5"
level=
"project"
/>
...
@@ -134,7 +141,6 @@
...
@@ -134,7 +141,6 @@
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.cloud:spring-cloud-alibaba-commons:2021.0.1.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.cloud:spring-cloud-alibaba-commons:2021.0.1.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.nacos:nacos-client:1.4.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.nacos:nacos-client:1.4.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.nacos:nacos-common:1.4.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.nacos:nacos-common:1.4.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: commons-io:commons-io:2.11.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.apache.httpcomponents:httpasyncclient:4.1.5"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.apache.httpcomponents:httpasyncclient:4.1.5"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.apache.httpcomponents:httpcore-nio:4.4.15"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.apache.httpcomponents:httpcore-nio:4.4.15"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.nacos:nacos-api:1.4.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.alibaba.nacos:nacos-api:1.4.2"
level=
"project"
/>
...
@@ -163,11 +169,11 @@
...
@@ -163,11 +169,11 @@
<orderEntry
type=
"library"
name=
"Maven: org.yaml:snakeyaml:1.29"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.yaml:snakeyaml:1.29"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.boot:spring-boot-starter-security:2.6.6"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.boot:spring-boot-starter-security:2.6.6"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework:spring-aop:5.3.18"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework:spring-aop:5.3.18"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-config:5.6.
2
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-config:5.6.
9
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-web:5.6.
2
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-web:5.6.
9
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-resource-server:5.6.
2
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-resource-server:5.6.
9
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-core:5.6.
2
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-core:5.6.
9
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-jose:5.6.
2
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-oauth2-jose:5.6.
9
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.nimbusds:nimbus-jose-jwt:9.14"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.nimbusds:nimbus-jose-jwt:9.14"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.github.stephenc.jcip:jcip-annotations:1.0-1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.github.stephenc.jcip:jcip-annotations:1.0-1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.jsonwebtoken:jjwt-api:0.11.5"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.jsonwebtoken:jjwt-api:0.11.5"
level=
"project"
/>
...
@@ -192,8 +198,8 @@
...
@@ -192,8 +198,8 @@
<orderEntry
type=
"library"
name=
"Maven: org.springframework.boot:spring-boot-starter-aop:2.6.6"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.boot:spring-boot-starter-aop:2.6.6"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.aspectj:aspectjweaver:1.9.7"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.aspectj:aspectjweaver:1.9.7"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.projectlombok:lombok:1.18.16"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.projectlombok:lombok:1.18.16"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-core:5.6.
2
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-core:5.6.
9
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-crypto:5.6.
2
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.security:spring-security-crypto:5.6.
9
"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework:spring-expression:5.3.18"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework:spring-expression:5.3.18"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.redisson:redisson:3.20.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.redisson:redisson:3.20.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.netty:netty-common:4.1.69.Final"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.netty:netty-common:4.1.69.Final"
level=
"project"
/>
...
@@ -220,11 +226,12 @@
...
@@ -220,11 +226,12 @@
<orderEntry
type=
"library"
name=
"Maven: com.yd:yd-feign:1.0-SNAPSHOT"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.yd:yd-feign:1.0-SNAPSHOT"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-starter-openfeign:3.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-starter-openfeign:3.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-openfeign-core:3.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.cloud:spring-cloud-openfeign-core:3.1.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign.form:feign-form-spring:3.8.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign.form:feign-form:3.8.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: commons-fileupload:commons-fileupload:1.3.3"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign:feign-core:11.8"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign:feign-core:11.8"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign:feign-slf4j:11.8"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign:feign-slf4j:11.8"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign.form:feign-form-spring:3.8.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: commons-fileupload:commons-fileupload:1.3.3"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: commons-io:commons-io:2.11.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: io.github.openfeign.form:feign-form:3.8.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.aliyun.oss:aliyun-sdk-oss:3.15.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.aliyun.oss:aliyun-sdk-oss:3.15.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.apache.httpcomponents:httpclient:4.5.13"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.apache.httpcomponents:httpclient:4.5.13"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.jdom:jdom2:2.0.6.1"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.jdom:jdom2:2.0.6.1"
level=
"project"
/>
...
@@ -280,5 +287,13 @@
...
@@ -280,5 +287,13 @@
<orderEntry
type=
"library"
name=
"Maven: org.apache.commons:commons-compress:1.19"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.apache.commons:commons-compress:1.19"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.github.virtuald:curvesapi:1.06"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.github.virtuald:curvesapi:1.06"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.apache.xmlbeans:xmlbeans:3.1.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.apache.xmlbeans:xmlbeans:3.1.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.jodconverter:jodconverter-core:4.4.7"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.jodconverter:jodconverter-local:4.4.7"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.openoffice:juh:4.1.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.openoffice:jurt:4.1.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.openoffice:ridl:4.1.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.openoffice:unoil:4.1.2"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.itextpdf:itextpdf:5.5.13"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.itextpdf:itext-asian:5.2.0"
level=
"project"
/>
</component>
</component>
</module>
</module>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment