You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 03:15:14