Skip to content

语义建模 ​

EruptCube 是 Erupt 框架提供的零代码数据分析能力,通过在 Java 类上添加注解,即可自动生成支持多维度下钻、指标聚合的数据分析视图,无需编写任何前端代码。

快速上手 ​

只需三步,即可完成一个数据分析模块:

第一步:创建 Cube 类,绑定数据源

java
@EruptCube(name = "订单分析", sql = "order_info", sqlType = SqlType.TABLE_NAME)
public class OrderCube {
    // ...
}

第二步:声明维度(用于分组、筛选)

java
@Dimension(title = "渠道")
private String channel;

@Dimension(title = "下单时间")
private Date createTime;

第三步:声明指标(聚合计算)

java
@Measure(title = "订单量", sql = "count(*)")
private Long orderCount;

@Measure(title = "总金额", sql = "sum(amount)")
private Double totalAmount;

启动后,Erupt 自动将该类注册为一个数据分析视图,并在 UI 中展示。

注解详解 ​

@EruptCube — 声明数据立方体 ​

标注在类上,定义数据来源与基本配置。

java
@EruptCube(
    name        = "显示名称",           // 必填
    sql         = "SQL 或表名",         // 必填
    sqlType     = SqlType.SUB_QUERY,    // 默认值,单表用 TABLE_NAME
    description = "",
    explores    = { @Explore(code = "overview", name = "Overview") },
    tags        = {},
    dataProxy   = {}
)
属性说明默认值
nameUI 显示名称必填
sql子查询 SQL 或表名必填
sqlType数据源类型,见下方说明SUB_QUERY
description描述文本""
explores对外暴露的查询视图overview
tags分类标签,用于 UI 分组{}
dataProxy数据代理处理器{}
datasource指定数据源(多数据源场景)""

sqlType 选择:

场景sqlTypesql 填写内容
单表,无 JOINSqlType.TABLE_NAME直接填表名,如 "order_info"
多表 JOIN 或复杂查询SqlType.SUB_QUERY(默认)完整 SELECT 语句

@Dimension — 声明维度 ​

标注在字段上,用于描述性分类字段,支持分组和筛选。

java
@Dimension(
    title = "渠道",       // 必填,UI 显示名
    sql   = "channel",   // 对应 SQL 列名;为空时自动取字段名
    type  = FieldType.AUTO
)
private String channel;
属性说明默认值
titleUI 显示名称必填
sql对应 SQL 列名或函数""(取字段名)
type数据类型,见下方说明AUTO
hidden是否在 UI 中隐藏false
tags分类标签{}

注意

多表 JOIN 场景下,若列有别名(column AS alias),sql 必须填别名,而非原列名。

@Measure — 声明指标 ​

标注在字段上,必须配合聚合函数使用。

java
@Measure(
    title = "订单量",       // 必填,UI 显示名
    sql   = "count(*)"     // 必填,聚合 SQL 表达式
)
private Long orderCount;
属性说明默认值
titleUI 显示名称必填
sql聚合函数表达式必填
type数据类型AUTO
hidden是否在 UI 中隐藏false

常用聚合表达式:

java
sql = "count(*)"                                       // 总行数
sql = "count(distinct user_id)"                        // 去重计数
sql = "sum(amount)"                                    // 求和
sql = "avg(duration)"                                  // 均值
sql = "max(score)"                                     // 最大值
sql = "min(price)"                                     // 最小值
sql = "sum(case when success then 1 else 0 end)"       // 条件计数(成功数)
sql = "sum(case when not success then 1 else 0 end)"   // 条件计数(失败数)
sql = "round(sum(amount) / count(*), 2)"               // 复合表达式(客单价)

@Parameter — 声明查询参数 ​

标注在字段上,用于运行时动态传入过滤条件,参数值会自动注入到 SQL 的 WHERE 子句中。

java
@Parameter(
    title = "状态",
    type  = FieldType.STRING,
    vl    = {
        @VL(value = "1", label = "已完成"),
        @VL(value = "0", label = "待处理")
    }
)
private String status;

FieldType — 数据类型 ​

type = FieldType.AUTO 时,框架根据 Java 字段类型自动推断:

Java 类型推断结果
Short / Integer / Long / Double / FloatNUMBER
Date / LocalDateTime / LocalDateDATE
其他(String、Boolean、枚举等)STRING

@Explore — 查询视图 ​

在 @EruptCube 的 explores 属性中配置,可定义多个不同视角的分析视图。

