【业务功能篇69】Springboot 树形菜单栏功能设计

业务场景: 系统的界面,前端设计的时候,一般会给一个菜单栏,顶部横向以及左侧纵向的导航栏菜单,这里后端返回菜单栏的时候,就涉及层级父子项的问题,所以返回数据的时候,我们需要按照树化形式返回菜单栏数据,方便用户进行解析读取 

 菜单栏的数据表设计

CREATE TABLE `dwr_quality_management_menu_bar` (
  `uid` int NOT NULL AUTO_INCREMENT,
  `id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '树节点id',
  `parent_id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '父id,树化时使用',
  `resource_id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '唯一资源id',
  `name_cn` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '中文名',
  `url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '路径',
  `level` tinyint DEFAULT NULL COMMENT '菜单层级',
  `show_order` int DEFAULT NULL COMMENT '显示顺序',
  `description` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '描述',
  `is_home_page` tinyint(1) DEFAULT '2' COMMENT '首页标识:1:是,2:否',
  `update_date` datetime DEFAULT NULL COMMENT '更改时间',
  `picture_id` varchar(255) DEFAULT NULL,
  `picture_url` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`uid`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3845 DEFAULT CHARSET=utf8 COMMENT='菜单栏配置';

控制层

@RestController
@RequestMapping(value = "/management/menu", produces = {"application/json;charset=UTF-8"})
@Validated
public class ManagementMenuController {
    @Autowired(required=false) 
    private ManagementMenuDelegate delegate;  

    @RequestMapping(
    		value = "/getAllMenu", 
    		produces = { "application/json" }, 
    		method = RequestMethod.GET)
    public ResponseVo getAllMenu( @RequestParam(value = "p", required = false) String p) 
            {
    	    
		return delegate.getAllMenu(p);
    }

}

 

服务层 接口

public interface ManagementMenuDelegate {
    ResponseVo getAllMenu(String pdu) ;
    	
}

 

服务层 接口实现 

@Service
public class ManagementMenuDelegateImpl implements ManagementMenuDelegate {

    @Resource
    private MenuBarService menuBarService;

    /**
     * getAllMenu
     * 
     * @param p 
     * @return ResponseVo
     */
    @Override
    public ResponseVo getAllMenu(String p) {
        return ResponseUtils.successResponse(menuBarService.getCompleteMenu(p), "");
    }

}

 

服务层 具体接口

public interface MenuBarService {

    /**
     * 获取所有菜单
     *
     * @param p
     * @return List<ManagementMenuBarVo>
     */
    List<ManagementMenuBarVo> getCompleteMenu(String p);

}

服务层 具体接口实现

@Service
@Slf4j
public class MenuBarServiceImpl implements MenuBarService {

    @Resource
    private ManagementMenuBarMapper menuBarMapper;

    /**
     * getCompleteMenu
     * 
     * @param p
     * @return List<ManagementMenuBarVo>
     */
    @Override
    public List<ManagementMenuBarVo> getCompleteMenu(String p) {
        List<ManagementMenuBarVo> result = TreeUtils.treeing(getAllFlattingMenu());
        if (ObjectUtils.isNotEmpty(p)) {
            for (ManagementMenuBarVo barVo : result) {
                if (barVo.getNameCn().equals(p)) {
                    return barVo.getChildren();
                }
            }
            return new ArrayList<>();
        }
        return result;
    }


        /**
     * getAllFlattingMenu
     * 
     * @return List<ManagementMenuBarVo>
     */
    private List<ManagementMenuBarVo> getAllFlattingMenu() {
        QueryWrapper<ManagementMenuBar> queryWrapper = new QueryWrapper<>();
        // 排序规则与getBarRootNode()一致
        queryWrapper.lambda()
            .orderBy(true, true, ManagementMenuBar::getLevel, ManagementMenuBar::getParentId,
                ManagementMenuBar::getShowOrder);
        List<ManagementMenuBar> menuBarList = menuBarMapper.selectList(queryWrapper);

        return convertToVo(menuBarList);
    }

        /**
     * convertToVo
     * 
     * @param list list
     * @return List<ManagementMenuBarVo>
     */
    private List<ManagementMenuBarVo> convertToVo(List<ManagementMenuBar> list) {
        List<ManagementMenuBarVo> voList = new LinkedList<>();
        for (ManagementMenuBar menuBar : list) {
            ManagementMenuBarVo vo = new ManagementMenuBarVo();
            MyBeanUtils.shallowCopy(menuBar, vo);
            vo.initSuperNodeId();
            vo.initSuperParentNodeId();
            voList.add(vo);
        }
        return voList;
    }

}

dao层 mapper

@Mapper
public interface ManagementMenuBarMapper extends BaseMapper<ManagementMenuBar> {


}

实体类DO表


@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@NoArgsConstructor
@TableName("dwr_quality_management_menu_bar")
public class ManagementMenuBar implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "uid" ,type = IdType.AUTO)
    private String uid;

    /**
     * 树节点id
     */
    @TableField("id")
    private String id;

    /**
     * 父id,树化时使用
     */
    @TableField("parent_id")
    private String parentId;

    /**
     * 唯一资源id
     */
    @TableField("resource_id")
    private String resourceId;

    /**
     * 图片ID
     */
    @TableField("picture_id")
    private String pictureId;

    /**
     * 中文名
     */
    @TableField("name_cn")
    private String nameCn;

    /**
     * 路径
     */
    @TableField("url")
    private String url;

    /**
     * 图片访问路径url
     */
    @TableField("picture_url")
    private String pictureUrl;

    /**
     * 菜单层级
     */
    @TableField("level")
    private Integer level;

    /**
     * 显示顺序
     */
    @TableField("show_order")
    private Integer showOrder;

    /**
     * 描述
     */
    @TableField("description")
    private String description;

    /**
     * 首页标识:1:是,2:否
     */
    @TableField("is_home_page")
    private Integer isHomePage;



    /**
     * 更改时间
     */
    @TableField("update_date")
    private Date updateDate;


}

 

