Как заполнить измененные данные обхода дерева предзаказа в объекте дерева Java?
У меня есть следующая таблица со структурой 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
(
)
)
)
)
)
Проблема в том, как я могу заполнить структуру данных MPTT в Java, используя класс дерева Java. Да, я знаю, что в Java не может быть динамического массива, как в PHP, в Java вы должны использовать класс Model.
Мой класс 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. Я не знаю, что делать, я не знаю, как заполнить это полностью. Я использую Java-класс Vivin GenericTree
Я думаю, что мне нужна стратегия запроса данных, нужна ли рекурсивная функция для извлечения всех данных из базы данных? Я думаю, что это занимает два шага: 1. Запрос данных, 2. Заполните все данные в объект дерева.
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;
}
(геттеры / сеттеры опущены для краткости)
parent
Поле помогает вам установить родительское меню и может быть нулевым для корневого меню.
Добавьте детское меню в 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
: Эта реализация не будет работать, если существует более одного корневого меню.
Вы, вероятно, хотите добавить private Menu menu;
переменная экземпляра, так что вы можете моделировать древовидную структуру
Возможно, вам будет полезно проверить эту реализацию MPTT в Java JPA. Демонстрация в исходном коде может дать идеи, как смоделировать вашу сущность, а также как заполнить дерево.