java
@EruptCube(
    name = "订单分析",
    sql  = "order_info",
    sqlType = SqlType.TABLE_NAME,
    explores = {
        @Explore(code = "all",      name = "全部订单"),
        @Explore(code = "finished", name = "已完成", where = "status = 1"),
        @Explore(code = "failed",   name = "已取消", where = "status = 0")
    }
)
属性说明默认值
code唯一标识,不可重复必填
nameUI 显示名称必填
where追加的 WHERE 条件(自动 AND 拼接)""
parameters固定视图参数,见 @ExploreParameter{}
joins关联其他 Cube{}
dimensions视图中使用的维度,不填则显示所有{}
measures视图中使用的指标,不填则显示所有{}

完整示例 ​

示例 1:直接引用单表 ​

java
@EruptCube(
    name    = "用户登录日志",
    sql     = "e_upms_login_log",
    sqlType = SqlType.TABLE_NAME
)
public class LoginLogCube {

    @Dimension(title = "用户名", sql = "user_name")
    private String userName;

    @Dimension(title = "IP 地址", sql = "ip")
    private String ip;

    @Dimension(title = "浏览器", sql = "browser")
    private String browser;

    @Dimension(title = "登录时间", sql = "login_time")
    private Date loginTime;

    @Measure(title = "登录次数", sql = "count(*)")
    private Long count;
}

示例 2:多表 JOIN 子查询 ​

java
@EruptCube(
    name = "通知日志分析",
    sql  = """
        select detail.status,
               detail.success,
               detail.create_time,
               detail.channel,
               detail.receive_user_id,
               log.title,
               scene.name
        from e_notice_log_detail detail
               inner join e_notice_log log on detail.notice_log_id = log.id
               inner join e_notice_scene scene on log.notice_scene_id = scene.id
        """
)
public class NoticeLogCube {

    @Dimension(title = "通知场景", sql = "name")   // 取别名/列名,而非字段名
    private String name;

    @Dimension(title = "发送渠道", sql = "channel")
    private String channel;

    @Dimension(title = "是否成功", sql = "success")
    private Boolean success;

    @Dimension(title = "创建时间", sql = "create_time")
    private Date createTime;

    @Measure(title = "总量", sql = "count(*)")
    private Long count;

    @Measure(title = "成功数", sql = "sum(case when success then 1 else 0 end)")
    private Long successCount;

    @Measure(title = "失败数", sql = "sum(case when not success then 1 else 0 end)")
    private Long failCount;

    @Measure(title = "接收用户数(去重)", sql = "count(distinct receive_user_id)")
    private Long uniqueReceivers;
}

示例 3:与 @Erupt 实体类共用 ​

当一个表既需要 CRUD 管理页面又需要数据分析视图时,可将两个注解放在同一个类上:

java
@Entity
@Table(name = "e_upms_operate_log")
@Erupt(name = "操作日志", ...)
@EruptCube(name = "操作日志分析", sql = "e_upms_operate_log", sqlType = SqlType.TABLE_NAME)
public class EruptOperateLog extends BaseModel {

    // @Dimension 和 @EruptField 可以同时标注同一字段
    @Dimension(title = "操作用户", sql = "operate_user")
    @EruptField(views = @View(title = "操作人"), ...)
    private String operateUser;

    // JPA 实体中,指标字段必须加 @Transient 避免 ORM 映射
    @Transient
    @Measure(title = "操作次数", sql = "count(*)")
    private Long count;

    @Transient
    @Measure(title = "最大请求耗时", sql = "max(total_time)")
    private Long maxDuration;
}

常见问题 ​

Q:字段名和 SQL 列名不一致时怎么处理? ​

@Dimension(sql = "列名或别名") 填 SQL 中实际的列名或 AS 别名,Java 字段名可自由命名。

java
// SQL: select create_time as ct from ...
@Dimension(title = "创建时间", sql = "ct", type = FieldType.DATE)
private Date createTime;  // Java 字段名随意,sql 属性决定 SQL 映射

Q:纯 Cube 类和 JPA 实体类的区别? ​

  • 纯 Cube 类(不继承 BaseModel、不带 @Entity):指标字段无需 @Transient
  • JPA 实体类(带 @Entity):指标字段必须加 @Transient,否则 JPA 会尝试映射该虚拟列

Q:Boolean 类型维度显示异常? ​

Boolean 字段在 FieldType.AUTO 模式下被推断为 STRING(按 "true"/"false" 字符串分组),这是预期行为,无需特殊处理。

Q:如何对同一数据设置多个分析视角? ​

使用 explores 配置多个 @Explore,每个视图可指定独立的 where 条件,实现"全量"、"成功"、"失败"等不同维度的固定过滤。

关于注解字符串在 IDE 里如何获得 SQL / VTL 语法高亮与校验,见专题 《注解里的那行字符串,不是哑字符串》。

贡献者

The avatar of contributor named as YuePeng YuePeng
The avatar of contributor named as Claude Fable 5.1 Claude Fable 5.1

页面历史

Released under the Apache-2.0 License.