传输前端类VO

  • 作为传输转换类,其中就需要继承我们自定义的一个树化类结构 

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class ManagementMenuBarVo extends TreeNode<ManagementMenuBarVo> implements Serializable {

    private static final long serialVersionUID = 1L;

    private String uid;
    private String id;

    private String parentId;

    private String resourceId;

    private String pictureId;

    private String pictureUrl;

    private String nameCn;

    private String url;

    private Integer level;

    private String description;

    private Integer isHomePage;

    private Integer isAccessible;

    private String functionName;

    private Integer showOrder;

    /**
     *
     */

    /**
     * initSuperNodeId
     * 
     */
    @Override
    public void initSuperNodeId() {
        super.setNodeId(this.id);
    }

    /**
     * 初始化TreeNode的parentNodeId属性
     */
    @Override
    public void initSuperParentNodeId() {
        super.setParentNodeId(this.parentId);
    }

}

 

树化工具节点类


/**
 * 树化工具实体
 *
 */
@Data
public abstract class TreeNode<T> {

    // 仅用于树化,序列化时忽略
    @JsonIgnore
    private String nodeId;

    @JsonIgnore
    private String parentNodeId;

    @JsonIgnore
    private T parent;

    private List<T> children = new ArrayList<>();

    /**
     * 初始化TreeNode的NodeId属性
     */
    public abstract void initSuperNodeId();

    /**
     * 初始化TreeNode的parentNodeId属性
     */
    public abstract void initSuperParentNodeId();

}

树化操作工具类 

/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 */

package com.xxx.utils;


/**
 * 树化工具
 *
 */
public class TreeUtils {

    /**
     * 树化
     * @param treeNodes 扁平节点数据
     * @return 树化的节点列表(列表中每一节点都是一棵树)
     */
    public static <T extends TreeNode<T>> List<T> treeing(List<T> treeNodes) {
        Map<String, T> nodeMap = new HashMap<>(treeNodes.size());
        treeNodes.forEach(t -> nodeMap.put(t.getNodeId(), t));

        List<T> result = new ArrayList<>();
        for (T treeNode : treeNodes) {
            T parent = nodeMap.get(treeNode.getParentNodeId());
            if (parent != null) {
                parent.getChildren().add(treeNode);
                treeNode.setParent(parent);
                continue;
            }
            // 仅添加顶层节点
            result.add(treeNode);
        }

        return result;
    }

    /**
     * 扁平化
     * @param treeNodes 树化数据
     * @return 扁平数据
     */
    public static <T extends TreeNode<T>> List<T> flattening(List<T> treeNodes) {
        if (!CollectionUtils.isEmpty(treeNodes)) {
            return new ArrayList<>();
        }
        List<T> newList = new LinkedList<>();
        Queue<T> queue = new LinkedList<>(treeNodes);
        while (!queue.isEmpty()) {
            T pollMenuBar = queue.poll();
            List<T> children = pollMenuBar.getChildren();
            if (!CollectionUtils.isEmpty(children)) {
                queue.addAll(children);
            }
            newList.add(pollMenuBar);
        }
        return newList;
    }
}

  •  返回前端的JSON数据格式如下
  • 每个菜单栏层级就比较清晰,通过children集合嵌套当前菜单栏的子菜单栏

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值