Skip to content

Commit

Permalink
增加originFileId字段,支持附件拷贝,共享文件存储
Browse files Browse the repository at this point in the history
  • Loading branch information
entropy-cloud committed Jul 23, 2024
1 parent 9d91677 commit 2b73a1e
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 17 deletions.
11 changes: 11 additions & 0 deletions docs/dev-guide/graphql/upload.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,17 @@ FileStatus会返回文件的名称、大小等信息。

`control.xlib`中的`<view-file>`用于在前台显示文件下载链接,它会使用FileStatus中的信息来获取文件名等。

## 文件共享
IOrmEntityFileStore提供了copyFile函数,可以根据指定fileId复制一份NopFileRecord记录,从而允许多个附件字段复用同一个文件存储。

```javascript
String copyFile(String fileId, String newBizObjName, String newObjId, String newFieldName);
```

* copyFile返回一个新的fileId
* 在NopFileRecord记录上增加了originFileId字段,从同一个NopFileRecord复制得到的记录都具有同样的originFileId值。
* detachFile的时候会检查当前记录是否是最后一个共享originFileId的记录。如果是,则也删除文件存储中的文件,否则只删除对应的NopFileRecord。

## 配置变量

* nop.file.store-dir
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4624,6 +4624,13 @@
"java.util.function.Consumer"
]
},
{
"name": "format",
"parameterTypes": [
"java.lang.String",
"[Ljava.lang.Object;"
]
},
{
"name": "formatDate",
"parameterTypes": [
Expand Down Expand Up @@ -16484,6 +16491,10 @@
"name": "getValue",
"parameterTypes": []
},
{
"name": "isIocIgnoreDepends",
"parameterTypes": []
},
{
"name": "isIocSkipIfEmpty",
"parameterTypes": []
Expand All @@ -16498,6 +16509,12 @@
"io.nop.core.lang.json.IJsonHandler"
]
},
{
"name": "setIocIgnoreDepends",
"parameterTypes": [
"boolean"
]
},
{
"name": "setIocSkipIfEmpty",
"parameterTypes": [
Expand Down Expand Up @@ -18620,6 +18637,10 @@
"name": "getIdProp",
"parameterTypes": []
},
{
"name": "getLabelProp",
"parameterTypes": []
},
{
"name": "getMaxBatchLoadSize",
"parameterTypes": []
Expand Down Expand Up @@ -18708,6 +18729,10 @@
"name": "getShardPropId",
"parameterTypes": []
},
{
"name": "getStateProp",
"parameterTypes": []
},
{
"name": "getTableName",
"parameterTypes": []
Expand Down
1 change: 1 addition & 0 deletions nop-file/deploy/sql/mysql/_create_nop-file.sql
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ CREATE TABLE nop_file_record(
BIZ_OBJ_ID VARCHAR(200) NULL COMMENT '对象ID',
FIELD_NAME VARCHAR(100) NULL COMMENT '字段名',
FILE_HASH VARCHAR(200) NULL COMMENT '文件摘要',
ORIGIN_FILE_ID VARCHAR(50) NOT NULL COMMENT '原始文件ID',
DEL_FLAG TINYINT NOT NULL COMMENT '删除标识',
CREATED_BY VARCHAR(50) NOT NULL COMMENT '创建人',
CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
Expand Down
3 changes: 3 additions & 0 deletions nop-file/deploy/sql/oracle/_create_nop-file.sql
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ CREATE TABLE nop_file_record(
BIZ_OBJ_ID VARCHAR2(200) ,
FIELD_NAME VARCHAR2(100) ,
FILE_HASH VARCHAR2(200) ,
ORIGIN_FILE_ID VARCHAR2(50) NOT NULL ,
DEL_FLAG SMALLINT NOT NULL ,
CREATED_BY VARCHAR2(50) NOT NULL ,
CREATE_TIME TIMESTAMP NOT NULL ,
Expand Down Expand Up @@ -43,6 +44,8 @@ CREATE TABLE nop_file_record(

COMMENT ON COLUMN nop_file_record.FILE_HASH IS '文件摘要';

COMMENT ON COLUMN nop_file_record.ORIGIN_FILE_ID IS '原始文件ID';

COMMENT ON COLUMN nop_file_record.DEL_FLAG IS '删除标识';

COMMENT ON COLUMN nop_file_record.CREATED_BY IS '创建人';
Expand Down
3 changes: 3 additions & 0 deletions nop-file/deploy/sql/postgresql/_create_nop-file.sql
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ CREATE TABLE nop_file_record(
BIZ_OBJ_ID VARCHAR(200) ,
FIELD_NAME VARCHAR(100) ,
FILE_HASH VARCHAR(200) ,
ORIGIN_FILE_ID VARCHAR(50) NOT NULL ,
DEL_FLAG INT4 NOT NULL ,
CREATED_BY VARCHAR(50) NOT NULL ,
CREATE_TIME TIMESTAMP NOT NULL ,
Expand Down Expand Up @@ -43,6 +44,8 @@ CREATE TABLE nop_file_record(

COMMENT ON COLUMN nop_file_record.FILE_HASH IS '文件摘要';

COMMENT ON COLUMN nop_file_record.ORIGIN_FILE_ID IS '原始文件ID';

COMMENT ON COLUMN nop_file_record.DEL_FLAG IS '删除标识';

COMMENT ON COLUMN nop_file_record.CREATED_BY IS '创建人';
Expand Down
Binary file modified nop-file/model/nop-file.orm.xlsx
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -64,31 +64,35 @@ public class _NopFileRecord extends DynamicOrmEntity{
public static final String PROP_NAME_fileHash = "fileHash";
public static final int PROP_ID_fileHash = 11;

/* 原始文件ID: ORIGIN_FILE_ID VARCHAR */
public static final String PROP_NAME_originFileId = "originFileId";
public static final int PROP_ID_originFileId = 12;

/* 删除标识: DEL_FLAG TINYINT */
public static final String PROP_NAME_delFlag = "delFlag";
public static final int PROP_ID_delFlag = 12;
public static final int PROP_ID_delFlag = 13;

/* 创建人: CREATED_BY VARCHAR */
public static final String PROP_NAME_createdBy = "createdBy";
public static final int PROP_ID_createdBy = 13;
public static final int PROP_ID_createdBy = 14;

/* 创建时间: CREATE_TIME TIMESTAMP */
public static final String PROP_NAME_createTime = "createTime";
public static final int PROP_ID_createTime = 14;
public static final int PROP_ID_createTime = 15;

/* 备注: REMARK VARCHAR */
public static final String PROP_NAME_remark = "remark";
public static final int PROP_ID_remark = 15;
public static final int PROP_ID_remark = 16;


private static int _PROP_ID_BOUND = 16;
private static int _PROP_ID_BOUND = 17;



protected static final List<String> PK_PROP_NAMES = Arrays.asList(PROP_NAME_fileId);
protected static final int[] PK_PROP_IDS = new int[]{PROP_ID_fileId};

private static final String[] PROP_ID_TO_NAME = new String[16];
private static final String[] PROP_ID_TO_NAME = new String[17];
private static final Map<String,Integer> PROP_NAME_TO_ID = new HashMap<>();
static{

Expand Down Expand Up @@ -125,6 +129,9 @@ public class _NopFileRecord extends DynamicOrmEntity{
PROP_ID_TO_NAME[PROP_ID_fileHash] = PROP_NAME_fileHash;
PROP_NAME_TO_ID.put(PROP_NAME_fileHash, PROP_ID_fileHash);

PROP_ID_TO_NAME[PROP_ID_originFileId] = PROP_NAME_originFileId;
PROP_NAME_TO_ID.put(PROP_NAME_originFileId, PROP_ID_originFileId);

PROP_ID_TO_NAME[PROP_ID_delFlag] = PROP_NAME_delFlag;
PROP_NAME_TO_ID.put(PROP_NAME_delFlag, PROP_ID_delFlag);

Expand Down Expand Up @@ -173,6 +180,9 @@ public class _NopFileRecord extends DynamicOrmEntity{
/* 文件摘要: FILE_HASH */
private java.lang.String _fileHash;

/* 原始文件ID: ORIGIN_FILE_ID */
private java.lang.String _originFileId;

/* 删除标识: DEL_FLAG */
private java.lang.Byte _delFlag;

Expand Down Expand Up @@ -292,6 +302,9 @@ public Object orm_propValue(int propId) {
case PROP_ID_fileHash:
return getFileHash();

case PROP_ID_originFileId:
return getOriginFileId();

case PROP_ID_delFlag:
return getDelFlag();

Expand Down Expand Up @@ -425,6 +438,16 @@ public void orm_propValue(int propId, Object value){
break;
}

case PROP_ID_originFileId:{
java.lang.String typedValue = null;
if(value != null){
typedValue = ConvertHelper.toString(value,
err-> newTypeConversionError(PROP_NAME_originFileId));
}
setOriginFileId(typedValue);
break;
}

case PROP_ID_delFlag:{
java.lang.Byte typedValue = null;
if(value != null){
Expand Down Expand Up @@ -551,6 +574,13 @@ public void orm_internalSet(int propId, Object value) {
break;
}

case PROP_ID_originFileId:{
onInitProp(propId);
this._originFileId = (java.lang.String)value;

break;
}

case PROP_ID_delFlag:{
onInitProp(propId);
this._delFlag = (java.lang.Byte)value;
Expand Down Expand Up @@ -794,6 +824,25 @@ public void setFileHash(java.lang.String value){
}
}

/**
* 原始文件ID: ORIGIN_FILE_ID
*/
public java.lang.String getOriginFileId(){
onPropGet(PROP_ID_originFileId);
return _originFileId;
}

/**
* 原始文件ID: ORIGIN_FILE_ID
*/
public void setOriginFileId(java.lang.String value){
if(onPropSet(PROP_ID_originFileId,value)){
this._originFileId = value;
internalClearRefs(PROP_ID_originFileId);

}
}

/**
* 删除标识: DEL_FLAG
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
*/
package io.nop.file.dao.store;

import io.nop.api.core.beans.FilterBeans;
import io.nop.api.core.beans.TreeBean;
import io.nop.api.core.beans.file.FileStatusBean;
import io.nop.api.core.beans.query.QueryBean;
import io.nop.api.core.exceptions.NopException;
import io.nop.api.core.util.Guard;
import io.nop.commons.io.stream.LimitedInputStream;
Expand Down Expand Up @@ -40,6 +43,8 @@
import java.util.Objects;
import java.util.concurrent.CompletionStage;

import static io.nop.api.core.beans.FilterBeans.eq;
import static io.nop.api.core.beans.FilterBeans.ne;
import static io.nop.file.core.FileErrors.ARG_BIZ_OBJ_ID;
import static io.nop.file.core.FileErrors.ARG_BIZ_OBJ_NAME;
import static io.nop.file.core.FileErrors.ARG_FIELD_NAME;
Expand Down Expand Up @@ -146,6 +151,7 @@ public String saveFile(UploadRequestBean record, long maxLength) {
String fileId = newFileId();
String filePath = newPath(record.getBizObjName(), fileId, entity.getFileExt());
entity.setFileId(fileId);
entity.setOriginFileId(fileId);
entity.setFilePath(filePath);

IResource tempResource = null;
Expand Down Expand Up @@ -214,6 +220,18 @@ protected String newPath(String bizObjName, String fileId, String fileExt) {

@Override
public FileStatusBean getFileStatus(String fileId, String bizObjName, String objId, String fieldName) {
NopFileRecord record = getRecord(fileId, bizObjName, objId, fieldName);
if (record == null)
return null;
FileStatusBean ret = new FileStatusBean();
ret.setFileId(record.getFileId());
ret.setName(record.getFileName());
ret.setLastModified(record.getFileLastModified() == null ? -1L : record.getFileLastModified().getTime());
ret.setSize(record.getFileLength() == null ? -1L : record.getFileLength());
return ret;
}

private NopFileRecord getRecord(String fileId, String bizObjName, String objId, String fieldName) {
NopFileRecord record = daoProvider.daoFor(NopFileRecord.class).getEntityById(fileId);
if (record == null)
return null;
Expand All @@ -224,12 +242,7 @@ public FileStatusBean getFileStatus(String fileId, String bizObjName, String obj
.param(ARG_BIZ_OBJ_NAME, bizObjName)
.param(ARG_BIZ_OBJ_ID, objId)
.param(ARG_FIELD_NAME, fieldName);
FileStatusBean ret = new FileStatusBean();
ret.setFileId(record.getFileId());
ret.setName(record.getFileName());
ret.setLastModified(record.getFileLastModified() == null ? -1L : record.getFileLastModified().getTime());
ret.setSize(record.getFileLength() == null ? -1L : record.getFileLength());
return ret;
return record;
}

@Override
Expand Down Expand Up @@ -259,13 +272,25 @@ public void detachFile(String fileId, String bizObjName, String objId, String fi
if (record != null) {
if (Objects.equals(record.getBizObjName(), bizObjName) && Objects.equals(record.getBizObjId(), objId)) {
dao.deleteEntity(record);
removeResource(record.getFilePath());
if (isUniqueRef(dao, record))
removeResource(record.getFilePath());
} else {
LOG.warn("nop.file.record-not-attached-to-object:fileId={},bizObjName={},objId={},attachedObjName={},attachedObjId={}", fileId, bizObjName, objId, record.getBizObjName(), record.getBizObjId());
}
}
}

protected boolean isUniqueRef(IEntityDao<NopFileRecord> dao, NopFileRecord record) {
// originFileId与当前记录相同,但是又不是当前记录
QueryBean query = new QueryBean();
TreeBean filter = FilterBeans.and(
eq(NopFileRecord.PROP_NAME_originFileId, record.getOriginFileId()),
ne(NopFileRecord.PROP_NAME_fileId, record.getFileId()));
query.addFilter(filter);

return dao.findFirstByQuery(query) == null;
}

@Override
public void attachFile(String fileId, String bizObjName, String objId, String fieldName) {
IEntityDao<NopFileRecord> dao = daoProvider.daoFor(NopFileRecord.class);
Expand All @@ -277,4 +302,23 @@ public void attachFile(String fileId, String bizObjName, String objId, String fi
record.setFieldName(fieldName);
dao.updateEntity(record);
}

@Override
public String copyFile(String fileId, String newBizObjName, String newObjId, String newFieldName) {
IEntityDao<NopFileRecord> dao = daoProvider.daoFor(NopFileRecord.class);
NopFileRecord record = dao.requireEntityById(fileId);
NopFileRecord newRecord = dao.newEntity();
newRecord.setBizObjName(newBizObjName);
newRecord.setBizObjId(newObjId);
newRecord.setFieldName(newFieldName);
newRecord.setOriginFileId(record.getFileId());
newRecord.setFileExt(record.getFileExt());
newRecord.setFileLength(record.getFileLength());
newRecord.setFileName(record.getFileName());
newRecord.setFilePath(record.getFilePath());
newRecord.setFileHash(record.getFileHash());
newRecord.setFileLastModified(record.getFileLastModified());
dao.saveEntity(newRecord);
return newRecord.getFileId();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,18 @@
stdDataType="string" stdSqlType="VARCHAR" i18n-en:displayName="Field Name"/>
<column code="FILE_HASH" displayName="文件摘要" name="fileHash" precision="200" propId="11"
stdDataType="string" stdSqlType="VARCHAR" i18n-en:displayName="File Hash"/>
<column code="DEL_FLAG" displayName="删除标识" domain="delFlag" mandatory="true" name="delFlag" propId="12"
<column code="ORIGIN_FILE_ID" comment="原始文件ID,用于跟踪哪些文件是从同一个文件复制而来" displayName="原始文件ID" mandatory="true"
name="originFileId" precision="50" propId="12" stdDataType="string" stdSqlType="VARCHAR"
i18n-en:displayName="Original File ID"/>
<column code="DEL_FLAG" displayName="删除标识" domain="delFlag" mandatory="true" name="delFlag" propId="13"
stdDataType="byte" stdDomain="boolFlag" stdSqlType="TINYINT" i18n-en:displayName="Deleted"
ui:show="X"/>
<column code="CREATED_BY" displayName="创建人" domain="createdBy" mandatory="true" name="createdBy"
precision="50" propId="13" stdDataType="string" stdSqlType="VARCHAR"
precision="50" propId="14" stdDataType="string" stdSqlType="VARCHAR"
i18n-en:displayName="Created By"/>
<column code="CREATE_TIME" displayName="创建时间" domain="createTime" mandatory="true" name="createTime"
propId="14" stdDataType="timestamp" stdSqlType="TIMESTAMP" i18n-en:displayName="Create Time"/>
<column code="REMARK" displayName="备注" name="remark" precision="200" propId="15" stdDataType="string"
propId="15" stdDataType="timestamp" stdSqlType="TIMESTAMP" i18n-en:displayName="Create Time"/>
<column code="REMARK" displayName="备注" name="remark" precision="200" propId="16" stdDataType="string"
stdSqlType="VARCHAR" i18n-en:displayName="Remark"/>
</columns>
</entity>
Expand Down
2 changes: 2 additions & 0 deletions nop-orm/src/main/java/io/nop/orm/IOrmEntityFileStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,6 @@ void detachFile(String fileId, String bizObjName,

void attachFile(String fileId, String bizObjName,
String objId, String fieldName);

String copyFile(String fileId, String newBizObjName, String newObjId, String newFieldName);
}

0 comments on commit 2b73a1e

Please sign in to comment.