mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-08 16:57:09 +08:00
feat(extension/crud): 支持树结构全局配置
This commit is contained in:
@@ -119,6 +119,11 @@ public class PropertiesConstants {
|
||||
*/
|
||||
public static final String MESSAGING_WEBSOCKET = MESSAGING + StringConstants.DOT + "websocket";
|
||||
|
||||
/**
|
||||
* CRUD 配置
|
||||
*/
|
||||
public static final String CRUD = CONTINEW_STARTER + StringConstants.DOT + "crud";
|
||||
|
||||
/**
|
||||
* 数据权限配置
|
||||
*/
|
||||
|
@@ -71,4 +71,11 @@ public @interface TreeField {
|
||||
* @return 递归深度
|
||||
*/
|
||||
int deep() default -1;
|
||||
|
||||
/**
|
||||
* 根节点 ID
|
||||
*
|
||||
* @return 根节点 ID
|
||||
*/
|
||||
long rootId() default 0L;
|
||||
}
|
||||
|
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.extension.crud.autoconfigure;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import top.continew.starter.core.constant.PropertiesConstants;
|
||||
|
||||
/**
|
||||
* CRUD 配置属性
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2.7.2
|
||||
*/
|
||||
@ConfigurationProperties(PropertiesConstants.CRUD)
|
||||
public class CrudProperties {
|
||||
|
||||
/**
|
||||
* 树配置
|
||||
*/
|
||||
@NestedConfigurationProperty
|
||||
private CrudTreeProperties tree;
|
||||
|
||||
public CrudTreeProperties getTree() {
|
||||
return tree;
|
||||
}
|
||||
|
||||
public void setTree(CrudTreeProperties tree) {
|
||||
this.tree = tree;
|
||||
}
|
||||
}
|
@@ -20,6 +20,7 @@ import jakarta.annotation.PostConstruct;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
@@ -36,6 +37,7 @@ import org.springframework.web.servlet.resource.ResourceUrlProvider;
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(CrudProperties.class)
|
||||
public class CrudRestControllerAutoConfiguration extends DelegatingWebMvcConfiguration {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CrudRestControllerAutoConfiguration.class);
|
||||
|
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.extension.crud.autoconfigure;
|
||||
|
||||
import cn.hutool.core.lang.tree.TreeNodeConfig;
|
||||
import top.continew.starter.core.util.validate.CheckUtils;
|
||||
import top.continew.starter.extension.crud.annotation.TreeField;
|
||||
|
||||
/**
|
||||
* CRUD 树列表配置属性
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2.7.2
|
||||
*/
|
||||
public class CrudTreeProperties {
|
||||
|
||||
/**
|
||||
* ID 字段名
|
||||
*/
|
||||
private String idKey = "id";
|
||||
|
||||
/**
|
||||
* 父 ID 字段名
|
||||
*
|
||||
*/
|
||||
private String parentIdKey = "parentId";
|
||||
|
||||
/**
|
||||
* 名称字段名
|
||||
*
|
||||
*/
|
||||
private String nameKey = "name";
|
||||
|
||||
/**
|
||||
* 排序字段名
|
||||
*
|
||||
*/
|
||||
private String weightKey = "weight";
|
||||
|
||||
/**
|
||||
* 子列表字段名
|
||||
*
|
||||
*/
|
||||
private String childrenKey = "children";
|
||||
|
||||
/**
|
||||
* 递归深度(< 0 不限制)
|
||||
*/
|
||||
private Integer deep = -1;
|
||||
|
||||
/**
|
||||
* 根节点 ID
|
||||
*/
|
||||
private Long rootId = 0L;
|
||||
|
||||
public String getIdKey() {
|
||||
return idKey;
|
||||
}
|
||||
|
||||
public void setIdKey(String idKey) {
|
||||
this.idKey = idKey;
|
||||
}
|
||||
|
||||
public String getParentIdKey() {
|
||||
return parentIdKey;
|
||||
}
|
||||
|
||||
public void setParentIdKey(String parentIdKey) {
|
||||
this.parentIdKey = parentIdKey;
|
||||
}
|
||||
|
||||
public String getNameKey() {
|
||||
return nameKey;
|
||||
}
|
||||
|
||||
public void setNameKey(String nameKey) {
|
||||
this.nameKey = nameKey;
|
||||
}
|
||||
|
||||
public String getWeightKey() {
|
||||
return weightKey;
|
||||
}
|
||||
|
||||
public void setWeightKey(String weightKey) {
|
||||
this.weightKey = weightKey;
|
||||
}
|
||||
|
||||
public String getChildrenKey() {
|
||||
return childrenKey;
|
||||
}
|
||||
|
||||
public void setChildrenKey(String childrenKey) {
|
||||
this.childrenKey = childrenKey;
|
||||
}
|
||||
|
||||
public Integer getDeep() {
|
||||
return deep;
|
||||
}
|
||||
|
||||
public void setDeep(Integer deep) {
|
||||
this.deep = deep;
|
||||
}
|
||||
|
||||
public Long getRootId() {
|
||||
return rootId;
|
||||
}
|
||||
|
||||
public void setRootId(Long rootId) {
|
||||
this.rootId = rootId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 {@link TreeNodeConfig} 对象
|
||||
*
|
||||
* @return {@link TreeNodeConfig} 对象
|
||||
*/
|
||||
public TreeNodeConfig genTreeNodeConfig() {
|
||||
return TreeNodeConfig.DEFAULT_CONFIG.setIdKey(idKey)
|
||||
.setParentIdKey(parentIdKey)
|
||||
.setNameKey(nameKey)
|
||||
.setWeightKey(weightKey)
|
||||
.setChildrenKey(childrenKey)
|
||||
.setDeep(deep < 0 ? null : deep);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 @TreeField 配置生成树结构配置
|
||||
*
|
||||
* @param treeField 树结构字段注解
|
||||
* @return 树结构配置
|
||||
*/
|
||||
public TreeNodeConfig genTreeNodeConfig(TreeField treeField) {
|
||||
CheckUtils.throwIfNull(treeField, "请添加并配置 @TreeField 树结构信息");
|
||||
return new TreeNodeConfig().setIdKey(treeField.value())
|
||||
.setParentIdKey(treeField.parentIdKey())
|
||||
.setNameKey(treeField.nameKey())
|
||||
.setWeightKey(treeField.weightKey())
|
||||
.setChildrenKey(treeField.childrenKey())
|
||||
.setDeep(treeField.deep() < 0 ? null : treeField.deep());
|
||||
}
|
||||
}
|
@@ -28,34 +28,42 @@ public enum Api {
|
||||
* 所有 API
|
||||
*/
|
||||
ALL,
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
PAGE,
|
||||
/**
|
||||
* 树列表
|
||||
*/
|
||||
TREE,
|
||||
|
||||
/**
|
||||
* 列表
|
||||
*/
|
||||
LIST,
|
||||
|
||||
/**
|
||||
* 树列表
|
||||
*/
|
||||
TREE,
|
||||
|
||||
/**
|
||||
* 详情
|
||||
*/
|
||||
GET,
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
ADD,
|
||||
|
||||
/**
|
||||
* 修改
|
||||
*/
|
||||
UPDATE,
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
DELETE,
|
||||
|
||||
/**
|
||||
* 导出
|
||||
*/
|
||||
|
@@ -16,18 +16,10 @@
|
||||
|
||||
package top.continew.starter.extension.crud.util;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.lang.tree.TreeNodeConfig;
|
||||
import cn.hutool.core.lang.tree.TreeUtil;
|
||||
import cn.hutool.core.lang.tree.parser.NodeParser;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import top.continew.starter.core.util.validate.CheckUtils;
|
||||
import top.continew.starter.extension.crud.annotation.TreeField;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 树工具类
|
||||
*
|
||||
@@ -37,7 +29,7 @@ import java.util.List;
|
||||
public class TreeUtils {
|
||||
|
||||
/**
|
||||
* 默认字段配置对象(根据前端树结构灵活调整名称)
|
||||
* 默认字段配置对象
|
||||
*/
|
||||
public static final TreeNodeConfig DEFAULT_CONFIG = TreeNodeConfig.DEFAULT_CONFIG.setNameKey("title")
|
||||
.setIdKey("key")
|
||||
@@ -46,37 +38,6 @@ public class TreeUtils {
|
||||
private TreeUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 树构建
|
||||
*
|
||||
* @param <T> 转换的实体 为数据源里的对象类型
|
||||
* @param <E> ID类型
|
||||
* @param list 源数据集合
|
||||
* @param nodeParser 转换器
|
||||
* @return List 树列表
|
||||
*/
|
||||
public static <T, E> List<Tree<E>> build(List<T> list, NodeParser<T, E> nodeParser) {
|
||||
return build(list, DEFAULT_CONFIG, nodeParser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 树构建
|
||||
*
|
||||
* @param <T> 转换的实体 为数据源里的对象类型
|
||||
* @param <E> ID类型
|
||||
* @param list 源数据集合
|
||||
* @param treeNodeConfig 配置
|
||||
* @param nodeParser 转换器
|
||||
* @return List 树列表
|
||||
*/
|
||||
public static <T, E> List<Tree<E>> build(List<T> list, TreeNodeConfig treeNodeConfig, NodeParser<T, E> nodeParser) {
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
E parentId = (E)ReflectUtil.getFieldValue(list.get(0), treeNodeConfig.getParentIdKey());
|
||||
return TreeUtil.build(list, parentId, treeNodeConfig, nodeParser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 @TreeField 配置生成树结构配置
|
||||
*
|
||||
|
@@ -71,21 +71,6 @@ public abstract class BaseController<S extends BaseService<L, D, Q, C>, L, D, Q,
|
||||
return baseService.page(query, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询树列表
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param sortQuery 排序查询条件
|
||||
* @return 树列表信息
|
||||
*/
|
||||
@Operation(summary = "查询树列表", description = "查询树列表")
|
||||
@ResponseBody
|
||||
@GetMapping("/tree")
|
||||
public List<Tree<Long>> tree(Q query, SortQuery sortQuery) {
|
||||
this.checkPermission(Api.LIST);
|
||||
return baseService.tree(query, sortQuery, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*
|
||||
@@ -101,6 +86,21 @@ public abstract class BaseController<S extends BaseService<L, D, Q, C>, L, D, Q,
|
||||
return baseService.list(query, sortQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询树列表
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param sortQuery 排序查询条件
|
||||
* @return 树列表信息
|
||||
*/
|
||||
@Operation(summary = "查询树列表", description = "查询树列表")
|
||||
@ResponseBody
|
||||
@GetMapping("/tree")
|
||||
public List<Tree<Long>> tree(Q query, SortQuery sortQuery) {
|
||||
this.checkPermission(Api.LIST);
|
||||
return baseService.tree(query, sortQuery, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询详情
|
||||
*
|
||||
|
@@ -46,16 +46,6 @@ public interface BaseService<L, D, Q, C> {
|
||||
*/
|
||||
PageResp<L> page(Q query, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询树列表
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param sortQuery 排序查询条件
|
||||
* @param isSimple 是否为简单树结构(不包含基本树结构之外的扩展字段)
|
||||
* @return 树列表信息
|
||||
*/
|
||||
List<Tree<Long>> tree(Q query, SortQuery sortQuery, boolean isSimple);
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*
|
||||
@@ -65,6 +55,20 @@ public interface BaseService<L, D, Q, C> {
|
||||
*/
|
||||
List<L> list(Q query, SortQuery sortQuery);
|
||||
|
||||
/**
|
||||
* 查询树列表
|
||||
* <p>
|
||||
* 虽然提供了查询条件,但不建议使用,容易因缺失根节点导致树节点丢失。
|
||||
* 建议在前端进行查询过滤,如需使用建议重写方法。
|
||||
* </p>
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param sortQuery 排序查询条件
|
||||
* @param isSimple 是否为简单树结构(不包含基本树结构之外的扩展字段)
|
||||
* @return 树列表信息
|
||||
*/
|
||||
List<Tree<Long>> tree(Q query, SortQuery sortQuery, boolean isSimple);
|
||||
|
||||
/**
|
||||
* 查看详情
|
||||
*
|
||||
|
@@ -22,12 +22,14 @@ import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.lang.tree.TreeNodeConfig;
|
||||
import cn.hutool.core.lang.tree.TreeUtil;
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.poi.ss.formula.functions.T;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import top.continew.starter.core.constant.StringConstants;
|
||||
@@ -37,12 +39,13 @@ import top.continew.starter.data.mf.base.BaseMapper;
|
||||
import top.continew.starter.data.mf.service.impl.ServiceImpl;
|
||||
import top.continew.starter.data.mf.util.QueryWrapperHelper;
|
||||
import top.continew.starter.extension.crud.annotation.TreeField;
|
||||
import top.continew.starter.extension.crud.autoconfigure.CrudProperties;
|
||||
import top.continew.starter.extension.crud.autoconfigure.CrudTreeProperties;
|
||||
import top.continew.starter.extension.crud.model.entity.BaseIdDO;
|
||||
import top.continew.starter.extension.crud.model.query.PageQuery;
|
||||
import top.continew.starter.extension.crud.model.query.SortQuery;
|
||||
import top.continew.starter.extension.crud.model.resp.PageResp;
|
||||
import top.continew.starter.extension.crud.service.BaseService;
|
||||
import top.continew.starter.extension.crud.util.TreeUtils;
|
||||
import top.continew.starter.file.excel.util.ExcelUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
@@ -79,6 +82,13 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdD
|
||||
return pageResp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<L> list(Q query, SortQuery sortQuery) {
|
||||
List<L> list = this.list(query, sortQuery, listClass);
|
||||
list.forEach(this::fill);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tree<Long>> tree(Q query, SortQuery sortQuery, boolean isSimple) {
|
||||
List<L> list = this.list(query, sortQuery);
|
||||
@@ -86,36 +96,35 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdD
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
// 如果构建简单树结构,则不包含基本树结构之外的扩展字段
|
||||
TreeNodeConfig treeNodeConfig = TreeUtils.DEFAULT_CONFIG;
|
||||
TreeField treeField = listClass.getDeclaredAnnotation(TreeField.class);
|
||||
if (!isSimple) {
|
||||
// 根据 @TreeField 配置生成树结构配置
|
||||
treeNodeConfig = TreeUtils.genTreeNodeConfig(treeField);
|
||||
CrudProperties crudProperties = SpringUtil.getBean(CrudProperties.class);
|
||||
CrudTreeProperties treeProperties = crudProperties.getTree();
|
||||
TreeNodeConfig treeNodeConfig;
|
||||
Long rootId;
|
||||
if (isSimple) {
|
||||
treeNodeConfig = treeProperties.genTreeNodeConfig();
|
||||
rootId = treeProperties.getRootId();
|
||||
} else {
|
||||
TreeField treeField = listClass.getDeclaredAnnotation(TreeField.class);
|
||||
treeNodeConfig = treeProperties.genTreeNodeConfig(treeField);
|
||||
rootId = treeField.rootId();
|
||||
}
|
||||
// 构建树
|
||||
return TreeUtils.build(list, treeNodeConfig, (node, tree) -> {
|
||||
// 转换器
|
||||
tree.setId(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.value())));
|
||||
tree.setParentId(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.parentIdKey())));
|
||||
tree.setName(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.nameKey())));
|
||||
tree.setWeight(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.weightKey())));
|
||||
return TreeUtil.build(list, rootId, treeNodeConfig, (node, tree) -> {
|
||||
tree.setId(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeNodeConfig.getIdKey())));
|
||||
tree.setParentId(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeNodeConfig.getParentIdKey())));
|
||||
tree.setName(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeNodeConfig.getNameKey())));
|
||||
tree.setWeight(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeNodeConfig.getWeightKey())));
|
||||
if (!isSimple) {
|
||||
List<Field> fieldList = ReflectUtils.getNonStaticFields(listClass);
|
||||
fieldList.removeIf(f -> CharSequenceUtil.equalsAnyIgnoreCase(f.getName(), treeField.value(), treeField
|
||||
.parentIdKey(), treeField.nameKey(), treeField.weightKey(), treeField.childrenKey()));
|
||||
fieldList.removeIf(f -> CharSequenceUtil.equalsAnyIgnoreCase(f.getName(), treeNodeConfig
|
||||
.getIdKey(), treeNodeConfig.getParentIdKey(), treeNodeConfig.getNameKey(), treeNodeConfig
|
||||
.getWeightKey(), treeNodeConfig.getChildrenKey()));
|
||||
fieldList.forEach(f -> tree.putExtra(f.getName(), ReflectUtil.invoke(node, CharSequenceUtil.genGetter(f
|
||||
.getName()))));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<L> list(Q query, SortQuery sortQuery) {
|
||||
List<L> list = this.list(query, sortQuery, listClass);
|
||||
list.forEach(this::fill);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public D get(Long id) {
|
||||
T entity = super.getById(id);
|
||||
|
@@ -71,21 +71,6 @@ public abstract class BaseController<S extends BaseService<L, D, Q, C>, L, D, Q,
|
||||
return baseService.page(query, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询树列表
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param sortQuery 排序查询条件
|
||||
* @return 树列表信息
|
||||
*/
|
||||
@Operation(summary = "查询树列表", description = "查询树列表")
|
||||
@ResponseBody
|
||||
@GetMapping("/tree")
|
||||
public List<Tree<Long>> tree(Q query, SortQuery sortQuery) {
|
||||
this.checkPermission(Api.LIST);
|
||||
return baseService.tree(query, sortQuery, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*
|
||||
@@ -101,6 +86,21 @@ public abstract class BaseController<S extends BaseService<L, D, Q, C>, L, D, Q,
|
||||
return baseService.list(query, sortQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询树列表
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param sortQuery 排序查询条件
|
||||
* @return 树列表信息
|
||||
*/
|
||||
@Operation(summary = "查询树列表", description = "查询树列表")
|
||||
@ResponseBody
|
||||
@GetMapping("/tree")
|
||||
public List<Tree<Long>> tree(Q query, SortQuery sortQuery) {
|
||||
this.checkPermission(Api.LIST);
|
||||
return baseService.tree(query, sortQuery, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询详情
|
||||
*
|
||||
|
@@ -46,16 +46,6 @@ public interface BaseService<L, D, Q, C> {
|
||||
*/
|
||||
PageResp<L> page(Q query, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询树列表
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param sortQuery 排序查询条件
|
||||
* @param isSimple 是否为简单树结构(不包含基本树结构之外的扩展字段)
|
||||
* @return 树列表信息
|
||||
*/
|
||||
List<Tree<Long>> tree(Q query, SortQuery sortQuery, boolean isSimple);
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*
|
||||
@@ -65,6 +55,20 @@ public interface BaseService<L, D, Q, C> {
|
||||
*/
|
||||
List<L> list(Q query, SortQuery sortQuery);
|
||||
|
||||
/**
|
||||
* 查询树列表
|
||||
* <p>
|
||||
* 虽然提供了查询条件,但不建议使用,容易因缺失根节点导致树节点丢失。
|
||||
* 建议在前端进行查询过滤,如需使用建议重写方法。
|
||||
* </p>
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param sortQuery 排序查询条件
|
||||
* @param isSimple 是否为简单树结构(不包含基本树结构之外的扩展字段)
|
||||
* @return 树列表信息
|
||||
*/
|
||||
List<Tree<Long>> tree(Q query, SortQuery sortQuery, boolean isSimple);
|
||||
|
||||
/**
|
||||
* 查询详情
|
||||
*
|
||||
|
@@ -22,6 +22,7 @@ import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.lang.tree.TreeNodeConfig;
|
||||
import cn.hutool.core.lang.tree.TreeUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
@@ -42,13 +43,14 @@ import top.continew.starter.data.mp.service.impl.ServiceImpl;
|
||||
import top.continew.starter.data.mp.util.QueryWrapperHelper;
|
||||
import top.continew.starter.extension.crud.annotation.DictField;
|
||||
import top.continew.starter.extension.crud.annotation.TreeField;
|
||||
import top.continew.starter.extension.crud.autoconfigure.CrudProperties;
|
||||
import top.continew.starter.extension.crud.autoconfigure.CrudTreeProperties;
|
||||
import top.continew.starter.extension.crud.model.entity.BaseIdDO;
|
||||
import top.continew.starter.extension.crud.model.query.PageQuery;
|
||||
import top.continew.starter.extension.crud.model.query.SortQuery;
|
||||
import top.continew.starter.extension.crud.model.resp.LabelValueResp;
|
||||
import top.continew.starter.extension.crud.model.resp.PageResp;
|
||||
import top.continew.starter.extension.crud.service.BaseService;
|
||||
import top.continew.starter.extension.crud.util.TreeUtils;
|
||||
import top.continew.starter.file.excel.util.ExcelUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
@@ -86,6 +88,13 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdD
|
||||
return pageResp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<L> list(Q query, SortQuery sortQuery) {
|
||||
List<L> list = this.list(query, sortQuery, this.getListClass());
|
||||
list.forEach(this::fill);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tree<Long>> tree(Q query, SortQuery sortQuery, boolean isSimple) {
|
||||
List<L> list = this.list(query, sortQuery);
|
||||
@@ -93,36 +102,35 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdD
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
// 如果构建简单树结构,则不包含基本树结构之外的扩展字段
|
||||
TreeNodeConfig treeNodeConfig = TreeUtils.DEFAULT_CONFIG;
|
||||
TreeField treeField = this.getListClass().getDeclaredAnnotation(TreeField.class);
|
||||
if (!isSimple) {
|
||||
// 根据 @TreeField 配置生成树结构配置
|
||||
treeNodeConfig = TreeUtils.genTreeNodeConfig(treeField);
|
||||
CrudProperties crudProperties = SpringUtil.getBean(CrudProperties.class);
|
||||
CrudTreeProperties treeProperties = crudProperties.getTree();
|
||||
TreeNodeConfig treeNodeConfig;
|
||||
Long rootId;
|
||||
if (isSimple) {
|
||||
treeNodeConfig = treeProperties.genTreeNodeConfig();
|
||||
rootId = treeProperties.getRootId();
|
||||
} else {
|
||||
TreeField treeField = listClass.getDeclaredAnnotation(TreeField.class);
|
||||
treeNodeConfig = treeProperties.genTreeNodeConfig(treeField);
|
||||
rootId = treeField.rootId();
|
||||
}
|
||||
// 构建树
|
||||
return TreeUtils.build(list, treeNodeConfig, (node, tree) -> {
|
||||
// 转换器
|
||||
tree.setId(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.value())));
|
||||
tree.setParentId(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.parentIdKey())));
|
||||
tree.setName(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.nameKey())));
|
||||
tree.setWeight(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.weightKey())));
|
||||
return TreeUtil.build(list, rootId, treeNodeConfig, (node, tree) -> {
|
||||
tree.setId(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeNodeConfig.getIdKey())));
|
||||
tree.setParentId(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeNodeConfig.getParentIdKey())));
|
||||
tree.setName(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeNodeConfig.getNameKey())));
|
||||
tree.setWeight(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeNodeConfig.getWeightKey())));
|
||||
if (!isSimple) {
|
||||
List<Field> fieldList = ReflectUtils.getNonStaticFields(this.getListClass());
|
||||
fieldList.removeIf(f -> CharSequenceUtil.equalsAnyIgnoreCase(f.getName(), treeField.value(), treeField
|
||||
.parentIdKey(), treeField.nameKey(), treeField.weightKey(), treeField.childrenKey()));
|
||||
List<Field> fieldList = ReflectUtils.getNonStaticFields(listClass);
|
||||
fieldList.removeIf(f -> CharSequenceUtil.equalsAnyIgnoreCase(f.getName(), treeNodeConfig
|
||||
.getIdKey(), treeNodeConfig.getParentIdKey(), treeNodeConfig.getNameKey(), treeNodeConfig
|
||||
.getWeightKey(), treeNodeConfig.getChildrenKey()));
|
||||
fieldList.forEach(f -> tree.putExtra(f.getName(), ReflectUtil.invoke(node, CharSequenceUtil.genGetter(f
|
||||
.getName()))));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<L> list(Q query, SortQuery sortQuery) {
|
||||
List<L> list = this.list(query, sortQuery, this.getListClass());
|
||||
list.forEach(this::fill);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public D get(Long id) {
|
||||
T entity = super.getById(id, false);
|
||||
|
Reference in New Issue
Block a user