Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
Y
yudao-cloud
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
hblj
yudao-cloud
Commits
34ea1db5
提交
34ea1db5
authored
7月 09, 2022
作者:
YunaiV
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
优化文件的 type 识别与存储
上级
fec84f26
隐藏空白字符变更
内嵌
并排
正在显示
5 个修改的文件
包含
55 行增加
和
18 行删除
+55
-18
FileUtils.java
.../cn/iocoder/yudao/framework/common/util/io/FileUtils.java
+23
-0
FileTypeUtils.java
...ocoder/yudao/framework/file/core/utils/FileTypeUtils.java
+25
-6
FileDO.java
...ocoder/yudao/module/infra/dal/dataobject/file/FileDO.java
+1
-5
FileServiceImpl.java
...oder/yudao/module/infra/service/file/FileServiceImpl.java
+3
-4
FileServiceTest.java
...oder/yudao/module/infra/service/file/FileServiceTest.java
+3
-3
没有找到文件。
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/io/FileUtils.java
浏览文件 @
34ea1db5
package
cn
.
iocoder
.
yudao
.
framework
.
common
.
util
.
io
;
package
cn
.
iocoder
.
yudao
.
framework
.
common
.
util
.
io
;
import
cn.hutool.core.io.FileTypeUtil
;
import
cn.hutool.core.io.FileUtil
;
import
cn.hutool.core.io.FileUtil
;
import
cn.hutool.core.io.file.FileNameUtil
;
import
cn.hutool.core.util.IdUtil
;
import
cn.hutool.core.util.IdUtil
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.crypto.digest.DigestUtil
;
import
lombok.SneakyThrows
;
import
lombok.SneakyThrows
;
import
java.io.ByteArrayInputStream
;
import
java.io.File
;
import
java.io.File
;
/**
/**
...
@@ -58,4 +63,22 @@ public class FileUtils {
...
@@ -58,4 +63,22 @@ public class FileUtils {
return
file
;
return
file
;
}
}
/**
* 生成文件路径
*
* @param content 文件内容
* @param originalName 原始文件名
* @return path,唯一不可重复
*/
public
static
String
generatePath
(
byte
[]
content
,
String
originalName
)
{
String
sha256Hex
=
DigestUtil
.
sha256Hex
(
content
);
// 情况一:如果存在 name,则优先使用 name 的后缀
if
(
StrUtil
.
isNotBlank
(
originalName
))
{
String
extName
=
FileNameUtil
.
extName
(
originalName
);
return
StrUtil
.
isBlank
(
extName
)
?
sha256Hex
:
sha256Hex
+
"."
+
extName
;
}
// 情况二:基于 content 计算
return
sha256Hex
+
'.'
+
FileTypeUtil
.
getType
(
new
ByteArrayInputStream
(
content
));
}
}
}
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/utils/FileTypeUtils.java
浏览文件 @
34ea1db5
...
@@ -4,8 +4,6 @@ import com.alibaba.ttl.TransmittableThreadLocal;
...
@@ -4,8 +4,6 @@ import com.alibaba.ttl.TransmittableThreadLocal;
import
lombok.SneakyThrows
;
import
lombok.SneakyThrows
;
import
org.apache.tika.Tika
;
import
org.apache.tika.Tika
;
import
java.io.ByteArrayInputStream
;
/**
/**
* 文件类型 Utils
* 文件类型 Utils
*
*
...
@@ -16,14 +14,35 @@ public class FileTypeUtils {
...
@@ -16,14 +14,35 @@ public class FileTypeUtils {
private
static
final
ThreadLocal
<
Tika
>
TIKA
=
TransmittableThreadLocal
.
withInitial
(
Tika:
:
new
);
private
static
final
ThreadLocal
<
Tika
>
TIKA
=
TransmittableThreadLocal
.
withInitial
(
Tika:
:
new
);
/**
/**
* 获得文件的 mineType
* 获得文件的 mineType
,对于doc,jar等文件会有误差
*
*
* @param data
文件内容
* @param data
包含文件开头几千个字节的字节数组
* @return mineType
* @return mineType
无法识别时会返回“application/octet-stream”
*/
*/
@SneakyThrows
@SneakyThrows
public
static
String
getMineType
(
byte
[]
data
)
{
public
static
String
getMineType
(
byte
[]
data
)
{
return
TIKA
.
get
().
detect
(
new
ByteArrayInputStream
(
data
));
return
TIKA
.
get
().
detect
(
data
);
}
/**
* 已知文件名,获取文件类型,在某些情况下比通过字节数组准确,例如使用jar文件时,通过名字更为准确
*
* @param name 文件名
* @return mineType 无法识别时会返回“application/octet-stream”
*/
public
static
String
getMineType
(
String
name
)
{
return
TIKA
.
get
().
detect
(
name
);
}
/**
* 在拥有文件和数据的情况下,最好使用此方法,最为准确
*
* @param data 包含文件开头几千个字节的字节数组
* @param name 文件名
* @return mineType 无法识别时会返回“application/octet-stream”
*/
public
static
String
getMineType
(
byte
[]
data
,
String
name
)
{
return
TIKA
.
get
().
detect
(
data
,
name
);
}
}
}
}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java
浏览文件 @
34ea1db5
...
@@ -5,8 +5,6 @@ import com.baomidou.mybatisplus.annotation.KeySequence;
...
@@ -5,8 +5,6 @@ import com.baomidou.mybatisplus.annotation.KeySequence;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
lombok.*
;
import
lombok.*
;
import
java.io.InputStream
;
/**
/**
* 文件表
* 文件表
* 每次文件上传,都会记录一条记录到该表中
* 每次文件上传,都会记录一条记录到该表中
...
@@ -46,9 +44,7 @@ public class FileDO extends BaseDO {
...
@@ -46,9 +44,7 @@ public class FileDO extends BaseDO {
*/
*/
private
String
url
;
private
String
url
;
/**
/**
* 文件类型
* 文件的 MIME 类型,例如 "application/octet-stream"
*
* 通过 {@link cn.hutool.core.io.FileTypeUtil#getType(InputStream)} 获取
*/
*/
private
String
type
;
private
String
type
;
/**
/**
...
...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java
浏览文件 @
34ea1db5
...
@@ -2,8 +2,8 @@ package cn.iocoder.yudao.module.infra.service.file;
...
@@ -2,8 +2,8 @@ package cn.iocoder.yudao.module.infra.service.file;
import
cn.hutool.core.lang.Assert
;
import
cn.hutool.core.lang.Assert
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.crypto.digest.DigestUtil
;
import
cn.iocoder.yudao.framework.common.pojo.PageResult
;
import
cn.iocoder.yudao.framework.common.pojo.PageResult
;
import
cn.iocoder.yudao.framework.common.util.io.FileUtils
;
import
cn.iocoder.yudao.framework.file.core.client.FileClient
;
import
cn.iocoder.yudao.framework.file.core.client.FileClient
;
import
cn.iocoder.yudao.framework.file.core.utils.FileTypeUtils
;
import
cn.iocoder.yudao.framework.file.core.utils.FileTypeUtils
;
import
cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO
;
import
cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO
;
...
@@ -40,10 +40,9 @@ public class FileServiceImpl implements FileService {
...
@@ -40,10 +40,9 @@ public class FileServiceImpl implements FileService {
@SneakyThrows
@SneakyThrows
public
String
createFile
(
String
name
,
String
path
,
byte
[]
content
)
{
public
String
createFile
(
String
name
,
String
path
,
byte
[]
content
)
{
// 计算默认的 path 名
// 计算默认的 path 名
String
type
=
FileTypeUtils
.
getMineType
(
content
);
String
type
=
FileTypeUtils
.
getMineType
(
content
,
name
);
if
(
StrUtil
.
isEmpty
(
path
))
{
if
(
StrUtil
.
isEmpty
(
path
))
{
path
=
DigestUtil
.
md5Hex
(
content
)
path
=
FileUtils
.
generatePath
(
content
,
name
);
+
'.'
+
StrUtil
.
subAfter
(
type
,
'/'
,
true
);
// 文件的后缀
}
}
// 如果 name 为空,则使用 path 填充
// 如果 name 为空,则使用 path 填充
if
(
StrUtil
.
isEmpty
(
name
))
{
if
(
StrUtil
.
isEmpty
(
name
))
{
...
...
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceTest.java
浏览文件 @
34ea1db5
...
@@ -40,7 +40,7 @@ public class FileServiceTest extends BaseDbUnitTest {
...
@@ -40,7 +40,7 @@ public class FileServiceTest extends BaseDbUnitTest {
// mock 数据
// mock 数据
FileDO
dbFile
=
randomPojo
(
FileDO
.
class
,
o
->
{
// 等会查询到
FileDO
dbFile
=
randomPojo
(
FileDO
.
class
,
o
->
{
// 等会查询到
o
.
setPath
(
"yunai"
);
o
.
setPath
(
"yunai"
);
o
.
setType
(
"jpg"
);
o
.
setType
(
"
image/
jpg"
);
o
.
setCreateTime
(
buildTime
(
2021
,
1
,
15
));
o
.
setCreateTime
(
buildTime
(
2021
,
1
,
15
));
});
});
fileMapper
.
insert
(
dbFile
);
fileMapper
.
insert
(
dbFile
);
...
@@ -48,7 +48,7 @@ public class FileServiceTest extends BaseDbUnitTest {
...
@@ -48,7 +48,7 @@ public class FileServiceTest extends BaseDbUnitTest {
fileMapper
.
insert
(
ObjectUtils
.
cloneIgnoreId
(
dbFile
,
o
->
o
.
setPath
(
"tudou"
)));
fileMapper
.
insert
(
ObjectUtils
.
cloneIgnoreId
(
dbFile
,
o
->
o
.
setPath
(
"tudou"
)));
// 测试 type 不匹配
// 测试 type 不匹配
fileMapper
.
insert
(
ObjectUtils
.
cloneIgnoreId
(
dbFile
,
o
->
{
fileMapper
.
insert
(
ObjectUtils
.
cloneIgnoreId
(
dbFile
,
o
->
{
o
.
setType
(
"png"
);
o
.
setType
(
"
image/
png"
);
}));
}));
// 测试 createTime 不匹配
// 测试 createTime 不匹配
fileMapper
.
insert
(
ObjectUtils
.
cloneIgnoreId
(
dbFile
,
o
->
{
fileMapper
.
insert
(
ObjectUtils
.
cloneIgnoreId
(
dbFile
,
o
->
{
...
@@ -90,7 +90,7 @@ public class FileServiceTest extends BaseDbUnitTest {
...
@@ -90,7 +90,7 @@ public class FileServiceTest extends BaseDbUnitTest {
assertEquals
(
10L
,
file
.
getConfigId
());
assertEquals
(
10L
,
file
.
getConfigId
());
assertEquals
(
path
,
file
.
getPath
());
assertEquals
(
path
,
file
.
getPath
());
assertEquals
(
url
,
file
.
getUrl
());
assertEquals
(
url
,
file
.
getUrl
());
assertEquals
(
"jpg"
,
file
.
getType
());
assertEquals
(
"
image/
jpg"
,
file
.
getType
());
assertEquals
(
content
.
length
,
file
.
getSize
());
assertEquals
(
content
.
length
,
file
.
getSize
());
}
}
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论