Reputation: 101
I have the following table with a MPTT structure :
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');
In CakePHP I can make the following data structure :
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
(
)
)
)
)
)
The problem is how can I populate MPTT data structure in Java, using a Java tree class. Yes, I know Java can not have dynamic array like in PHP, in Java you have to use class Model.
My Model class looks like this:
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;
}
}
I find it very confusing and I don't know any way on how to do it. Data that comes from database is populated to a Java tree object. I don't know what to do, I don't know how to populate it completely. I am using Vivin's GenericTree Java class
I think i need data querying strategy, is it need a recursive function to retrieve all data from database? I think it takes two steps : 1. Querying the data, 2. Populate all data to tree object.
Upvotes: 4
Views: 1358
Reputation: 3013
It might be valuable for you to check this Java JPA implementation of MPTT. The demo in the source code could give ideas how to model your entity, as well as populating the tree.
https://github.com/hacker-works/mptt-jpa
Upvotes: 0
Reputation: 2203
You do not really need a generic tree data structure for this. Consider the following example:
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 ommited for conciseness)
The parent
field helps you set the parent menu and can be null for the root menu.
Add the Children menu to the children
field.
With this you will be able to capture the needs of your hierarchical menu I hope.
Now to build the query supposing you have a result set 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... */));
}
as for find findMenuById
it could be something like:
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;
}
Here is a custom working implementation I made. I inserted your menu in the database and use result set. I should be almost the same with the custom abstraction of yours.
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
: I used an HashMap
to store the menus that are not attached to the root yet.
Note 2
: This implementation wont work if there are more than one root menu.
Upvotes: 2
Reputation: 9096
You probably want to add a private Menu menu;
instance variable so that you can model a tree structure
Upvotes: 1