Vaadin 8基于Enum类创建树形菜单的技术咨询
Hey there! No worries at all about being new to Vaadin—we all start somewhere. Let's break down how you can smoothly transition from your custom button-based menu to Vaadin 8.3.2's built-in Tree component, while keeping your existing user permission controls fully intact.
Vaadin 8.3+ introduced a proper Tree component that natively supports hierarchical structures, which is perfect for your menu needs. Unlike your custom button loop approach, it handles parent-child relationships out of the box and can be easily integrated with your existing permission logic.
Your existing Enum-based menu definition and permission checks can be repurposed directly for the Tree. Here's a step-by-step implementation:
Step 1: Define (or Reuse) Your Menu Enum
First, let's formalize the Enum structure you likely have (based on your code snippet):
public enum MenuItem { DASHBOARD("Dashboard", "/dashboard", Permission.VIEW_DASHBOARD), ORDERS("Orders", "/orders", Permission.VIEW_ORDERS), CUSTOMERS("Customers", "/customers", Permission.VIEW_CUSTOMERS, MenuItem.CUSTOMER_DETAILS, MenuItem.CUSTOMER_REPORTS), // Parent with children CUSTOMER_DETAILS("Customer Details", "/customers/details", Permission.VIEW_CUSTOMER_DETAILS), CUSTOMER_REPORTS("Customer Reports", "/customers/reports", Permission.VIEW_CUSTOMER_REPORTS); private final String label; private final String route; private final Permission requiredPermission; private final MenuItem[] children; // Constructor MenuItem(String label, String route, Permission requiredPermission, MenuItem... children) { this.label = label; this.route = route; this.requiredPermission = requiredPermission; this.children = children; } // Getters public String getLabel() { return label; } public String getRoute() { return route; } public Permission getRequiredPermission() { return requiredPermission; } public MenuItem[] getChildren() { return children; } }
Step 2: Build the Tree with Permission Filtering
Create the Tree component and populate it with menu items, filtering out any items the user doesn't have permissions for:
// Initialize Tree with your MenuItem Enum as the node type Tree<MenuItem> menuTree = new Tree<>(); // Set how nodes are displayed (use the label from your Enum) menuTree.setItemCaptionGenerator(MenuItem::getLabel); // Get current user's permissions (replace with your actual permission fetch logic) Set<Permission> userPermissions = getCurrentUserPermissions(); // Recursively add menu items to the Tree, skipping items without permission addMenuItemsToTree(MenuItem.values(), null, menuTree, userPermissions); // Optional: Expand root nodes by default for better UX menuTree.expandItemsRecursively(MenuItem.DASHBOARD);
Recursive Helper Method for Populating the Tree
private void addMenuItemsToTree(MenuItem[] items, MenuItem parent, Tree<MenuItem> tree, Set<Permission> userPermissions) { for (MenuItem item : items) { // Skip items the user doesn't have permission to see if (userPermissions.contains(item.getRequiredPermission())) { // Add the menu item as a Tree node tree.addItem(item); // Set parent if this is a child menu item if (parent != null) { tree.setParent(item, parent); } // Recursively add child items if any exist if (item.getChildren() != null && item.getChildren().length > 0) { addMenuItemsToTree(item.getChildren(), item, tree, userPermissions); } } } }
Step 3: Handle Tree Selection (Replace Button Click Logic)
Replace your ValoMenuItemButton click handlers with a Tree selection listener to handle navigation and active state:
menuTree.addSelectionListener(event -> { event.getFirstSelectedItem().ifPresent(selectedItem -> { // Navigate to the corresponding view (replace with your existing navigation logic) getUI().getNavigator().navigateTo(selectedItem.getRoute()); // Apply the "selected" style to match your old button's visual state menuTree.setStyleGenerator(item -> item.equals(selectedItem) ? "selected" : null); }); });
Step 4: Match Your Valo Theme Styling
Keep the familiar "selected" state look by adding this CSS to your theme:
.v-tree-node-selected .v-tree-node-caption { background-color: #3F51B5; /* Replace with your original Valo selected color */ color: #ffffff; }
- Preserves all your existing permission logic without major rewrites
- Leverages Vaadin's native Tree component for cleaner, maintainable code
- Automatically handles hierarchical menu rendering without manual button loops
内容的提问来源于stack exchange,提问作者Melvin Mah

