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

基于JSF与PrimeFaces如何为各资产自动生成专属雷达统计图表

资产专属雷达图实现流程

核心问题定位

原有代码直接将全量风险数据塞入单个雷达图实例,没有按资产ID做数据拆分,且存在重复查库、循环内重复赋值的性能问题,按以下步骤改造即可实现按资产生成独立图表、新增资产自动生成图表的需求。


步骤1:将全量风险数据按资产维度分组

首先把查询到的所有风险关联数据按asset_id分组,同一个资产下的所有风险数据归为一组,注意不要在循环里反复调用数据库查询方法,提前把查询结果存入局部变量复用,避免重复连库。

// 仅查询一次数据库,拿到全量数据后复用
List<risk> allRiskData = getGet_all_risk_for_radar_chart2();
// 按资产ID分组,key为资产ID,value为该资产关联的所有风险数据
Map<Integer, List<risk>> assetRiskGroup = allRiskData.stream()
        .collect(Collectors.groupingBy(risk::getId));

如果项目用的JDK版本不支持stream,手动遍历allRiskData按asset_id放到Map里也可以。


步骤2:封装单资产雷达图的通用生成方法

把原来写死的单图表生成逻辑,改造成支持传入资产ID、对应风险数据列表,返回专属RadarChartModel的通用方法,不再写死单个图表实例。

/**
 * 生成单个资产的专属雷达图
 * @param assetId 资产ID
 * @param assetRisks 该资产关联的所有风险数据
 * @return 组装完成的雷达图模型
 */
private RadarChartModel buildSingleAssetRadar(Integer assetId, List<risk> assetRisks) {
    RadarChartModel model = new RadarChartModel();
    ChartData chartData = new ChartData();

    // 初始化计算风险值数据集
    RadarChartDataSet riskSet = new RadarChartDataSet();
    riskSet.setLabel("计算风险值");
    riskSet.setFill(true);
    riskSet.setBackgroundColor("rgba(255, 99, 132, 0.2)");
    riskSet.setBorderColor("rgb(255, 99, 132)");
    riskSet.setPointBackgroundColor("rgb(255, 99, 132)");
    riskSet.setPointBorderColor("#fff");
    riskSet.setPointHoverBackgroundColor("#fff");
    riskSet.setPointHoverBorderColor("rgb(255, 99, 132)");
    List<Number> riskValues = new ArrayList<>();

    // 初始化风险缓解率数据集
    RadarChartDataSet mitigationSet = new RadarChartDataSet();
    mitigationSet.setLabel("风险缓解率");
    mitigationSet.setFill(true);
    mitigationSet.setBackgroundColor("rgba(54, 162, 235, 0.2)");
    mitigationSet.setBorderColor("rgb(54, 162, 235)");
    mitigationSet.setPointBackgroundColor("rgb(54, 162, 235)");
    mitigationSet.setPointBorderColor("#fff");
    mitigationSet.setPointHoverBackgroundColor("#fff");
    mitigationSet.setPointHoverBorderColor("rgb(54, 162, 235)");
    List<Number> mitigationValues = new ArrayList<>();

    // 初始化雷达图轴标签
    List<String> labels = new ArrayList<>();

    // 仅遍历当前资产的风险数据填充,不再遍历全量数据
    for (risk item : assetRisks) {
        riskValues.add(item.getCalculated_risk());
        mitigationValues.add(item.getMitigation_percent());
        labels.add("风险ID:" + item.getRisk_id()); // 后续可替换为风险名称字段,展示效果更好
    }

    // 数据填充完成后统一赋值,不要在循环里反复set
    riskSet.setData(riskValues);
    mitigationSet.setData(mitigationValues);
    chartData.addChartDataSet(riskSet);
    chartData.addChartDataSet(mitigationSet);
    chartData.setLabels(labels);

    // 统一配置项
    RadarChartOptions options = new RadarChartOptions();
    Elements elements = new Elements();
    ElementsLine lineConfig = new ElementsLine();
    lineConfig.setTension(0);
    lineConfig.setBorderWidth(3);
    elements.setLine(lineConfig);
    options.setElements(elements);

    model.setOptions(options);
    model.setData(chartData);
    return model;
}

步骤3:做图表缓存,支持批量生成所有资产的雷达图

在后端管理Bean中维护一个缓存Map,key为资产ID,value为对应资产的雷达图实例,避免每次请求都重新生成图表。

// 资产雷达图缓存,key=资产ID,value=对应雷达图模型
private Map<Integer, RadarChartModel> assetRadarCache = new HashMap<>();

/**
 * 刷新全量资产的雷达图缓存
 */
public void refreshAllAssetRadar() throws Exception {
    assetRadarCache.clear();
    List<risk> allRiskData = getGet_all_risk_for_radar_chart2();
    Map<Integer, List<risk>> assetRiskGroup = allRiskData.stream()
            .collect(Collectors.groupingBy(risk::getId));
    // 遍历每个资产,生成对应图表存入缓存
    for (Map.Entry<Integer, List<risk>> entry : assetRiskGroup.entrySet()) {
        Integer assetId = entry.getKey();
        List<risk> risks = entry.getValue();
        assetRadarCache.put(assetId, buildSingleAssetRadar(assetId, risks));
    }
}

/**
 * 对外提供查询方法,前端根据资产ID获取对应图表
 */
public RadarChartModel getRadarByAssetId(Integer assetId) {
    return assetRadarCache.get(assetId);
}

在Bean的@PostConstruct初始化方法中调用refreshAllAssetRadar(),页面首次加载时就会自动生成所有已有资产的雷达图。


步骤4:实现新增资产自动生成雷达图逻辑

在新增资产、保存资产与风险关联关系的业务方法执行成功、数据全部落库后,根据业务场景选择以下两种方案之一即可:

  • 方案1(简单易维护,适合资产总量<1000的场景):直接调用refreshAllAssetRadar()全量刷新缓存,不需要额外写逻辑,不会出现数据不一致问题
  • 方案2(性能更好,适合资产量大的场景):单独查询刚新增资产对应的所有风险关联数据,调用buildSingleAssetRadar()生成该资产的雷达图,直接put到assetRadarCache缓存中即可,不需要全量刷新

注意:必须等资产的风险关联关系、风险评分、缓解率数据全部写入数据库后再触发生成逻辑,否则会出现图表数据缺失的问题。


步骤5:前端页面渲染

在资产列表、资产详情页面,遍历资产数据时为每个资产单独引入PrimeFaces雷达图标签,绑定对应资产ID的图表实例即可:

<!-- 遍历资产列表 -->
<ui:repeat value="#{assetBean.assetList}" var="asset">
    <div class="asset-item">
        <h4>资产#{asset.id} 风险雷达图</h4>
        <p:radarChart model="#{radarBean.getRadarByAssetId(asset.id)}" style="width: 420px;height:420px;"/>
    </div>
</ui:repeat>

原有代码问题修正

  • 移除循环内重复调用数据库查询方法的逻辑,所有数据一次查询后复用,避免不必要的数据库连接开销
  • 移除循环内反复调用setData()、setLabels()的逻辑,等数据集、标签列表全部填充完成后统一赋值即可
  • 所有数据填充前先按资产ID过滤分组,禁止将不同资产的风险数据塞入同一个图表实例

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 22:03:25