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

如何用Vaadin Grid创建类Excel表格并整合多SQL表数据

矩阵式Vaadin Grid实现方案(多SQL表数据源)

核心思路

Vaadin Grid是基于行数据模型的组件,要实现Excel式的矩阵异构数据展示,关键是先将分散在多表中的数据统一聚合为符合Grid行结构的模型,再通过Grid的列绑定或动态列功能完成展示。

高效实现步骤

1. 构建统一的矩阵行DTO

定义通用的MatrixRowDTO,覆盖所有行和列的可能字段,同时标记行的来源类型,方便后续区分处理:

public class MatrixRowDTO {
    private String rowType; // 标记行来源:"MONITORING"或"DEPLOYMENT"
    private Consultant consultant; // 关联顾问表数据
    private BigDecimal region1Value; // 区域1数据
    private BigDecimal region2Value; // 区域2数据
    private BigDecimal region3Value; // 区域3数据
    // 其他必要字段、getter/setter
}

数据聚合建议:在DAO层通过SQL联查(如LEFT JOIN)一次性获取所有关联数据,避免多次数据库查询。示例SQL:

SELECT 
    m.id AS row_id, 'MONITORING' AS row_type, c.name AS consultant_name, 
    r1.value AS region1_value, r2.value AS region2_value, r3.value AS region3_value
FROM Monitoring m
LEFT JOIN Consultant c ON m.consultant_id = c.id
LEFT JOIN Region1 r1 ON m.region1_id = r1.id
LEFT JOIN Region2 r2 ON m.region2_id = r2.id
LEFT JOIN Region3 r3 ON m.region3_id = r3.id
UNION ALL
SELECT 
    d.id AS row_id, 'DEPLOYMENT' AS row_type, c.name AS consultant_name, 
    r1.value AS region1_value, r2.value AS region2_value, r3.value AS region3_value
FROM Deployment d
LEFT JOIN Consultant c ON d.consultant_id = c.id
LEFT JOIN Region1 r1 ON d.region1_id = r1.id
LEFT JOIN Region2 r2 ON d.region2_id = r2.id
LEFT JOIN Region3 r3 ON d.region3_id = r3.id

将查询结果直接映射到MatrixRowDTO,这是最高效的数据获取方式。

2. 配置Vaadin Grid数据提供者

如果数据量较大,使用CallbackDataProvider实现懒加载分页,避免一次性加载所有数据:

DataProvider<MatrixRowDTO, Void> dataProvider = DataProvider.fromCallbacks(
    query -> {
        // 分页查询:query.getOffset()是起始位置,query.getLimit()是每页数量
        List<MatrixRowDTO> rows = matrixRowService.getRows(query.getOffset(), query.getLimit());
        return rows.stream();
    },
    query -> matrixRowService.getTotalRowCount() // 返回总数据量
);
grid.setDataProvider(dataProvider);

小数据量则直接用ListDataProvider:

List<MatrixRowDTO> rows = matrixRowService.getAllRows();
grid.setItems(rows);

添加Areas和Consultant列

添加Consultant列

如果DTO中已关联Consultant实体,直接绑定列并渲染字段:

grid.addColumn(row -> row.getConsultant() != null ? row.getConsultant().getName() : "-")
    .setHeader("Consultant")
    .setKey("consultant"); // 设置key方便后续维护

如果DTO中仅存储consultantId,建议在数据聚合阶段就关联查询顾问名称,避免在UI渲染时发起数据库请求(会导致界面卡顿)。

添加Areas(Region 1/2/3)列

基于已有的单个DTO填充逻辑,扩展DTO字段后直接绑定:

// 静态列绑定
grid.addColumn(MatrixRowDTO::getRegion1Value)
    .setHeader("Region 1")
    .setKey("region1");

grid.addColumn(MatrixRowDTO::getRegion2Value)
    .setHeader("Region 2")
    .setKey("region2");

grid.addColumn(MatrixRowDTO::getRegion3Value)
    .setHeader("Region 3")
    .setKey("region3");

如果区域列是动态可变的(比如可能新增Region 4),可以通过循环生成动态列:

// 假设从配置或数据库获取区域列表
List<String> areaHeaders = Arrays.asList("Region 1", "Region 2", "Region 3");
// DTO中添加Map<String, BigDecimal> regionValues字段存储区域值
for (String header : areaHeaders) {
    grid.addColumn(row -> row.getRegionValues().getOrDefault(header, BigDecimal.ZERO))
        .setHeader(header)
        .setKey(header.toLowerCase().replace(" ", "-"));
}

优化建议

  • 缓存静态数据:如果Consultant或区域字典数据不频繁更新,用本地缓存(如Guava Cache)存储,减少重复查询。
  • 行样式区分:给不同来源的行添加差异化样式,提升用户体验:
    grid.addClassNameGenerator(row -> {
        return switch(row.getRowType()) {
            case "MONITORING" -> "monitoring-row";
            case "DEPLOYMENT" -> "deployment-row";
            default -> "";
        };
    });
    
    对应的CSS:
    .monitoring-row { background-color: #f8f9fa; }
    .deployment-row { background-color: #fff3cd; }
    
  • 使用LazyDataView:启用懒加载后,Grid只会加载当前可见页的数据,大幅提升大数据量下的渲染速度:
    LazyDataView<MatrixRowDTO> lazyDataView = grid.setLazyDataView(dataProvider);
    lazyDataView.setPageSize(20); // 设置每页显示行数
    

内容的提问来源于stack exchange,提问作者Anshaz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 01:20:37