YAML 参考

动态模型以 YAML 格式进行序列化,根键为 model:。本节介绍该文件的结构:每个字段、类型、是否必填、默认值以及适用规则。有关如何定义模型和页面,请参考 定义模型视图和菜单项

模型

model 根节点包含以下顶层字段:

字段 类型 必填 说明

basePackage

string

配置生成的动态实体、枚举和视图类的 Java 包。如果省略或为空,有效值为最后一个 Jmix 模块基础包加上 .dynmod。使用默认值时,序列化时会省略该字段。

enumerations

list

动态枚举定义。缺失或 null 则为空列表。

entities

list

静态实体扩展和动态实体定义。缺失或 null 则为空列表。

名称与解析

实体定义按 Jmix 实体名称匹配:

  • 如果元数据中已存在该 name 的实体,则该定义使用动态属性、验证、唯一性或视图覆盖来扩展该静态实体。

  • 如果元数据中不存在该实体,动态模型将创建一个具有相同 Jmix 实体名称的动态实体,并生成一个名为 <effective basePackage>.<name> 的 Java 类。

动态实体、属性、枚举类和枚举值使用类似 Java 的名称。生成的数据库标识符会自动规范化:

  • 驼峰命名会被分割为大写加下划线的名称,例如 loyaltyLevel 变为 LOYALTY_LEVEL

  • 不支持的字符会被替换为下划线;

  • 保留字会添加尾随下划线,例如 user 变为 USER_

  • 超过 DBMS 长度限制的标识符会使用 8 字符哈希进行缩写。

本地化值

大多数标题使用简单的语言环境和消息的映射:

messages:
  en: "Loyalty level"
  de: "Treuestufe"

某些字段是 本地化值,可以接受纯字符串:

viewTitle: "Benefit"

或语言环境映射:

viewTitle:
  en: "Loyalty levels"
  de: "Treuestufen"

语言环境键值必须为非空并映射到字符串。运行时,优先匹配精确的语言环境(例如 zh_CN),然后是仅语言的语言环境(例如 zh),最后是映射中的第一个值。

枚举

动态枚举在 model.enumerations 中声明:

enumerations:
  - name: "CustomerGrade"
    messages:
      en: "Customer grade"
    values:
      - name: "PLATINUM"
        id: "30"
        messages:
          en: "Platinum"
      - name: "GOLD"
        id: "20"
        messages:
          en: "Gold"
      - name: "BRONZE"
        id: "10"
        messages:
          en: "Bronze"

枚举字段:

字段 类型 必填 说明

name

string

短类名或完全限定类名。短名称会相对于 basePackage 解析。

values

list

必须至少包含一个值。

messages

map

枚举类的标题。

枚举值字段:

字段 类型 必填 说明

name

string

Java 枚举常量名称。

id

string

存储的枚举 ID。一个动态枚举中的所有 ID 必须是同质的:要么全部解析为 32 位整数,要么全部是非整数字符串。

messages

map

此枚举值的标题。

当所有 ID 都是整数字符串时,动态枚举实现 EnumClass<Integer>,否则实现 EnumClass<String>

对枚举属性使用 enumeration 字段:

- name: "grade"
  enumeration: "CustomerGrade" # short name, resolved via base package
  messages:
    en: "Grade"

如果类实现了 EnumClass,也支持静态枚举。使用完全限定类名,或者当枚举类位于 basePackage 中时使用短名称。枚举的数据库映射同时支持整数 ID 和字符串 ID。

实体

实体定义在 model.entities 中声明:

- name: "Benefit"
  messages:
    en: "Benefit"
  attributes:
    - name: "name"
      javaClass: "java.lang.String"
      instanceName: true
      messages:
        en: "Name"
  views:
    - type: "detail"
      viewId: "Benefit.detail"
      viewTitle: "Benefit"
      descriptor:
        template: "default"
字段 类型 必填 说明

name

string

Jmix 实体名称。使用已有的元数据名称表示静态实体扩展;否则将创建动态实体。

store

string

动态实体的物理 JPA 数据存储。空白和 main 在序列化时会被省略。静态实体定义只有在数据存储与实体元数据存储匹配时才可声明。已有动态实体的 store 无法更改。

attributes

list

动态属性。缺失或 null 则为空列表。

uniqueConstraints

list

实体级唯一命名约束。

views

