Skip to content

Commit

Permalink
更新附件字段时自动删除此前上传的文件
Browse files Browse the repository at this point in the history
  • Loading branch information
entropy-cloud committed Aug 12, 2023
1 parent b165c9c commit 53e5cfc
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 10 deletions.
1 change: 1 addition & 0 deletions docs/compare/nop-vs-springcloud.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Nop平台没有采用目前业内主流的基础开源框架,而是选择了
| 轮子 | Nop体系 | Spring体系 |
|------------|---------------|---------------------|
| Web框架 | NopGraphQL | SpringMVC |
| 表达式引擎 | XLang | SpringEL |
| 模板引擎 | XLang Xpl | Velocity/Freemarker |
| ORM引擎 | NopORM | JPA/Mybatis |
| IoC容器 | NopIoC | SpringIoC |
Expand Down
Binary file added docs/dev-guide/graphql/field-domain.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/dev-guide/graphql/file-domain.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
90 changes: 90 additions & 0 deletions docs/dev-guide/graphql/upload.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# 文件上传下载

引入nop-quarkus-web-starter或者nop-quarkus-spring-starter依赖后,会自动引入

* nop-file-dao: 包含文件上传下载服务实现
* nop-integration-sso: 包含AmazonS3对象存储支持,阿里云OSS,腾讯云COS,七牛云,京东云,minio都支持这一接口标准。

## Excel数据模型

在Excel数据模型中为字段的domain指定stdDomain=file,表示它保存上传文件的链接地址。

![](file-domain.png)
![](field-domain.png)

根据Excel模型生成orm.xml模型文件中会为字段生成stdDomain配置。

````xml

<orm>
<x:post-extends x:override="replace">
<orm-gen:DefaultPostExtends xpl:lib="/nop/orm/xlib/orm-gen.xlib"/>
</x:post-extends>

<entites>
<entity className="io.nop.auth.dao.entity.NopAuthUser">
<columns>
<column code="AVATAR" displayName="头像" domain="image" name="avatar" precision="100" propId="9"
stdDataType="string" stdDomain="file" stdSqlType="VARCHAR" i18n-en:displayName="Avatar"
ext:show="X"/>
</columns>
</entity>
</entites>
</orm>
````

在编译期执行的`x:post-extends`段会执行标签函数 `<orm-gen:FileComponentSupport/>`,它会为每个文件链接字段生成一个对应的OrmFileComponent属性。

## OrmFileComponent实现文件与实体的绑定

上传文件会将具体文件数据保存到IFileStore中,同时会在数据库中插入NopFileRecord记录,用于保存文件名、文件大小等描述信息。

当实体更新或者删除的时候,会触发IOrmComponent接口上的onEntityFlush和onEntityDelete回调函数,在回调函数中将更新NopFileRecord对象上的bizObjName,bizObjId属性。

## 前端控件

在control.xlib标签库中,根据stdDomain设置会自动为字段选择对应的编辑和显示控件。

`<edit-file>`控件缺省会上传文件到/f/upload这个链接,返回的数据格式为
````
{
status:0,
data:{
value: "文件下载链接"
}
}
````

下载链接为 /f/download/{fileId}

在meta的prop节点上,可以配置以下属性:

* ui:maxUploadSize 控制上传文件的最大大小
* ui:uploadUrl 定制上传文件端点
* ui:accept 可以控制允许的文件后缀,例如 .txt,.md表示只允许上传txt和markddown文件

另外也可以通过全局配置来设置上传控件属性
* nop.file.upload-url 全局指定的上传文件端点,缺省为/f/upload
* nop.file.upload.max-size 全局指定的上传文件大小限制。每个prop上指定的ui:maxUploadSize不能超过这个值,实际起作用的是min(prop.uploadFileSize,global.uploadMaxSize)

## 集成Minio

很多分布式存储都兼容Amazon的S3存储协议,例如阿里云OSS,腾讯云COS,七牛云,京东云,Minio等。

使用如下配置启用Minio支持。

````yaml
nop:
file:
store-impl: oss

integration:
oss:
enabled: true
endpoint: http://localhost:9000
access-key: xxx
secret-key: yyy
````

