REQ-3540: 解决报错问题

This commit is contained in:
yanglin 2025-03-13 15:36:02 +08:00
parent 1996c2ebf3
commit c1b559134f
13 changed files with 224 additions and 21 deletions

View File

@ -1,8 +1,10 @@
package cn.axzo.nanopart.doc.api.domain;
import java.util.ArrayList;
import java.util.List;
import cn.axzo.maokai.api.vo.response.tree.NodeValue;
import cn.axzo.nanopart.doc.api.enums.DatabaseScope;
import cn.axzo.nanopart.doc.api.enums.IndexNodeState;
import cn.axzo.nanopart.doc.api.enums.IndexNodeType;
@ -14,7 +16,11 @@ import lombok.Setter;
*/
@Setter
@Getter
public class IndexNodeInfo {
public class IndexNodeInfo implements NodeValue {
private Long id;
private Long parentId;
/**
* 系统编码, 文件编码
@ -24,7 +30,7 @@ public class IndexNodeInfo {
/**
* 父节点code
*/
private Long parentCode;
private String parentCode;
/**
* 根节点code
@ -81,6 +87,12 @@ public class IndexNodeInfo {
*/
private List<IndexNodeInfo> children;
public void addChild(IndexNodeInfo child) {
if (children == null)
children = new ArrayList<>();
children.add(child);
}
// !! custom
/**
@ -95,4 +107,24 @@ public class IndexNodeInfo {
private IndexNodeAttributes attributes;
public FileTemplateNodeInfo getOrCreateFileTemplateNodeInfo() {
if (fileTemplateNodeInfo == null)
fileTemplateNodeInfo = new FileTemplateNodeInfo();
return fileTemplateNodeInfo;
}
@Override
public Long id() {
return id;
}
@Override
public Long parentId() {
return parentId;
}
@Override
public boolean isValueRoot() {
return parentId == 0;
}
}

View File

@ -2,7 +2,10 @@
package cn.axzo.nanopart.doc.dao;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Repository;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -38,4 +41,12 @@ public class FileTemplateDao extends ServiceImpl<FileTemplateMapper, FileTemplat
.set(FileTemplate::getState, FileTemplateState.DELETED) //
.remove();
}
public List<FileTemplate> getByCodes(List<String> codes) {
if (CollectionUtils.isEmpty(codes))
return Collections.emptyList();
return lambdaQuery() //
.in(FileTemplate::getCode, codes) //
.list();
}
}

View File

@ -41,7 +41,7 @@ public class IndexNodeDao extends ServiceImpl<IndexNodeMapper, IndexNode> {
public IndexNode getOrThrow(String code) {
IndexNode node = findOrNull(code);
BizAssertions.assertNotNull(node, "节点不存在: {}", code);
BizAssertions.assertNotNull(node, "找不到节点: {}", code);
return node;
}
@ -81,9 +81,16 @@ public class IndexNodeDao extends ServiceImpl<IndexNodeMapper, IndexNode> {
.update();
}
public List<IndexNode> collectValidScopeTree(IndexNodeScope nodeScope) {
return scopeQuery(nodeScope) //
.eq(IndexNode::getState, IndexNodeState.VALID) //
.list();
}
public List<IndexNode> collectValidSubtree(IndexNode indexNode) {
return lambdaQuery() //
.likeRight(IndexNode::getPath, indexNode.getPath()) //
.eq(IndexNode::getState, IndexNodeState.VALID) //
.list();
}

View File

@ -0,0 +1,48 @@
package cn.axzo.nanopart.doc.file;
import static java.util.stream.Collectors.toList;
import java.util.List;
import cn.axzo.basics.common.BeanMapper;
import cn.axzo.maokai.api.vo.response.tree.Node;
import cn.axzo.maokai.api.vo.response.tree.RecursiveVisitor;
import cn.axzo.maokai.api.vo.response.tree.TreeBuilder;
import cn.axzo.maokai.api.vo.response.tree.WalkingDecision;
import cn.axzo.nanopart.doc.api.domain.IndexNodeInfo;
import cn.axzo.nanopart.doc.entity.IndexNode;
/**
* @author yanglin
*/
public class IndexNodeTreeBuilder {
/**
* @return tree roots
*/
public static List<IndexNodeInfo> buildTree(List<IndexNode> nodes, BuildIndexNodeTreeVisitor visitor) {
List<IndexNodeInfo> indexNodeInfoList = BeanMapper.copyList(nodes, IndexNodeInfo.class);
TreeBuilder.build(indexNodeInfoList).walkDown(visitor);
return indexNodeInfoList.stream() //
.filter(IndexNodeInfo::isValueRoot) //
.collect(toList());
}
public static class BuildIndexNodeTreeVisitor extends RecursiveVisitor {
@Override
public WalkingDecision visit(Node node) {
if (node.isTreeRoot())
return WalkingDecision.CONTINUE;
IndexNodeInfo child = node.<IndexNodeInfo> asValueNode().getValue();
if (node.getParent() != null && !node.getParent().isTreeRoot()) {
IndexNodeInfo parent = node.getParent().<IndexNodeInfo> asValueNode().getValue();
parent.addChild(child);
}
return WalkingDecision.CONTINUE;
}
}
}

View File

@ -77,7 +77,7 @@ public class FileDatabaseService {
}
public void active(FileDatabaseActiveRequest request) {
// TODO(yl): copy database from template
// TODO(yl): 1. copy database from template; 2. 拷贝中不能重复拷贝
}
@BizTransactional

View File

@ -6,8 +6,11 @@ import java.util.List;
import org.springframework.web.bind.annotation.RestController;
import cn.axzo.basics.common.BeanMapper;
import cn.axzo.maokai.api.vo.response.tree.Node;
import cn.axzo.maokai.api.vo.response.tree.WalkingDecision;
import cn.axzo.nanopart.doc.api.domain.IndexNodeInfo;
import cn.axzo.nanopart.doc.api.domain.IndexNodeScope;
import cn.axzo.nanopart.doc.api.enums.IndexNodeType;
import cn.axzo.nanopart.doc.api.filetemplate.FileTemplateApi;
import cn.axzo.nanopart.doc.api.filetemplate.request.FileTemplateCreateDirRequest;
import cn.axzo.nanopart.doc.api.filetemplate.request.FileTemplateCreateFileRequest;
@ -22,6 +25,8 @@ import cn.axzo.nanopart.doc.api.index.request.MoveNodeRequest;
import cn.axzo.nanopart.doc.api.index.request.RenameNodeRequest;
import cn.axzo.nanopart.doc.entity.FileTemplate;
import cn.axzo.nanopart.doc.entity.IndexNode;
import cn.axzo.nanopart.doc.file.IndexNodeTreeBuilder;
import cn.axzo.nanopart.doc.file.IndexNodeTreeBuilder.BuildIndexNodeTreeVisitor;
import cn.axzo.nanopart.doc.file.index.IndexManager;
import cn.axzo.nanopart.doc.file.index.IndexQueryService;
import cn.axzo.nanopart.doc.file.index.domain.IndexNodes;
@ -90,16 +95,44 @@ public class FileTemplateApiController implements FileTemplateApi {
@Override
public CommonResponse<List<IndexNodeInfo>> getTree() {
List<IndexNode> children = indexQueryService.getTree(IndexNodeScope.FILE_TEMPLATE_SCOPE);
return CommonResponse.success(IndexNodes.wrap(children).toIndexNodeInfos());
List<IndexNode> subtreeNodes = indexQueryService.getTree(IndexNodeScope.FILE_TEMPLATE_SCOPE);
FileTemplates fileTemplates = buildFileTemplates(subtreeNodes);
return CommonResponse.success(IndexNodeTreeBuilder.buildTree(subtreeNodes, new BuildIndexNodeTreeVisitor() {
@Override
public WalkingDecision visit(Node node) {
if (node.isTreeRoot())
return WalkingDecision.CONTINUE;
IndexNodeInfo child = node.<IndexNodeInfo> asValueNode().getValue();
maybePopulateFileTemplateInfo(fileTemplates, child);
return super.visit(node);
}
}));
}
@Override
public CommonResponse<Page<IndexNodeInfo>> search(IndexNodeSearchRequest request) {
log.info("search request:{}", request);
Page<IndexNode> page = indexQueryService.search(IndexNodeScope.FILE_TEMPLATE_SCOPE, request);
return CommonResponse.success(Page.toPage(page.getPageNum(), page.getPageSize(), page.getTotalElements(),
IndexNodes.wrap(page.getList()).toIndexNodeInfos()));
Page<IndexNodeInfo> infoPage = Page.toPage(page.getPageNum(), page.getPageSize(), page.getTotalElements(),
BeanMapper.copyList(page.getList(), IndexNodeInfo.class));
FileTemplates fileTemplates = buildFileTemplates(page.getList());
for (IndexNodeInfo info : infoPage.getList())
maybePopulateFileTemplateInfo(fileTemplates, info);
return CommonResponse.success(infoPage);
}
private FileTemplates buildFileTemplates(List<IndexNode> list) {
List<FileTemplate> fileTemplates = fileTemplateManager.getByCodes(
IndexNodes.wrap(list).collectCodes(IndexNodeType.FILE));
return FileTemplates.wrap(fileTemplates);
}
private void maybePopulateFileTemplateInfo(FileTemplates fileTemplates, IndexNodeInfo info) {
FileTemplate fileTemplate = fileTemplates.findOrNull(info.getCode());
if (fileTemplate == null)
return;
info.getOrCreateFileTemplateNodeInfo().setState(fileTemplate.getState());
info.getOrCreateFileTemplateNodeInfo().setFee(fileTemplate.getFee());
}
@Override

View File

@ -20,6 +20,8 @@ import cn.axzo.nanopart.doc.file.index.domain.IndexNodes;
import cn.axzo.nanopart.doc.utils.BizTransactional;
import lombok.RequiredArgsConstructor;
import java.util.List;
/**
* @author yanglin
*/
@ -63,6 +65,10 @@ public class FileTemplateManager {
return fileTemplateDao.findOrNull(code);
}
public List<FileTemplate> getByCodes(List<String> codes) {
return fileTemplateDao.getByCodes(codes);
}
public void updateFileInfo(FileTemplateUpdateFileInfoRequest request) {
FileTemplate fileTemplate = fileTemplateDao.getOrThrow(request.getCode());
fileTemplateDao.lambdaUpdate() //

View File

@ -0,0 +1,28 @@
package cn.axzo.nanopart.doc.file.filetemplate;
import java.util.List;
import cn.axzo.nanopart.doc.entity.FileTemplate;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
/**
* @author yanglin
*/
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class FileTemplates {
private final List<FileTemplate> fileTemplates;
public static FileTemplates wrap(List<FileTemplate> fileTemplates) {
return new FileTemplates(fileTemplates);
}
public FileTemplate findOrNull(String code) {
return fileTemplates.stream() //
.filter(fileTemplate -> fileTemplate.getCode().equals(code)) //
.findFirst() //
.orElse(null);
}
}

View File

@ -135,10 +135,24 @@ public class IndexManager {
public IndexNode copy(String srcCode, String destParentCode) {
IndexNode srcNode = getOrThrow(srcCode);
BizAssertions.assertTrue(indexNodeDao.validSubtreeFileCount(srcNode) < docProps.getIndexNodeMaxCopyFileSize(),
IndexNode destNode = getOrThrow(destParentCode);
checkCopyFileSize(srcNode);
List<IndexNode> subtreeNodes = indexNodeDao.collectValidSubtree(srcNode);
Ref<IndexNode> copyRoot = Ref.create();
TreeBuilder.build(subtreeNodes).walkDown(new RecursiveVisitor() {
@Override
public WalkingDecision visit(Node node) {
if (node.isTreeRoot())
return WalkingDecision.CONTINUE;
return null;
}
});
return copyRoot.get();
}
private void checkCopyFileSize(IndexNode srcNode) {
BizAssertions.assertTrue(indexNodeDao.validSubtreeFileCount(srcNode) <= docProps.getIndexNodeMaxCopyFileSize(),
"拷贝文件数超过限制: {}", docProps.getIndexNodeMaxCopyFileSize());
// TODO(yl): 文件夹不能拷贝到文件下面
return null;
}
public IndexNode move(String srcCode, String destParentCode) {
@ -149,7 +163,7 @@ public class IndexManager {
public WalkingDecision visit(Node node) {
if (node.isTreeRoot())
return WalkingDecision.CONTINUE;
IndexNode value = node.<IndexNode> asValueNode().getValue();
IndexNode indexNode = node.<IndexNode> asValueNode().getValue();
return WalkingDecision.CONTINUE;
}
});

View File

@ -1,7 +1,6 @@
package cn.axzo.nanopart.doc.file.index;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -9,7 +8,10 @@ import java.util.List;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import cn.axzo.nanopart.doc.api.domain.IndexNodeScope;
import cn.axzo.nanopart.doc.api.enums.IndexNodeState;
import cn.axzo.nanopart.doc.api.enums.IndexNodeType;
import cn.axzo.nanopart.doc.api.index.request.IndexNodeSearchRequest;
import cn.axzo.nanopart.doc.dao.IndexNodeDao;
@ -27,12 +29,16 @@ public class IndexQueryService {
private final IndexNodeDao indexNodeDao;
public List<IndexNode> getTree(IndexNodeScope nodeScope) {
return new ArrayList<>();
return indexNodeDao.collectValidScopeTree(nodeScope);
}
public Page<IndexNode> search(IndexNodeScope nodeScope, IndexNodeSearchRequest search) {
//todo valid state
return null;
IPage<IndexNode> page = indexNodeDao.scopeQuery(nodeScope) //
.eq(IndexNode::getState, IndexNodeState.VALID) //
.like(IndexNode::getName, search.getName()) //
.in(CollectionUtils.isNotEmpty(search.getNodeTypes()), IndexNode::getNodeType, search.getNodeTypes()) //
.page(search.toPage());
return Page.toPage(page.getPages(), page.getSize(), page.getTotal(), page.getRecords());
}
public List<IndexNode> getNameLike(IndexNodeScope nodeScope, String name, IndexNodeType... nodeTypes) {

View File

@ -5,7 +5,9 @@ import java.util.List;
import org.springframework.web.bind.annotation.RestController;
import cn.axzo.basics.common.BeanMapper;
import cn.axzo.nanopart.doc.api.domain.IndexNodeInfo;
import cn.axzo.nanopart.doc.api.domain.IndexNodeScope;
import cn.axzo.nanopart.doc.api.index.request.CopyNodeRequest;
import cn.axzo.nanopart.doc.api.index.request.DeleteNodeRequest;
import cn.axzo.nanopart.doc.api.index.request.IndexNodeSearchRequest;
@ -20,7 +22,10 @@ import cn.axzo.nanopart.doc.api.templatedb.reqeust.TemplateDatabaseUpdateDatabas
import cn.axzo.nanopart.doc.api.templatedb.reqeust.TemplateDatabaseUploadFileRequest;
import cn.axzo.nanopart.doc.api.templatedb.response.TemplateDatabaseGetDatabaseOrDirInfoResponse;
import cn.axzo.nanopart.doc.entity.IndexNode;
import cn.axzo.nanopart.doc.file.IndexNodeTreeBuilder;
import cn.axzo.nanopart.doc.file.IndexNodeTreeBuilder.BuildIndexNodeTreeVisitor;
import cn.axzo.nanopart.doc.file.index.IndexManager;
import cn.axzo.nanopart.doc.file.index.IndexQueryService;
import cn.azxo.framework.common.model.CommonResponse;
import cn.azxo.framework.common.model.Page;
import lombok.RequiredArgsConstructor;
@ -37,6 +42,7 @@ public class TemplateDatabaseApiController implements TemplateDatabaseApi {
private final TemplateDatabaseManager templateDatabaseManager;
private final IndexManager indexManager;
private final TemplateDatabaseQueryService templateDatabaseQueryService;
private final IndexQueryService indexQueryService;
@Override
public CommonResponse<String> createDatabase(TemplateDatabaseCreateDatabaseRequest request) {
@ -88,12 +94,16 @@ public class TemplateDatabaseApiController implements TemplateDatabaseApi {
@Override
public CommonResponse<List<IndexNodeInfo>> getTree() {
return null;
List<IndexNode> subtreeNodes = indexQueryService.getTree(IndexNodeScope.TEMPLATE_DATABASE_SCOPE);
return CommonResponse.success(IndexNodeTreeBuilder.buildTree(subtreeNodes, new BuildIndexNodeTreeVisitor()));
}
@Override
public CommonResponse<Page<IndexNodeInfo>> search(IndexNodeSearchRequest request) {
return null;
Page<IndexNode> page = indexQueryService.search(IndexNodeScope.TEMPLATE_DATABASE_SCOPE, request);
Page<IndexNodeInfo> infoPage = Page.toPage(page.getPageNum(), page.getPageSize(), page.getTotalElements(),
BeanMapper.copyList(page.getList(), IndexNodeInfo.class));
return CommonResponse.success(infoPage);
}
@Override

View File

@ -7,6 +7,9 @@ import cn.axzo.nanopart.doc.api.enums.FileFormat;
import cn.axzo.nanopart.doc.config.DocProps;
import lombok.RequiredArgsConstructor;
import java.util.Collections;
import java.util.List;
/**
* @author yanglin
*/
@ -21,6 +24,11 @@ public class OssClient {
return "";
}
public List<String> copy() {
// TODO(yl): finish this
return Collections.emptyList();
}
public void rename(String ossFileKey, String newName) {
// TODO(yl): finish this
}

View File

@ -46,7 +46,7 @@ public class WpsBaseManager {
* @param docCode 文件编码
*/
public WpsFetchFileResponse fetchFileBase(String docCode) {
IndexNode node = indexNodeDao.getNodeOrThrow(docCode);
IndexNode node = indexNodeDao.getOrThrow(docCode);
return WpsFetchFileResponse.builder()
.docCode(docCode)
@ -65,7 +65,7 @@ public class WpsBaseManager {
* @param docCode 文件编码
*/
public WpsFetchDownloadResponse fetchDownload(String docCode) {
IndexNode node = indexNodeDao.getNodeOrThrow(docCode);
IndexNode node = indexNodeDao.getOrThrow(docCode);
return WpsFetchDownloadResponse.builder()
.url(this.downloadUrl(node.getAttributes().getFileAttributes().getOssFileKey()))
.digest("")
@ -133,7 +133,7 @@ public class WpsBaseManager {
*/
public WpsRenameResponse rename(WpsRenameRequest request) {
AssertUtil.isFalse(Objects.isNull(request) || StringUtils.isEmpty(request.getDocCode()) || StringUtils.isEmpty(request.getName()), "参数错误");
IndexNode node = indexNodeDao.getNodeOrThrow(request.getDocCode());
IndexNode node = indexNodeDao.getOrThrow(request.getDocCode());
if (Objects.isNull(node)
|| Objects.isNull(node.getAttributes())
|| Objects.isNull(node.getAttributes().getFileAttributes())