我的下表中包含 MPTT 结构:
CREATE TABLE IF NOT EXISTS menus (
id int(10) unsigned NOT NULL AUTO_INCREMENT,
parent_id int(10) DEFAULT NULL,
lft int(10) DEFAULT NULL,
rght int(10) DEFAULT NULL,
module_name varchar(255) DEFAULT NULL,
module_controller_name varchar(128) DEFAULT NULL,
module_action_name varchar(128) DEFAULT NULL,
alias varchar(128) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB;
INSERT INTO menus (`id`, `parent_id`, `lft`, `rght`, `module_name`,
`module_controller_name`, `module_action_name`, `alias`) VALUES (1, NULL, 1, 14,
'Root', '', '', 'Root'),
(2, 1, 2, 7, 'Toolbox', '', '', 'Toolbox'),
(3, 2, 5, 6, 'Menu Manajemen', 'menus', 'index', 'MenuManajemenz'),
(4, 2, 3, 4, 'Hak Akses Manajemen', 'access_rights', 'index', 'HakAksesManajemen'),
(5, 1, 8, 13, 'Accounts', '', '', 'Accounts'),
(6, 5, 9, 10, 'Users', 'users', 'index', 'Users'),
(7, 5, 11, 12, 'Groups', 'groups', 'index', 'Groups');
在 CakePHP 中,我可以制作以下数据结构:
Array
(
[0] => Array
(
[Menu] => Array
(
[id] => 2
[parent_id] => 1
[lft] => 2
[rght] => 7
[module_name] => Toolbox
[module_controller_name] =>
[module_action_name] =>
[alias] => Toolbox
)
[children] => Array
(
[0] => Array
(
[Menu] => Array
(
[id] => 4
[parent_id] => 2
[lft] => 3
[rght] => 4
[module_name] => Hak Akses Manajemen
[module_controller_name] => access_rights
[module_action_name] => index
[alias] => HakAksesManajemen
)
[children] => Array
(
)
)
[1] => Array
(
[Menu] => Array
(
[id] => 3
[parent_id] => 2
[lft] => 5
[rght] => 6
[module_name] => Menu Manajemen
[module_controller_name] => menus
[module_action_name] => index
[alias] => MenuManajemenz
)
[children] => Array
(
)
)
)
)
)
问题是如何使用 Java 树类在 Java 中填充 MPTT 数据结构。是的,我知道 Java 不能像 PHP 那样拥有动态数组,在 Java 中你必须使用类模型 。
我的Model类看起来像这样:
public class Menu {
private String moduleName;
private String moduleControllerName;
private String moduleActionName;
private String alias;
public String getModuleName() {
return moduleName;
}
public void setModuleName(String moduleName) {
this.moduleName = moduleName;
}
public String getModuleControllerName() {
return moduleControllerName;
}
public void setModuleControllerName(String moduleControllerName) {
this.moduleControllerName = moduleControllerName;
}
public String getModuleActionName() {
return moduleActionName;
}
public void setModuleActionName(String moduleActionName) {
this.moduleActionName = moduleActionName;
}
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
}
我发现它很混乱,我不知道如何做到这一点。来自数据库的数据将填充到 Java 树对象。我不知道该怎么做,我不知道如何完全填充它。我正在使用Vivin's GenericTree Java class
我认为我需要数据查询策略,是否需要一个递归函数来从数据库中检索所有数据?我认为它需要两个步骤:1。查询数据,2。将所有数据填充到树对象。
答案 0 :(得分:2)
您实际上并不需要通用的树数据结构。请考虑以下示例:
private static final class Menu {
private Menu parent;
private List<Menu> children;
private String moduleName;
private String moduleControllerName;
private String moduleActionName;
private String alias;
}
(getters / setters因为简洁而无视)
parent
字段可帮助您设置父菜单,对于根菜单可以为null。
将“儿童”菜单添加到children
字段。
通过这种方式,您将能够捕捉到我希望的分级菜单的需求。
现在构建查询,假设您有一个结果集rs
:
Menu menu;
while (rs.hasNext()) {
if (rs.get("parent_id") == null) {
// it s the root
menu = new Menu(rs.get("id"), /* etc... */);
} else {
menu = findMenuById(menu, rs.get("parent_id"));
menu.addChild(new Menu(rs.get("id"), /* etc... */));
}
对于查找findMenuById
,它可能类似于:
private Menu findMenuById(Menu menu, Long id) {
if (menu.getId() == id) return menu;
for (Menu childMenu : menu.getChildren()) {
Menu found = findMenuById(childMenu, id);
if (found != null) return found;
}
return null;
}
这是我制作的自定义工作实现。我在数据库中插入了菜单并使用结果集。对于你的自定义抽象,我应该差不多了。
Menu root = null;
Map<Integer, Menu> menus = new HashMap<Integer, Menu>();
final Database databaseConnection = Database.createConnection("test", "root", "");
final ResultSet rs = databaseConnection.executeQuery("SELECT * FROM test.menus;");
while ( rs.next() ) {
final Menu menu = new Menu(rs.getInt("id"))
.setAlias(rs.getString("alias"))
.setModuleName(rs.getString("module_name"));
final Integer parentId = rs.getInt("parent_id");
if (root == null && parentId == 0) {
root = menu;
} else {
menus.get(parentId).addSubMenu(menu);
}
menus.put(menu.getId(), menu);
}
rootMenu = root;
databaseConnection.closeConnection();
Note 1
:我使用HashMap
来存储尚未附加到根目录的菜单。
Note 2
:如果有多个根菜单,则此实现不起作用。
答案 1 :(得分:1)
您可能希望添加private Menu menu;
实例变量,以便可以为树结构建模
答案 2 :(得分:0)
检查MPTT的Java JPA实现可能对您来说很有价值。 源代码中的演示可以提供有关如何对实体建模以及如何填充树的想法。