list

实体的 UI 视图。

resourceRoles

object

实体 CRUD 角色授权。仅支持动态实体。

validation

object

实体级验证约束。

messages

map

实体标题。

动态实体表的前缀可配置:jmix.dynmodel.dynamic-entity-table-prefix,默认为 DYN_。静态实体动态属性使用 jmix.dynmodel.static-entity-table-prefix 前缀存储在侧表中,默认为 DYN_。静态侧表在与父实体相同的物理存储中创建。

属性

每个属性只能定义下列类型之一:

  • 数据类型:javaClass

  • 引用:entityName

  • 枚举:enumeration

- name: "Customer"
  attributes:
    - name: "taxId"
      javaClass: "java.lang.String"
      length: 20
      required: true
      unique: true
      validation:
        constraints:
          - annotation: "Pattern"
            parameters:
              regexp: "^[A-Z0-9-]+$"
            message:
              en: "Tax ID can contain uppercase letters, digits and dashes only"
      messages:
        en: "Tax ID"
字段 类型 必填 说明

name

string

属性名称。

javaClass

string

类型之一

数据类型属性的 Java 类。请参见下面的 支持的值

entityName

string

类型之一

引用和集合的目标 Jmix 实体名称。

enumeration

string

类型之一

动态或静态枚举名称。短名称通过 basePackage 解析。

length

integer

字符串、URI 值、字节数组和字符串 ID 枚举的长度。

lob

boolean

LOB 指示符。仅支持 java.lang.Stringbyte[] 属性。

required

boolean

添加必填元数据和默认组 NotNull 验证规则。不会创建数据库 NOT NULL 约束。

unique

boolean

名为 <attributeName>Unique 的单属性唯一约束的简写。

instanceName

boolean

将该属性标记为实例名称属性。如果标记了多个属性,则使用第一个,后面的会被忽略并发出警告。

collection

boolean

entityName 的有序组合列表。

calculated

object

计算属性,只读且非持久化。

validation

object

属性级约束。不支持用于计算型属性。

resourceRoles

object

查看/修改属性的角色。

messages

map

属性标题。

支持的 javaClass 值

框架将可持久化的数据类型映射到 SQL 类型。手动编写 YAML 时使用以下值:

YAML 值 Java 类型 默认 SQL 映射

java.lang.String

String

varchar(255)length 覆盖大小

java.net.URI

URI

varchar(1024)length 覆盖大小

