如何在Vaadin中实现带分组行的CRUD树形表格?解决空指针异常
解决Vaadin TreeGridCrud空指针问题并实现树形分组CRUD表格
报错原因
这个空指针是因为TreeGridCrud初始化时,未指定树形结构的子项提供逻辑——它无法识别如何获取某个父节点下的子产品,因此抛出Given child item provider may not be null错误。
具体实现步骤
1. 给Product实体添加父子关联字段
确保实体类包含父产品关联和子产品查询的基础结构:
@Entity public class Product { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; // 父产品关联 @ManyToOne @JoinColumn(name = "parent_id") private Product parent; // 子产品集合(双向关联可选) @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL) private List<Product> children = new ArrayList<>(); // getter、setter、构造方法省略 }
2. 调整ProductView的TreeGridCrud初始化逻辑
需要明确传入树形数据的根节点获取逻辑和子节点获取逻辑,同时配置CRUD的增删改查回调:
@Route(value = "products", layout = MainView.class) public class ProductView extends VerticalLayout { private final ProductService productService; // 构造方法注入(推荐写法,避免字段注入的混乱) public ProductView(ProductService productService) { this.productService = productService; // 创建TreeGridCrud实例 TreeGridCrud<Product> productTable = new TreeGridCrud<>(Product.class); // 配置树形数据提供器 TreeDataProvider<Product> treeDataProvider = new TreeDataProvider<>( // 根节点获取:查询所有无父产品的记录 () -> productService.findAllByParentIsNull(), // 子节点获取:根据父节点查询子产品 product -> productService.findAllByParent(product) ); productTable.getGrid().setDataProvider(treeDataProvider); // 配置CRUD操作的数据源回调 productTable.setCrudListener(new CrudListener<Product>() { @Override public List<Product> findAll() { return productService.findAll(); } @Override public Product add(Product product) { return productService.save(product); } @Override public Product update(Product product) { return productService.save(product); } @Override public void delete(Product product) { productService.delete(product); } }); // 配置树形表格的层级显示列 productTable.getGrid().setHierarchyColumn("name"); // 新增其他列(示例) productTable.getGrid().addColumn(Product::getId).setHeader("ID"); add(productTable); } private void openNewProductFormEditor() { // 可在此实现新增表单打开逻辑,例如: // productTable.getCrudLayout().addNew(); } }
3. 完善ProductService的查询方法
补充树形结构所需的查询逻辑:
@Service public class ProductService { private final ProductRepository productRepository; @Autowired public ProductService(ProductRepository productRepository) { this.productRepository = productRepository; } public List<Product> findAll() { return productRepository.findAll(); } public Product save(Product product) { return productRepository.save(product); } public void delete(Product product) { productRepository.delete(product); } // 查询所有根节点产品 public List<Product> findAllByParentIsNull() { return productRepository.findByParentIsNull(); } // 根据父产品查询子产品 public List<Product> findAllByParent(Product parent) { return productRepository.findByParent(parent); } }
4. 在ProductRepository中添加对应查询接口
@Repository public interface ProductRepository extends JpaRepository<Product, Long> { List<Product> findByParentIsNull(); List<Product> findByParent(Product parent); }
内容的提问来源于stack exchange,提问作者Zakella
相关产品推荐
相关产品推荐

