REQ-3540: 更新表

This commit is contained in:
yanglin 2025-03-12 11:33:07 +08:00
parent e115a65766
commit 719a11869e
38 changed files with 544 additions and 289 deletions

View File

@ -1,7 +0,0 @@
package cn.axzo.nanopart.doc.api.domain;
/**
* @author yanglin
*/
public class ExtendScopeId {
}

View File

@ -0,0 +1,17 @@
package cn.axzo.nanopart.doc.api.domain;
/**
* @author yanglin
*/
public interface IndexNodeParentScope {
default IndexNodeScope nodeScope() {
return IndexNodeScope.SYSTEM_SCOPE;
}
default String parentCode() {
return "";
}
}

View File

@ -1,8 +1,8 @@
package cn.axzo.nanopart.doc.api.domain;
import cn.axzo.nanopart.doc.api.enums.DatabaseScope;
import cn.axzo.nanopart.doc.api.enums.IndexNodeContext;
import cn.axzo.nanopart.doc.api.enums.NodeScope;
/**
* @author yanglin
@ -13,14 +13,17 @@ public interface IndexNodeScope {
return IndexNodeContext.SYSTEM;
}
default NodeScope scope() {
return NodeScope.NONE;
default DatabaseScope scope() {
return DatabaseScope.NONE;
}
default Long scopeId() {
return 0L;
default String scopeCode() {
return "";
}
IndexNodeScope SYSTEM_SCOPE = new IndexNodeScope() {
};
IndexNodeScope FILE_TEMPLATE_SCOPE = new IndexNodeScope() {
@Override
public IndexNodeContext context() {
@ -35,4 +38,4 @@ public interface IndexNodeScope {
}
};
}
}

View File

@ -4,11 +4,7 @@ package cn.axzo.nanopart.doc.api.domain;
/**
* @author yanglin
*/
public interface NodeCreate extends IndexNodeScope {
default String parentCode() {
return "";
}
public interface NodeCreate extends IndexNodeParentScope {
default String bizCode() {
return "";
@ -30,4 +26,4 @@ public interface NodeCreate extends IndexNodeScope {
return null;
}
}
}

View File

@ -0,0 +1,35 @@
package cn.axzo.nanopart.doc.api.domain;
import cn.axzo.nanopart.doc.api.enums.FileFormat;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter
@Getter
public class OssFile {
/**
* 格式. EXCEL, WORD, PDF
*/
private FileFormat format;
/**
* 大小, bytes大小
*/
private int size;
/**
* oss文件key
*/
private String ossFileKey;
public static OssFile create(FileFormat format, int size, String ossFileKey) {
OssFile ossFile = new OssFile();
ossFile.setFormat(format);
ossFile.setSize(size);
ossFile.setOssFileKey(ossFileKey);
return ossFile;
}
}

View File

@ -0,0 +1,16 @@
package cn.axzo.nanopart.doc.api.enums;
/**
* @author yanglin
*/
public enum DatabaseScope {
//
NONE,
// 企业数据库
ENT_DATABASE,
// 项目数据库
PROJECT_DATABASE,
// 个人数据库: 为单位建的
PERSONAL_FOR_ENT;
}

View File

@ -3,7 +3,7 @@ package cn.axzo.nanopart.doc.api.enums;
/**
* @author yanglin
*/
public enum FileDatabaseType {
public enum DatabaseType {
NONE,
// 平台资料库

View File

@ -10,9 +10,9 @@ public enum IndexNodeState {
VALID,
// 放到回收站
MOVED_TO_TRASH,
// 已删除
DELETED,
// 复制中
COPING,
// 创建中
CREATING
}

View File

@ -1,32 +0,0 @@
package cn.axzo.nanopart.doc.api.enums;
/**
* @author yanglin
*/
public enum NodeScope {
//
NONE,
// 企业数据库
ENT_DATABASE,
// 项目数据库
PROJECT_DATABASE,
// 个人数据库: 为单位建的
PERSONAL_FOR_ENT;
public FileDatabaseType toFileDatabaseType() {
switch (this) {
case ENT_DATABASE:
case PROJECT_DATABASE:
return FileDatabaseType.CREATED_BY_SYSTEM;
case PERSONAL_FOR_ENT:
return FileDatabaseType.CREATED_BY_USER_FOR_ENT;
default:
return FileDatabaseType.NONE;
}
}
public boolean isNone() {
return this == NONE;
}
}

View File

@ -1,7 +1,7 @@
package cn.axzo.nanopart.doc.api.filedb.request;
import cn.axzo.nanopart.doc.api.enums.FileDatabaseState;
import cn.axzo.nanopart.doc.api.enums.FileDatabaseType;
import cn.axzo.nanopart.doc.api.enums.DatabaseType;
import lombok.Getter;
import lombok.Setter;
@ -24,7 +24,7 @@ public class FileDatabaseSearchRequest {
/**
* 资料库类型. CREATED_BY_SYSTEM: 平台资料库, CREATED_BY_USER_FOR_ENT: 专属资料库
*/
private FileDatabaseType type;
private DatabaseType type;
/**
* 资料库名称

View File

@ -3,9 +3,10 @@ package cn.axzo.nanopart.doc.api.filetemplate.request;
import javax.validation.constraints.NotNull;
import com.alibaba.fastjson.JSON;
import cn.axzo.nanopart.doc.api.enums.FileFormat;
import cn.axzo.nanopart.doc.api.util.DefaultIcons;
import com.alibaba.fastjson.JSON;
import lombok.Getter;
import lombok.Setter;

View File

@ -1,10 +1,12 @@
package cn.axzo.nanopart.doc.api.filetemplate.request;
import javax.validation.constraints.NotBlank;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import com.alibaba.fastjson.JSON;
import cn.axzo.nanopart.doc.api.domain.OssFile;
import lombok.Getter;
import lombok.Setter;
@ -13,13 +15,14 @@ import lombok.Setter;
*/
@Setter
@Getter
public class FileTemplateUploadFileRequest extends FileTemplateCreateFileRequest {
public class FileTemplateUploadFileRequest extends NodeCreateFileTemplate {
/**
* ossFileKey
* 上传的文件信息
*/
@NotBlank(message = "ossFileKey不能为空")
private String ossFileKey;
@Valid
@NotNull(message = "上传的文件信息不能为空")
private OssFile ossFile;
@Override
public String toString() {

View File

@ -3,10 +3,7 @@ package cn.axzo.nanopart.doc.api.filetemplate.request;
import javax.validation.constraints.NotBlank;
import cn.axzo.nanopart.doc.api.domain.IndexNodeScope;
import cn.axzo.nanopart.doc.api.domain.NodeCreate;
import cn.axzo.nanopart.doc.api.enums.IndexNodeContext;
import cn.axzo.nanopart.doc.api.enums.NodeScope;
import lombok.Getter;
import lombok.Setter;
@ -43,21 +40,6 @@ abstract class NodeCreateFileTemplate implements NodeCreate {
return "";
}
@Override
public final IndexNodeContext context() {
return IndexNodeScope.FILE_TEMPLATE_SCOPE.context();
}
@Override
public NodeScope scope() {
return IndexNodeScope.FILE_TEMPLATE_SCOPE.scope();
}
@Override
public Long scopeId() {
return IndexNodeScope.FILE_TEMPLATE_SCOPE.scopeId();
}
@Override
public final String description() {
return "";

View File

@ -1,9 +1,11 @@
package cn.axzo.nanopart.doc.api.index;
import java.util.List;
import cn.axzo.nanopart.doc.api.enums.DatabaseScope;
import cn.axzo.nanopart.doc.api.enums.IndexNodeState;
import cn.axzo.nanopart.doc.api.enums.IndexNodeType;
import cn.axzo.nanopart.doc.api.enums.NodeScope;
import lombok.Getter;
import lombok.Setter;
@ -14,15 +16,20 @@ import lombok.Setter;
@Getter
public class IndexNodeInfo {
/**
* 系统编码, 文件编码
*/
private String code;
/**
* 父节点code
*/
private Long parentCode;
/**
* 系统编码, 文件编码
* 根节点code
*/
private String code;
private String rootCode;
/**
* 业务编码, 空间或文件夹在页面上填的编码
@ -42,7 +49,7 @@ public class IndexNodeInfo {
/**
* 作用范围. NONE: , ENT_DATABASE: 企业数据库, PROJECT_DATABASE: 项目数据库, PERSONAL_DATABASE: 个人数据库
*/
private NodeScope scope;
private DatabaseScope scope;
/**
* 作用范围id. 单位数据库存ouId, 项目数据库存workspaceId, 个人数据库存personId
@ -69,4 +76,15 @@ public class IndexNodeInfo {
*/
private IndexNodeState state;
/**
* 子结点
*/
private List<IndexNodeInfo> children;
// !! custom
/**
* 是否可以添加更多的子节点
*/
private boolean addMoreChildren;
}

View File

@ -24,4 +24,4 @@ public class DatabaseOrDirInfo {
* 图标
*/
private String icon;
}
}

View File

@ -5,7 +5,7 @@ import javax.validation.constraints.NotBlank;
import cn.axzo.nanopart.doc.api.domain.NodeCreate;
import cn.axzo.nanopart.doc.api.enums.CooperationAccessOption;
import cn.axzo.nanopart.doc.api.enums.NodeScope;
import cn.axzo.nanopart.doc.api.enums.DatabaseScope;
import lombok.Getter;
import lombok.Setter;
@ -20,11 +20,11 @@ public class TemplateDatabaseCreateDatabaseRequest extends TemplateDatabaseCreat
* 归属. ENT_DATABASE: 企业数据库, PROJECT_DATABASE: 项目数据库
*/
@NotBlank(message = "scope不能为空")
private NodeScope scope;
private DatabaseScope scope;
/**
* 协作模版. ALL_ORGS_IN_PROJECT: 项目内所有企业可见, ORGS_BY_COOPERATE_TYPES: 指定参建单位可见
*/
private CooperationAccessOption accessOption;
}
}

View File

@ -16,25 +16,25 @@ import javax.validation.constraints.NotBlank;
@Getter
public class TemplateDatabaseUpdateDatabaseOrDirInfoRequest {
/**
* 节点编码
*/
@NotBlank(message = "code不能为空")
private String code;
/**
* 节点编码
*/
@NotBlank(message = "code不能为空")
private String code;
/**
* 基础信息, 传了就更新
*/
private DatabaseOrDirInfo databaseOrDirInfo;
/**
* 基础信息, 传了就更新
*/
private DatabaseOrDirInfo databaseOrDirInfo;
/**
* 如果是空间的话, 空间的费用配置, 传了就更新
*/
private DatabaseFeeConfig feeConfig;
/**
* 如果是空间的话, 空间的费用配置, 传了就更新
*/
private DatabaseFeeConfig feeConfig;
/**
* 如果是空间的话, 空间的安全管理配置, 传了就更新
*/
private DatabaseAccessConfig accessConfig;
/**
* 如果是空间的话, 空间的安全管理配置, 传了就更新
*/
private DatabaseAccessConfig accessConfig;
}

View File

@ -1,8 +1,11 @@
package cn.axzo.nanopart.doc.api.templatedb.reqeust;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import cn.axzo.nanopart.doc.api.domain.OssFile;
import lombok.Getter;
import lombok.Setter;
@ -11,12 +14,24 @@ import lombok.Setter;
*/
@Setter
@Getter
public class TemplateDatabaseUploadFileRequest extends TemplateDatabaseCreateFileRequest {
public class TemplateDatabaseUploadFileRequest {
/**
* ossFileKey
* 父节点code
*/
@NotBlank(message = "ossFileKey不能为空")
private String ossFileKey;
private String parentCode;
/**
* 节点名称(文件夹/文件)不能为空
*/
@NotBlank(message = "节点名称不能为空")
private String name;
/**
* 上传的文件信息
*/
@Valid
@NotNull(message = "上传的文件信息不能为空")
private OssFile ossFile;
}

View File

@ -1,12 +1,13 @@
package cn.axzo.nanopart.doc.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@ -19,5 +20,6 @@ public class DocProps {
private String emptyWordOssFileKey;
private String emptyExcelFileKey;
private int maxChildrenSize = 200;
}

View File

@ -7,6 +7,7 @@ import org.springframework.stereotype.Repository;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.axzo.nanopart.doc.api.enums.FileTemplateState;
import cn.axzo.nanopart.doc.api.util.BizAssertions;
import cn.axzo.nanopart.doc.entity.FileTemplate;
import cn.axzo.nanopart.doc.mapper.FileTemplateMapper;
@ -32,6 +33,9 @@ public class FileTemplateDao extends ServiceImpl<FileTemplateMapper, FileTemplat
public void deleteByCodes(Collection<String> codes) {
if (codes == null)
return;
lambdaUpdate().in(FileTemplate::getCode, codes).remove();
lambdaUpdate() //
.in(FileTemplate::getCode, codes) //
.set(FileTemplate::getState, FileTemplateState.DELETED) //
.remove();
}
}

View File

@ -11,6 +11,7 @@ import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.axzo.nanopart.doc.api.domain.IndexNodeParentScope;
import cn.axzo.nanopart.doc.api.domain.IndexNodeScope;
import cn.axzo.nanopart.doc.api.enums.IndexNodeState;
import cn.axzo.nanopart.doc.api.util.BizAssertions;
@ -86,6 +87,7 @@ public class IndexNodeDao extends ServiceImpl<IndexNodeMapper, IndexNode> {
public void deleteSubtree(String code) {
lambdaUpdate() //
.likeRight(IndexNode::getPath, code) //
.set(IndexNode::getState, IndexNodeState.DELETED) //
.update();
}
@ -95,6 +97,12 @@ public class IndexNodeDao extends ServiceImpl<IndexNodeMapper, IndexNode> {
.list();
}
public int countValidChild(IndexNodeParentScope parentScope) {
return parentOrScopeQuery(parentScope.nodeScope(), parentScope.parentCode()) //
.eq(IndexNode::getState, IndexNodeState.VALID) //
.count();
}
private LambdaQueryChainWrapper<IndexNode> parentOrScopeQuery(IndexNodeScope nodeScope, String parentCode) {
if (StringUtils.isBlank(parentCode))
return scopeQuery(nodeScope);
@ -105,7 +113,7 @@ public class IndexNodeDao extends ServiceImpl<IndexNodeMapper, IndexNode> {
return lambdaQuery() //
.eq(IndexNode::getContext, nodeScope.context()) //
.eq(IndexNode::getScope, nodeScope.scope()) //
.eq(IndexNode::getScopeId, nodeScope.scopeId()).eq(IndexNode::getParentCode, "");
.eq(IndexNode::getScopeCode, nodeScope.scopeCode()).eq(IndexNode::getParentCode, "");
}
}

View File

@ -6,10 +6,9 @@ import java.util.Date;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotation.TableName;
import cn.axzo.nanopart.doc.api.domain.ExtendScopeId;
import cn.axzo.nanopart.doc.api.enums.DatabaseScope;
import cn.axzo.nanopart.doc.api.enums.DatabaseType;
import cn.axzo.nanopart.doc.api.enums.FileDatabaseState;
import cn.axzo.nanopart.doc.api.enums.FileDatabaseType;
import cn.axzo.nanopart.doc.api.enums.NodeScope;
import cn.axzo.nanopart.doc.api.util.YesOrNo;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import lombok.Getter;
@ -41,22 +40,27 @@ public class FileDatabase extends BaseEntity<FileDatabase> {
/**
* 资料库类型. CREATED_BY_SYSTEM: 平台资料库, CREATED_BY_USER_FOR_ENT: 专属资料库
*/
private FileDatabaseType type;
private DatabaseType type;
/**
* 作用范围. NONE: , ENT_DATABASE: 企业数据库, PROJECT_DATABASE: 项目数据库, PERSONAL_DATABASE: 个人数据库
*/
private NodeScope scope;
private DatabaseScope scope;
/**
* 作用范围id. 单位数据库存ouId, 项目数据库存workspaceId, 个人数据库存personId
* 人员id
*/
private Long scopeId;
private Long personId;
/**
* 存更多的scope相关的信息
* 项目id
*/
private ExtendScopeId extendScopeId;
private Long workspaceId;
/**
* 单位id
*/
private Long ouId;
/**
* 状态. ACTIVATING: 开通中, ACTIVATED: 已开通, EXPIRED: 已到期

View File

@ -8,11 +8,12 @@ import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import cn.axzo.maokai.api.vo.response.tree.NodeValue;
import cn.axzo.nanopart.doc.api.domain.IndexNodeAttributes;
import cn.axzo.nanopart.doc.api.domain.NodeCreate;
import cn.axzo.nanopart.doc.api.domain.IndexNodeParentScope;
import cn.axzo.nanopart.doc.api.domain.IndexNodeScope;
import cn.axzo.nanopart.doc.api.enums.DatabaseScope;
import cn.axzo.nanopart.doc.api.enums.IndexNodeContext;
import cn.axzo.nanopart.doc.api.enums.IndexNodeState;
import cn.axzo.nanopart.doc.api.enums.IndexNodeType;
import cn.axzo.nanopart.doc.api.enums.NodeScope;
import cn.axzo.nanopart.doc.api.util.UUIDUtil;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import lombok.Getter;
@ -24,9 +25,7 @@ import lombok.Setter;
@Setter
@Getter
@TableName(value = "doc_index_node", autoResultMap = true)
public class IndexNode extends BaseEntity<IndexNode> implements NodeCreate, NodeValue {
public static final String ROOT_CODE = "";
public class IndexNode extends BaseEntity<IndexNode> implements NodeValue, IndexNodeParentScope, IndexNodeScope {
public static String newCode() {
return UUIDUtil.uuidString();
@ -37,15 +36,20 @@ public class IndexNode extends BaseEntity<IndexNode> implements NodeCreate, Node
*/
private Long parentId;
/**
* 系统编码
*/
private String code;
/**
* 父节点code
*/
private String parentCode;
/**
* 系统编码
* 根节点code
*/
private String code;
private String rootCode;
/**
* 节点名称
@ -70,12 +74,12 @@ public class IndexNode extends BaseEntity<IndexNode> implements NodeCreate, Node
/**
* 作用范围. NONE: , ENT_DATABASE: 企业数据库, PROJECT_DATABASE: 项目数据库, PERSONAL_DATABASE: 个人数据库
*/
private NodeScope scope;
private DatabaseScope scope;
/**
* 作用范围id. 单位数据库存ouId, 项目数据库存workspaceId, 个人数据库存personId
*/
private Long scopeId;
private String scopeCode;
/**
* 路径, id拼起来, 以斜杠开头和结束. /1/2/3/
@ -118,51 +122,6 @@ public class IndexNode extends BaseEntity<IndexNode> implements NodeCreate, Node
return nodeType == IndexNodeType.FILE;
}
@Override
public String parentCode() {
return parentCode;
}
@Override
public String bizCode() {
return bizCode;
}
@Override
public String name() {
return name;
}
@Override
public String description() {
return description;
}
@Override
public String icon() {
return icon;
}
@Override
public IndexNodeAttributes attributes() {
return attributes.copy();
}
@Override
public IndexNodeContext context() {
return context;
}
@Override
public NodeScope scope() {
return scope;
}
@Override
public Long scopeId() {
return scopeId;
}
@Override
public String toString() {
return JSON.toJSONString(this);
@ -182,4 +141,29 @@ public class IndexNode extends BaseEntity<IndexNode> implements NodeCreate, Node
public boolean isValueRoot() {
return parentId == 0;
}
@Override
public IndexNodeContext context() {
return context;
}
@Override
public DatabaseScope scope() {
return scope;
}
@Override
public String scopeCode() {
return scopeCode;
}
@Override
public IndexNodeScope nodeScope() {
return this;
}
@Override
public String parentCode() {
return parentCode;
}
}

View File

@ -1,7 +1,7 @@
package cn.axzo.nanopart.doc.entity;
import cn.axzo.nanopart.doc.api.enums.NodeScope;
import cn.axzo.nanopart.doc.api.enums.DatabaseScope;
import cn.axzo.nanopart.doc.api.domain.DatabaseAccessConfig;
import cn.axzo.nanopart.doc.api.domain.DatabaseFeeConfig;
import com.alibaba.fastjson.JSON;
@ -29,7 +29,7 @@ public class TemplateDatabase extends BaseEntity<TemplateDatabase> {
/**
* 作用范围. NONE: , ENT_DATABASE: 企业数据库, PROJECT_DATABASE: 项目数据库, PERSONAL_DATABASE: 个人数据库
*/
private NodeScope scope;
private DatabaseScope scope;
/**
* 费用配置

View File

@ -1,18 +0,0 @@
package cn.axzo.nanopart.doc.file;
import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor;
/**
* @author yanglin
*/
@Component
@RequiredArgsConstructor
public class FileBroadcaster {
public void fireRenameOssFileEvent(String indexNodeCode) {
// TODO(yl): finish this
}
}

View File

@ -4,6 +4,7 @@ package cn.axzo.nanopart.doc.file.filetemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
import cn.axzo.nanopart.doc.api.domain.OssFile;
import cn.axzo.nanopart.doc.api.enums.FileTemplateState;
import cn.axzo.nanopart.doc.api.enums.IndexNodeType;
import cn.axzo.nanopart.doc.api.filetemplate.request.FileTemplateCreateDirRequest;
@ -16,7 +17,6 @@ import cn.axzo.nanopart.doc.entity.FileTemplate;
import cn.axzo.nanopart.doc.entity.IndexNode;
import cn.axzo.nanopart.doc.file.index.IndexManager;
import cn.axzo.nanopart.doc.file.index.domain.IndexNodes;
import cn.axzo.nanopart.doc.file.index.domain.OssFile;
import cn.axzo.nanopart.doc.utils.BizTransactional;
import lombok.RequiredArgsConstructor;
@ -42,7 +42,7 @@ public class FileTemplateManager {
@BizTransactional
public String uploadFile(FileTemplateUploadFileRequest request) {
return createFileTemplate(indexManager.uploadFile(request, request.getFormat(), request.getOssFileKey()));
return createFileTemplate(indexManager.uploadFile(request, request.getOssFile()));
}
private String createFileTemplate(IndexNode fileNode) {

View File

@ -5,17 +5,19 @@ import java.util.List;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionTemplate;
import cn.axzo.maokai.api.util.Ref;
import cn.axzo.nanopart.doc.api.domain.NodeCreate;
import cn.axzo.nanopart.doc.api.domain.OssFile;
import cn.axzo.nanopart.doc.api.enums.FileFormat;
import cn.axzo.nanopart.doc.api.enums.IndexNodeType;
import cn.axzo.nanopart.doc.api.util.BizAssertions;
import cn.axzo.nanopart.doc.config.DocProps;
import cn.axzo.nanopart.doc.dao.IndexNodeDao;
import cn.axzo.nanopart.doc.entity.IndexNode;
import cn.axzo.nanopart.doc.file.FileBroadcaster;
import cn.axzo.nanopart.doc.file.index.domain.NameUsedException;
import cn.axzo.nanopart.doc.file.index.domain.OssFile;
import cn.axzo.nanopart.doc.file.mq.FileBroadcaster;
import cn.axzo.nanopart.doc.integration.OssClient;
import cn.axzo.nanopart.doc.utils.BizTransactional;
import lombok.RequiredArgsConstructor;
@ -34,19 +36,20 @@ public class IndexManager {
private final OssClient ossClient;
private final DocProps docProps;
private final FileBroadcaster fileBroadcaster;
private final TransactionTemplate transactionTemplate;
@BizTransactional
public IndexNode createDatabase(NodeCreate node) {
indexSupport.lockParentAndReleaseOnCommit(node);
indexSupport.ensureChildNameNotUsed(node);
return indexSupport.createNode(node, IndexNodeType.DATABASE);
public IndexNode createDatabase(NodeCreate create) {
indexSupport.lockParentAndReleaseOnCommit(create);
indexSupport.ensureChildNameNotUsed(create);
return indexSupport.createNode(create, IndexNodeType.DATABASE);
}
@BizTransactional
public IndexNode createDir(NodeCreate node) {
indexSupport.lockParentAndReleaseOnCommit(node);
indexSupport.ensureChildNameNotUsed(node);
return indexSupport.createNode(node, IndexNodeType.DIRECTORY);
public IndexNode createDir(NodeCreate create) {
indexSupport.lockParentAndReleaseOnCommit(create);
indexSupport.ensureChildNameNotUsed(create);
return indexSupport.createNode(create, IndexNodeType.DIRECTORY);
}
/**
@ -59,45 +62,50 @@ public class IndexManager {
String emptyOssFileKey = format == FileFormat.WORD //
? docProps.getEmptyWordOssFileKey() //
: docProps.getEmptyExcelFileKey();
String code = IndexNode.newCode();
return new OssFile(format, code, ossClient.copy(emptyOssFileKey, format, node.name()));
return OssFile.create(format, 0, ossClient.copy(emptyOssFileKey, format, node.name()));
}
@BizTransactional
public IndexNode uploadFile(NodeCreate node, FileFormat format, String ossFileKey) {
public IndexNode uploadFile(NodeCreate node, OssFile ossFile) {
indexSupport.ensureChildNameNotUsed(node);
String code = IndexNode.newCode();
OssFile ossFile = new OssFile(format, code, ossFileKey);
return createFile(node, ossFile);
}
@BizTransactional
public IndexNode createFile(NodeCreate node, OssFile ossFile) {
indexSupport.lockParentAndReleaseOnCommit(node);
Ref<Boolean> deleteOssFile = Ref.create(false);
try {
indexSupport.ensureChildNameNotUsed(node);
return transactionTemplate.execute(unused -> {
indexSupport.lockParentAndReleaseOnCommit(node);
try {
indexSupport.ensureChildNameNotUsed(node);
}
catch (NameUsedException e) {
deleteOssFile.set(true);
throw e;
}
IndexNode fileNode = indexSupport.createNode(node, IndexNodeType.FILE);
fileNode.getOrCreateAttributes().getOrCreateFileAttributes().setOssFileKey(ossFile.getOssFileKey());
fileNode.getOrCreateAttributes().getOrCreateFileAttributes().setFileFormat(ossFile.getFormat());
indexNodeDao.updateAttributes(fileNode);
return indexNodeDao.findNodeOrNull(fileNode.getCode());
});
}
catch (NameUsedException e) {
ossClient.asyncDelete(ossFile.ossFileKey());
throw e;
finally {
if (deleteOssFile.get())
fileBroadcaster.fireDeleteOssFile(ossFile.getOssFileKey(), "create file failed");
}
IndexNode fileNode = indexSupport.createNode(ossFile.code(), node, IndexNodeType.FILE);
fileNode.getOrCreateAttributes().getOrCreateFileAttributes().setOssFileKey(ossFile.ossFileKey());
fileNode.getOrCreateAttributes().getOrCreateFileAttributes().setFileFormat(ossFile.format());
indexNodeDao.updateAttributes(fileNode);
return indexNodeDao.findNodeOrNull(fileNode.getCode());
}
@BizTransactional
public void rename(String code, String newName) {
IndexNode indexNode = indexNodeDao.getNodeOrThrow(code);
indexSupport.lockParentAndReleaseOnCommit(indexNode);
if (indexNode.name().equals(newName))
if (indexNode.getName().equals(newName))
return;
indexSupport.ensureChildNameNotUsed(indexNode, indexNode.getParentCode(), newName);
indexNodeDao.rename(code, newName);
if (indexNode.isFile())
fileBroadcaster.fireRenameOssFileEvent(code);
fileBroadcaster.fireRenameIndexNodeOssFile(code);
}
@BizTransactional

View File

@ -5,9 +5,9 @@ import java.util.List;
import org.springframework.stereotype.Service;
import cn.axzo.nanopart.doc.api.index.request.IndexNodePageSearchRequest;
import cn.axzo.nanopart.doc.api.domain.IndexNodeScope;
import cn.axzo.nanopart.doc.api.enums.IndexNodeState;
import cn.axzo.nanopart.doc.api.index.request.IndexNodePageSearchRequest;
import cn.axzo.nanopart.doc.dao.IndexNodeDao;
import cn.axzo.nanopart.doc.entity.IndexNode;
import cn.azxo.framework.common.model.Page;
@ -31,4 +31,4 @@ public class IndexQueryService {
return null;
}
}
}

View File

@ -7,12 +7,14 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import cn.axzo.nanopart.doc.api.domain.IndexNodeParentScope;
import cn.axzo.nanopart.doc.api.domain.IndexNodeScope;
import cn.axzo.nanopart.doc.api.domain.NodeCreate;
import cn.axzo.nanopart.doc.api.enums.IndexNodeState;
import cn.axzo.nanopart.doc.api.enums.IndexNodeType;
import cn.axzo.nanopart.doc.api.util.BizAssertions;
import cn.axzo.nanopart.doc.api.util.UUIDUtil;
import cn.axzo.nanopart.doc.config.DocProps;
import cn.axzo.nanopart.doc.dao.DocLockDao;
import cn.axzo.nanopart.doc.dao.IndexNodeDao;
import cn.axzo.nanopart.doc.entity.IndexNode;
@ -28,34 +30,38 @@ class IndexSupport {
private final IndexNodeDao indexNodeDao;
private final DocLockDao docLockDao;
private final DocProps docProps;
IndexNode createNode(NodeCreate node, IndexNodeType nodeType) {
return createNode(UUIDUtil.uuidString(), node, nodeType);
}
IndexNode createNode(String code, NodeCreate node, IndexNodeType nodeType) {
// TODO(yl): 检查子节点数量
IndexNode createNode(NodeCreate create, IndexNodeType nodeType) {
String code = UUIDUtil.uuidString();
if (nodeType == IndexNodeType.DATABASE)
BizAssertions.assertBlank(create.parentCode(), "创建空间时不能指定父节点");
BizAssertions.assertFalse(indexNodeDao.countValidChild(create) < docProps.getMaxChildrenSize(), "子节点数量超过限制");
IndexNode parent = null;
if (StringUtils.isNotBlank(node.parentCode())) {
parent = indexNodeDao.getNodeOrThrow(node.parentCode());
BizAssertions.assertEquals(parent.getContext(), node.context(), "创建子节点时父子context不匹配: {}",
node.parentCode());
BizAssertions.assertEquals(parent.getScope(), node.scope(), "创建子节点时父子scope不匹配: {}", node.parentCode());
BizAssertions.assertEquals(parent.getScopeId(), node.scopeId(), "创建子节点时父子scopeId不匹配: {}",
node.parentCode());
if (StringUtils.isNotBlank(create.parentCode())) {
parent = indexNodeDao.getNodeOrThrow(create.parentCode());
BizAssertions.assertEquals(parent.getContext(), create.nodeScope().context(), //
"创建子节点时父子context不匹配: {}", create.parentCode());
BizAssertions.assertEquals(parent.getScope(), create.nodeScope(), //
"创建子节点时父子scope不匹配: {}", create.parentCode());
BizAssertions.assertEquals(parent.getScopeCode(), create.nodeScope().scopeCode(), //
"创建子节点时父子scopeId不匹配: {}", create.parentCode());
if (nodeType == IndexNodeType.DIRECTORY)
BizAssertions.assertFalse(parent.isFile(), "不能在文件下建立文件夹");
}
IndexNode child = new IndexNode();
child.setParentId(parent == null ? 0L : parent.getParentId());
child.setParentCode(parent == null ? IndexNode.ROOT_CODE : parent.getCode());
child.setCode(code);
child.setName(node.name());
child.setBizCode(node.bizCode());
child.setContext(node.context());
child.setScope(node.scope());
child.setDescription(node.description());
child.setIcon(node.icon());
child.setParentId(parent == null ? 0L : parent.getParentId());
child.setParentCode(parent == null ? "" : parent.getCode());
child.setRootCode(parent == null ? child.getCode() : parent.getRootCode());
child.setName(create.name());
child.setBizCode(create.bizCode());
child.setContext(create.nodeScope().context());
child.setScope(create.nodeScope().scope());
child.setDescription(create.description());
child.setIcon(create.icon());
child.setState(IndexNodeState.VALID);
child.setAttributes(node.attributes());
child.setAttributes(create.attributes());
child.setNodeType(nodeType);
child.setSize(0);
indexNodeDao.save(child);
@ -66,8 +72,8 @@ class IndexSupport {
return indexNodeDao.getNodeOrThrow(child.getCode());
}
void ensureChildNameNotUsed(NodeCreate nodeCreate) {
ensureChildNameNotUsed(nodeCreate, nodeCreate.parentCode(), nodeCreate.name());
void ensureChildNameNotUsed(NodeCreate create) {
ensureChildNameNotUsed(create.nodeScope(), create.parentCode(), create.name());
}
void ensureChildNameNotUsed(IndexNodeScope nodeScope, String parentCode, String childName) {
@ -76,8 +82,8 @@ class IndexSupport {
throw new NameUsedException("名称已被使用");
}
void lockParentAndReleaseOnCommit(NodeCreate node) {
lockParentAndReleaseOnCommit(node, node.parentCode());
void lockParentAndReleaseOnCommit(IndexNodeParentScope parentScope) {
lockParentAndReleaseOnCommit(parentScope.nodeScope(), parentScope.parentCode());
}
void lockParentAndReleaseOnCommit(IndexNodeScope nodeScope, String parentCode) {
@ -90,8 +96,8 @@ class IndexSupport {
.append("INDEX_NODE") //
.append(nodeScope.context()) //
.append(nodeScope.scope()) //
.append(nodeScope.scopeId()) //
.append(nodeScope.scopeCode()) //
.build());
}
}
}

View File

@ -1,21 +0,0 @@
package cn.axzo.nanopart.doc.file.index.domain;
import cn.axzo.nanopart.doc.api.enums.FileFormat;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Accessors;
/**
* @author yanglin
*/
@Getter
@Accessors(fluent = true)
@RequiredArgsConstructor
public class OssFile {
private final FileFormat format;
private final String code;
private final String ossFileKey;
}

View File

@ -0,0 +1,46 @@
package cn.axzo.nanopart.doc.file.mq;
import org.springframework.stereotype.Component;
import cn.axzo.framework.rocketmq.Event;
import cn.axzo.framework.rocketmq.EventProducer;
import cn.axzo.nanopart.doc.file.mq.message.DeleteOssFileMessage;
import cn.axzo.nanopart.doc.file.mq.message.RenameIndexNodeOssFileMessage;
import lombok.RequiredArgsConstructor;
/**
* @author yanglin
*/
@Component
@RequiredArgsConstructor
public class FileBroadcaster {
private final EventProducer<?> eventProducer;
public void fireRenameIndexNodeOssFile(String indexNodeCode) {
RenameIndexNodeOssFileMessage message = new RenameIndexNodeOssFileMessage();
message.setIndexNodeCode(indexNodeCode);
eventProducer.send(Event.builder() //
.eventCode(FileInternalEvent.INDEX_NODE_RENAME_OSS_FILE.getEventCode()) //
.shardingKey(indexNodeCode) //
.targetId(indexNodeCode) //
.targetType("index-node") //
.data(message) //
.build());
}
public void fireDeleteOssFile(String ossFileKey, String reason) {
DeleteOssFileMessage message = new DeleteOssFileMessage();
message.setOssFileKey(ossFileKey);
message.setReason(reason);
eventProducer.send(Event.builder() //
.eventCode(FileInternalEvent.OSS_FILE_DELETE.getEventCode()) //
.shardingKey(ossFileKey) //
.targetId(ossFileKey) //
.targetType("oss-file") //
.data(message) //
.build());
}
}

View File

@ -0,0 +1,29 @@
package cn.axzo.nanopart.doc.file.mq;
import cn.axzo.framework.rocketmq.Event;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* @author yanglin
*/
@Getter
@RequiredArgsConstructor
public enum FileInternalEvent {
INDEX_NODE_RENAME_OSS_FILE("nanopart-doc", "index-node-rename-oss-file", "修改index node oss文件名"),
OSS_FILE_DELETE("nanopart-doc", "oss-file-delete", "删除oss文件"),;
FileInternalEvent(String model, String name, String desc) {
this.eventCode = Event.EventCode.builder().module(model).name(name).build();
this.model = model;
this.name = name;
this.desc = desc;
}
private final String model;
private final String name;
private final String desc;
private final Event.EventCode eventCode;
}

View File

@ -0,0 +1,48 @@
package cn.axzo.nanopart.doc.file.mq.filehandler;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import cn.axzo.framework.rocketmq.Event;
import cn.axzo.framework.rocketmq.EventConsumer;
import cn.axzo.framework.rocketmq.EventHandler;
import cn.axzo.nanopart.doc.dao.IndexNodeDao;
import cn.axzo.nanopart.doc.entity.IndexNode;
import cn.axzo.nanopart.doc.file.mq.FileInternalEvent;
import cn.axzo.nanopart.doc.file.mq.message.RenameIndexNodeOssFileMessage;
import cn.axzo.nanopart.doc.integration.OssClient;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* @author yanglin
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class IndexNodeRenameOssFileHandler implements EventHandler, InitializingBean {
private final EventConsumer eventConsumer;
private final OssClient ossClient;
private final IndexNodeDao indexNodeDao;
@Override
public void onEvent(Event event, EventConsumer.Context context) {
RenameIndexNodeOssFileMessage message = event.normalizedData(RenameIndexNodeOssFileMessage.class);
log.info("receive rename index node oss file message: {}", message);
IndexNode indexNode = indexNodeDao.findNodeOrNull(message.getIndexNodeCode());
if (indexNode == null)
return;
String ossFileKey = indexNode.getOrCreateAttributes().getOrCreateFileAttributes().getOssFileKey();
if (StringUtils.isNotBlank(ossFileKey))
ossClient.rename(ossFileKey, indexNode.getName());
}
@Override
public void afterPropertiesSet() {
eventConsumer.registerHandler(FileInternalEvent.INDEX_NODE_RENAME_OSS_FILE.getEventCode(), this);
}
}

View File

@ -0,0 +1,43 @@
package cn.axzo.nanopart.doc.file.mq.filehandler;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import cn.axzo.framework.rocketmq.Event;
import cn.axzo.framework.rocketmq.EventConsumer;
import cn.axzo.framework.rocketmq.EventHandler;
import cn.axzo.nanopart.doc.file.mq.FileInternalEvent;
import cn.axzo.nanopart.doc.file.mq.message.DeleteOssFileMessage;
import cn.axzo.nanopart.doc.integration.OssClient;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* @author yanglin
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class OssFileDeleteHandler implements EventHandler, InitializingBean {
private final EventConsumer eventConsumer;
private final OssClient ossClient;
@Override
public void onEvent(Event event, EventConsumer.Context context) {
log.info("receive delete oss file message: {}", event);
DeleteOssFileMessage message = event.normalizedData(DeleteOssFileMessage.class);
try {
ossClient.delete(message.getOssFileKey());
} catch (Exception e) {
log.error("删除oss file失败", e);
}
}
@Override
public void afterPropertiesSet() {
eventConsumer.registerHandler(FileInternalEvent.OSS_FILE_DELETE.getEventCode(), this);
}
}

View File

@ -0,0 +1,17 @@
package cn.axzo.nanopart.doc.file.mq.message;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter
@Getter
public class DeleteOssFileMessage extends MqMessage {
private String ossFileKey;
private String reason;
}

View File

@ -0,0 +1,33 @@
package cn.axzo.nanopart.doc.file.mq.message;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import cn.hutool.core.lang.UUID;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter
@Getter
public abstract class MqMessage implements Serializable {
/**
* 消息唯一id
*/
private String messageId = UUID.randomUUID().toString();
/**
* 消息发送时间
*/
private Date messageSendTime = new Date();
/**
* 消息发送时间, 字符串格式
*/
private String messageSendTimeStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(messageSendTime);
}

View File

@ -0,0 +1,22 @@
package cn.axzo.nanopart.doc.file.mq.message;
import com.alibaba.fastjson.JSON;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter
@Getter
public class RenameIndexNodeOssFileMessage extends MqMessage {
private String indexNodeCode;
@Override
public String toString() {
return JSON.toJSONString(this);
}
}

View File

@ -1,8 +1,6 @@
package cn.axzo.nanopart.doc.integration;
import java.util.Set;
import org.springframework.stereotype.Component;
import cn.axzo.nanopart.doc.api.enums.FileFormat;
@ -20,20 +18,15 @@ public class OssClient {
public String copy(String srcOssFileKey, FileFormat format, String fileName) {
// TODO(yl): finish this
throw new UnsupportedOperationException();
}
public void asyncDelete(String ossFileKey) {
// TODO(yl): finish this
}
public void asyncDelete(Set<String> ossFileKeys) {
// TODO(yl): finish this
return "";
}
public void rename(String ossFileKey, String newName) {
// TODO(yl): finish this
throw new UnsupportedOperationException();
}
public void delete(String ossFileKey) {
// TODO(yl): finish this
}
}