[B

byte[]

varbinary(255)length 覆盖大小

java.lang.Booleanboolean

Boolean

boolean

java.lang.Characterchar

Character

char(1)

java.lang.Integerint

Integer

integer

java.lang.Longlong

Long

bigint

java.lang.Shortshort

Short

smallint

java.lang.Doubledouble

Double

double

java.lang.Floatfloat

Float

real

java.math.BigDecimal

BigDecimal

decimal(38, 18)

java.math.BigInteger

BigInteger

decimal(38, 0)

java.time.LocalDate

LocalDate

date

java.time.LocalTime

LocalTime

time

java.time.LocalDateTime

LocalDateTime

timestamp

java.time.OffsetTime

OffsetTime

time with time zone

java.time.OffsetDateTime

OffsetDateTime

timestamp with time zone

java.util.UUID

UUID

DB 特定的 UUID 类型

注意事项:

  • 序列化器存储 Java 的 Class#getName() 值。对于字节数组,是 [B;如果不确定,请复制序列化后的值。

  • 除非扩展了 DB 类型映射,否则动态模型存储不支持其他 Java 类。

数据库特定差异:

类型 HSQLDB / H2 PostgreSQL MySQL / MariaDB SQL Server Oracle

UUID

uuid

uuid

char(32)

uniqueidentifier

char(32)

String

varchar(n)

varchar(n)

varchar(n)

nvarchar(n)

varchar2(n)

byte[]

varbinary(n)

bytea

varbinary(n)

varbinary(n)

raw(min(n, 2000))

Boolean

boolean

boolean

bit

bit

char(1)

OffsetTime

time with time zone

time with time zone

time 以 UTC 存储

datetimeoffset

timestamp with time zone

OffsetDateTime

timestamp with time zone

timestamp with time zone

datetime 以 UTC 存储

datetimeoffset

timestamp with time zone

String + lob: true

clob

text

longtext

nvarchar(max)

clob

byte[] + lob: true

blob

bytea

longblob

varbinary(max)

blob

引用

单值引用使用 entityName

- name: "loyaltyLevel"
  entityName: "LoyaltyLevel"
  messages:
    en: "Loyalty level"

规则:

  • 子类必须解析为模型中声明的动态实体或已有的静态实体。

  • 动态引用存储子类的主键。

  • 不支持具有复合主键的静态子类。

  • 父类和子类必须在同一物理存储中。

集合

集合属性是有序组合列表:

- name: "benefits"
  entityName: "Benefit"
  collection: true
  messages:
    en: "Benefits"

规则:

  • entityName 必需。

  • 子类必须是动态实体。

  • 不支持 javaClassenumerationlobinstanceName

  • 集合不能参与唯一约束。

  • 父类和子类必须在同一物理存储中。

  • 不支持具有复合主键的静态父类。

动态模型会为反向父类引用和排序列创建内部子属性。不会写入 YAML。

计算属性

计算属性是只读的、非持久化的属性,在访问时计算:

- name: "publicSummary"
  javaClass: "java.lang.String"
  calculated:
    evaluator: "spel"
    expression: "(name ?: '') + ': ' + (description ?: '')"
    dependsOn:
      - "name"
      - "description"
  messages:
    en: "Public summary"
字段 类型 必填 说明

evaluator

string

DynamicCalculatedAttributeEvaluator bean 从 getName() 返回的评估器名称。如果省略或为空,则使用 jmix.dynmodel.calculated-attributes.default-evaluator 中的配置,默认使用 spel

expression

string

评估器的表达式。内置的 spel 评估器使用 SimpleEvaluationContext

dependsOn

list

与计算型属性一起加载的实例属性名称。不能使用点号路径。缺失或 null 则为空列表。

规则:

  • 计算型属性必须使用 javaClassenumeration 声明唯一结果类型。

  • 不支持 entityNamecollectionrequiredvalidation 和唯一性配置。

  • lob: true 只是一个 UI 元数据提示,仍然要求 javaClassjava.lang.Stringbyte[]

  • 依赖属性必须存在于同一实体,无论是在当前模型中还是在已有的元数据中。

  • 不支持实体中计算属性之间的循环依赖。

  • 不支持将已有的存储属性改为计算型属性,或将已有的计算型属性改为存储属性。也不支持更改计算属性的结果类型。

内置的 SpEL 评估器支持元数据感知的属性读取,并注册了 DynamicCalculatedAttributeFunction 函数。不开放 Spring bean、T(…​)、构造函数、任意方法调用、反射、类加载器访问或基础架构 API。

属性验证

属性验证在 attributes[].validation.constraints 中声明:

validation:
  constraints:
    - annotation: "Pattern"
      parameters:
        regexp: "^[A-Z0-9-]+$"
      message:
        en: "Tax ID can contain uppercase letters, digits and dashes only"

约束字段:

字段 类型 必填 说明

annotation

string

约束别名。请参见下面的支持别名。

parameters

map

YAML 标量/列表/对象值。参数名称取决于约束。缺失则为空映射。

groups

list

分组别名或完全限定的验证组类名。缺失表示 Default

message

本地化值

纯字符串或语言环境消息映射。

支持的组:

  • Default

  • UiComponentChecks

  • UiCrossFieldChecks

  • RestApiChecks

  • 可通过 Class.forName() 解析的完全限定类名。

支持的属性约束:

别名 适用于 参数

NotNull

任意属性

NotEmpty

字符串、集合、数组

NotBlank

字符串

Size

字符串、集合、数组

min 可选,默认 0max 可选,默认 Integer.MAX_VALUE

Length

字符串

min 可选,默认 0max 可选,默认 Integer.MAX_VALUE

Min

数值

value

Max

数值

value

DecimalMin

数值

valueinclusive 可选布尔值,默认 true

DecimalMax

数值

valueinclusive 可选布尔值,默认 true

Digits

数值

integerfraction

Positive

数值

PositiveOrZero

数值

Negative

数值

NegativeOrZero

数值

Past

日期/时间

PastOrPresent

日期/时间

Future

日期/时间

FutureOrPresent

日期/时间

Pattern

字符串

regexp

Email

字符串

AssertTrue

布尔值

AssertFalse

布尔值

验证使用 Bean Validation 的空值语义:除非规则是 NotNullNotEmptyNotBlankAssertTrueAssertFalse,否则 null 是有效的。

required: true 等同于必填 UI 元数据加上默认组的 NotNull 规则。验证元数据不会创建数据库约束。

实体验证

实体级验证在 entities[].validation.constraints 下声明:

validation:
  constraints:
    - name: "discountDescriptionRequired"
      target: "entity"
      type: "expression"
      evaluator: "spel"
      expression: "discount == null || description != null"
      attributes:
        - "discount"
        - "description"
      path: "description"
      groups:
        - "UiCrossFieldChecks"
        - "RestApiChecks"
      message:
        en: "Description is required when discount is specified"
字段 类型 必填 说明

name

string

约束名称。

target

string

必须为 entity

type

string

expressionbean

evaluator

string

expression

内置表达式评估器为 spel。空值也解析为 spel

expression

string

expression

对于有效实体必须评估为 true

validator

string

bean

DynamicModelConstraintValidator bean 返回的名称。

attributes

list

参与的属性名称。每个名称必须存在于模型或元数据中。

path

string

违规属性路径。空值表示 bean 级违规。

groups

list

与属性验证相同的组别名。

message

localized value

纯字符串或语言环境映射。

表达式约束使用与计算型属性相同的受限 SpEL 属性访问方法。bean 约束委托给应用程序的 DynamicModelConstraintValidator bean。

唯一约束

单属性唯一性:

unique: true

复合唯一性:

uniqueConstraints:
  - name: "customerCountryTaxIdUnique"
    attributes:
      - "countryCode"
      - "taxId"
    message:
      en: "Tax ID must be unique within a country"
字段 类型 必填 说明

name

string

逻辑约束名称。必须非空且在实体中唯一。物理 DB 名称由表名加上此值生成。

attributes

list

至少一个直接动态属性。不能使用重复名称。

message

本地化值

违规消息。

规则:

  • attributes[].unique: true 在比较和 DDL 计划之前会被规范化为命名的实体级约束。

  • 只支持直接的持久化单值动态属性。

  • 不支持计算型属性、集合和 LOB 属性。

  • 不支持静态软删除父类。

  • 如果现有行已包含重复值,则应用新的唯一约束会失败。

  • 可空的唯一性遵循 DBMS 行为。

资源角色

动态的 resourceRoles 声明会在运行时创建叠加性质的资源策略。如果没有声明则不授予访问权限。在 jmix.dynmodel.security.full-access-roles 中列出的角色会授予对所有动态模型资源的完全访问权限;默认为 system-full-access

角色代码必须非空。错误的角色代码会在日志记录且不授予访问权限。

实体级 CRUD 授权仅支持动态实体:

resourceRoles:
  read:
    - "employee"
    - "manager"
  create:
    - "manager"
  update:
    - "manager"
  delete:
    - "manager"

属性授权支持静态和动态实体的动态属性:

- name: "countryCode"
  javaClass: "java.lang.String"
  length: 2
  resourceRoles:
    view:
      - "employee"
      - "manager"
    modify:
      - "manager"
  messages:
    en: "Country code"

视图和菜单授权是列表:

views:
  - type: "list"
    viewId: "LoyaltyLevel.list"
    viewRoute: "loyalty-levels"
    viewTitle:
      en: "Loyalty levels"
      de: "Treuestufen"
    templateParams:
      includeProperties: ["name", "discount"]
      excludeProperties: ["publicSummary"]
    resourceRoles:
      - "employee"
      - "manager"
    menuItem:
      parentMenu: "application"
      insertBefore: "Customer.list"
      title:
        en: "Loyalty levels"
      resourceRoles:
        - "employee"
        - "manager"
    descriptor:
      template: "default"

视图

视图在 entities[].views 下声明。

views:
  - type: "list"
    viewId: "LoyaltyLevel.list"
    viewRoute: "loyalty-levels"
    viewTitle:
      en: "Loyalty levels"
      de: "Treuestufen"
    templateParams:
      includeProperties: ["name", "discount"]
      excludeProperties: ["publicSummary"]
    resourceRoles:
      - "employee"
      - "manager"
    menuItem:
      parentMenu: "application"
      insertBefore: "Customer.list"
      title:
        en: "Loyalty levels"
      resourceRoles:
        - "employee"
        - "manager"
    descriptor:
      template: "default"

视图字段:

字段 类型 必填 说明

type

string

动态实体的 UI

listdetail。反序列化时不区分大小写。动态实体视图必填。静态实体视图可以从已注册的基础视图推断。

viewId

string

唯一的视图 ID。动态和静态视图声明都必须显式设置。

viewRoute

string

动态实体路由段。默认从 viewId 生成;详情视图附加 /:id。静态实体视图不支持此字段。

viewTitle

本地化值

动态实体视图标题。静态实体视图不支持此字段。

templateParams

map

动态实体模板参数。静态实体视图不支持此字段。

resourceRoles

list

可以打开该视图的角色代码。静态实体视图不支持此字段。

menuItem

object

动态实体菜单项。静态实体视图不支持此字段。

descriptor

object

静态实体

XML 描述符声明。动态实体视图可以省略以使用默认模板。静态实体视图必须提供 descriptor.source

lookupComponentId

string

动态列表视图查找组件 ID。默认为 dataGrid。静态实体视图不支持此字段。

editedEntityContainerId

string

动态详情视图被编辑实体容器 ID。默认为 entityDc。静态实体视图不支持此字段。

动态实体视图

规则:

  • type 必须为 listdetail

  • viewId 必须显式设置且必须唯一。

  • 如果省略 viewRoute,则通过将 viewId 小写并将非字母数字序列替换为 - 来生成。

  • 详情路由自动添加 /:id;因此 viewRoute 本身不能以 /:id 结尾。

  • 第一个声明的列表视图成为动态实体的主列表视图。第一个声明的详情视图成为主详情视图。

  • descriptor 可以省略、使用 template: "default"、使用自定义模板资源路径或提供字面 source

  • 如果使用 descriptor.source,则内容必须是有效的 XML,根元素为 <view xmlns="http://jmix.io/schema/flowui/view">

  • 显式列表视图的 XML 必须包含查找组件 ID,默认为 dataGrid

  • 显式详情视图的 XML 必须包含被编辑实体容器 ID,默认为 entityDc

默认模板为:

  • io/jmix/flowui/view/template/list-view.ftl 用于列表视图;

  • io/jmix/flowui/view/template/detail-template.ftl 用于详情视图。

templateParams 是传递给 XML 模板渲染的 YAML 对象。动态模型组件没有为其定义固定结构;支持的键值取决于所选模板。例如,模板可以使用字符串列表的属性过滤器:

templateParams:
  includeProperties: ["name", "discount"]
  excludeProperties: ["publicSummary"]

静态实体视图覆盖

静态实体覆盖已注册视图的 XML:

- viewId: "Customer.list"
  descriptor:
    source: |
      <?xml version="1.0" encoding="UTF-8" standalone="no"?>
      <view xmlns="http://jmix.io/schema/flowui/view"
            extends="com/company/sample/view/customer/customer-list-view.xml">
          <layout>
              <dataGrid id="customersDataGrid">
                  <columns>
                      <column property="taxId"/>
                  </columns>
              </dataGrid>
          </layout>
      </view>

规则:

  • viewId 是必填的,且必须使用已注册的静态视图 ID。

  • type 可以省略;从控制器类推断。

  • 仅支持 descriptor.source

  • 不支持 descriptor.templateviewRouteviewTitletemplateParamsresourceRolesmenuItemlookupComponentIdeditedEntityContainerId

  • 生成的控制器继承当前注册的控制器并保留其路由。

XML 描述

descriptor 必须使用以下配置之一:

descriptor:
  template: "default"

或:

descriptor:
  source: |
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <view xmlns="http://jmix.io/schema/flowui/view"
          extends="com/company/sample/view/customer/customer-list-view.xml">
        <layout>
            <dataGrid id="customersDataGrid">
                <columns>
                    <column property="taxId"/>
                </columns>
            </dataGrid>
        </layout>
    </view>

menuItem 字段:

字段 类型 必填 说明

parentMenu

string

已有的或新的父菜单 ID。如果未找到,则使用此 ID 创建根菜单。

insertBefore

string

如果找到同级菜单 ID,则插入到其前面;否则追加到末尾。

title

本地化值

省略时默认为视图标题。

resourceRoles

list

可以访问该菜单项的角色代码。

详情视图菜单项接收路由参数 id=new