nop.file.store-impl指定为oss时会使用对象存储来保存文件,否则会使用本地文件系统,存放在/nop/file目录下

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 @@ -46,6 +46,12 @@ public class DaoResourceFileStore implements IFileStore {

private IResourceStore resourceStore;

private boolean keepFileExt = true;

public void setKeepFileExt(boolean keepFileExt) {
this.keepFileExt = keepFileExt;
}

@PostConstruct
public void init() {
Guard.notNull(resourceStore, "resourceStore");
Expand Down Expand Up @@ -73,9 +79,12 @@ public String getFileLink(String fileId) {
public String decodeFileId(String fileLink) {
if (StringHelper.isEmpty(fileLink))
return null;
String fileId = fileLink;
if (fileLink.startsWith(FileConstants.PATH_DOWNLOAD))
return StringHelper.lastPart(fileLink, '/');
return null;
fileId = StringHelper.lastPart(fileLink, '/');
// 除去文件后缀名
fileId = StringHelper.firstPart(fileId, '.');
return fileId;
}

@Override
Expand All @@ -101,7 +110,7 @@ public String saveFile(UploadRequestBean record, long maxLength) {
entity.setMimeType(MediaType.APPLICATION_OCTET_STREAM);

String fileId = newFileId();
String filePath = newPath(record.getBizObjName(), fileId);
String filePath = newPath(record.getBizObjName(), fileId, entity.getFileExt());
entity.setFileId(fileId);
entity.setFilePath(filePath);

Expand All @@ -117,6 +126,7 @@ public String saveFile(UploadRequestBean record, long maxLength) {
is = new LimitedInputStream(is, maxLength);
}
ResourceHelper.writeStream(tempResource, is);
entity.setFileLength(tempResource.length());
filePath = resourceStore.saveResource(filePath, tempResource, null, null);
}

Expand Down Expand Up @@ -154,14 +164,16 @@ protected String newFileId() {
return StringHelper.generateUUID();
}

protected String newPath(String bizObjName, String fileId) {
protected String newPath(String bizObjName, String fileId, String fileExt) {
LocalDate now = DateHelper.currentDate();
StringBuilder sb = new StringBuilder();
sb.append('/').append(bizObjName);
sb.append("/").append(StringHelper.leftPad(String.valueOf(now.getYear()), 4, '0'));
sb.append('/').append(StringHelper.leftPad(String.valueOf(now.getMonthValue()), 2, '0'));
sb.append('/').append(StringHelper.leftPad(String.valueOf(now.getDayOfMonth()), 2, '0'));
sb.append('/').append(fileId);
if (keepFileExt && !StringHelper.isEmpty(fileExt))
sb.append('.').append(fileExt);
return sb.toString();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,17 @@ public void writeToStream(OutputStream os, IStepProgressListener listener) {
}
}

@Override
public boolean delete() {
IFileServiceClient client = factory.newClient();
try {
client.deleteFile(remotePath);
return true;
} finally {
IoHelper.safeClose(client);
}
}

@Override
public long length() {
return getFileStatus().getSize();
Expand Down
7 changes: 3 additions & 4 deletions nop-orm/src/main/java/io/nop/orm/support/OrmEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -297,11 +297,10 @@ public void orm_reset() {
public Object orm_propOldValue(int propId) {
if (oldValues != null) {
Object value = oldValues.get(propId);
if (value == null && !oldValues.containsKey(propId)) {
// 如果没有被修改过,则返回当前值
return orm_propValue(propId);
}
if(value != null || oldValues.containsKey(propId))
return value;
}
// 如果没有被修改过,则返回当前值
return orm_propValue(propId);
}

Expand Down
4 changes: 2 additions & 2 deletions nop-web/src/main/resources/_vfs/nop/web/xlib/control.xlib
Original file line number Diff line number Diff line change
Expand Up @@ -527,8 +527,8 @@
import io.nop.xui.utils.XuiHelper;
const name = propMeta.name
const maxSize = XuiHelper.getMaxUploadSize(propMeta,dispMeta);
const uploadUrl = dispMeta?.uploadUrl || ($config.var('nop.file.upload-url','/f/upload') + '?bizObjName='+bizObjName)
const supportFileLink = dispMeta?.['ui:supportFileLink'] ?? propMeta?.['ui:supportFileLink'] ?? true
const uploadUrl = dispMeta?.uploadUrl || propMeta?.['ui:uploadUrl'] || ($config.var('nop.file.upload-url','/f/upload') + '?bizObjName='+bizObjName)
const supportFileLink = dispMeta?.['ui:supportFileLink'] ?? propMeta?.['ui:supportFileLink'] ?? false
if(supportFileLink){
return {
Expand Down

0 comments on commit 53e5cfc

Please sign in to comment.