实体日志

实体日志是一种监控系统内 JPA 实体变更的机制。它记录实体属性的改动并提供用户视图用于查找和展示变更的信息:

  • 修改了什么实体实例。

  • 属性变更前后的旧值和新值。

  • 修改实体的时间。

  • 修改实体的用户。

变更注册

如果 JPA 实体是通过 DataManagerEntityManager 保存,实体日志会自动监控实体的变更。但使用原生 SQL 时,实体日志不会起作用。

另一中方法是使用 EntityLog bean 在应用程序代码中注册变更的实体,此时,需要调用 registerCreate()registerModify()registerDelete() 方法并设置 auto 参数为 false。当框架自动调用实体日志时,该参数设置为 true。

配置实体日志

为了在运行时使用管理界面,用户必须具有该扩展组件提供的 entity-log 资源角色。

可以在应用程序的 Audit → Entity Log 视图中配置实体日志。切换至 Setup tab:

entity log set

点击 Create 按钮开始配置实体日志。

Name 下拉框中选择实体,并选择需要审计的属性。

Auto 复选框配置当使用 auto = true 参数调用 EntityLog 时(即,由实体监听器调用时),系统是否需要记录变更。

Manual 复选框配置当使用 auto = false 参数调用 EntityLog 时,系统是否需要记录变更。

ExportImport 操作支持导入或导出 JSON、ZIP 格式的配置。

另外,如果需要在数据库初始化脚本中配置实体日志,则可以用插入数据库记录的方式进行配置。

实体日志的配置通过 LoggedEntityLoggedAttribute 实体完成,对应数据库的 AUDIT_LOGGED_ENTITYAUDIT_LOGGED_ATTR 表。

LoggedEntity 定义需要记录日志的实体类型。

LoggedAttribute 定义需要记录的实体属性,带有属性名,并包含至 LoggedEntity 的引用。

如需为特定实体配置日志,需要在 AUDIT_LOGGED_ENTITYAUDIT_LOGGED_ATTR 表添加相应的记录。

例如,下面的示例中,在数据库初始化时,完成了对 Customer 实体 phone 属性的变更记录的配置:

<changeSet id="1" author="audit">
    <insert tableName="AUDIT_LOGGED_ENTITY">
        <column name="ID" value="0a6ba81c-a8b9-bc8f-3829-53a6cef48871"/>
        <column name="CREATED_BY" value="admin"/>
        <column name="CREATE_TS" valueDate="2024-02-21T14:57:25.339"/>
        <column name="NAME" value="Customer"/>
        <column name="AUTO" value="true"/>
        <column name="MANUAL" value="true"/>
    </insert>
</changeSet>
<changeSet id="2" author="audit">
    <insert tableName="AUDIT_LOGGED_ATTR">
        <column name="ID" value="8e6e9825-1381-5299-e704-eadf1b96996e"/>
        <column name="CREATE_TS" valueDate="2024-02-21T14:57:25.339"/>
        <column name="CREATED_BY" value="admin"/>
        <column name="ENTITY_ID" value="0a6ba81c-a8b9-bc8f-3829-53a6cef48871"/>
        <column name="NAME" value="phone"/>
    </insert>
</changeSet>

查看实体日志

打开 Audit → Entity Log 视图的 View tab 即可查看实体日志的内容。可以在过滤器中设置必要的条件查找日志记录。

entity log view

另外,也可以从任何应用程序视图访问特定实体的日志。

日志记录保存在 AUDIT_ENTITY_LOG 表,对应 EntityLogItem 实体。修改的属性值保存在 CHANGES 列,Java 中转换成 EntityLogAttr 实体实例。

在下面的示例中,Order 实体的详情视图展示实体日志内容的列表。

这是视图 XML 的部分内容:

<data>
    <instance id="orderDc"
              class="com.company.demo.entity.Order">
        <fetchPlan extends="_base"/>
        <loader/>
    </instance>
    <collection id="entityLogItemsDc"
                class="io.jmix.audit.entity.EntityLogItem"> (1)
        <fetchPlan extends="_local"/>
        <loader id="entityLogItemsDl" readOnly="true">
            <query>
                <![CDATA[select e from audit_EntityLog e
                where e.entityRef.entityId = :entityOrder]]>
            </query>
        </loader>
        <collection id="entityLogAttrDc" property="attributes"/> (2)
    </collection>
</data>
<facets>
    <dataLoadCoordinator auto="true"/>
</facets>
<actions>
    <action id="saveAction" type="detail_saveClose"/>
    <action id="closeAction" type="detail_close"/>
</actions>
<layout>
    <formLayout id="form" dataContainer="orderDc">
        <datePicker id="dateField" property="date"/>
        <textField id="productField" property="product"/>
        <textField id="amountField" property="amount"/>
        <textField id="priceField" property="price"/>
    </formLayout>
    <formLayout>
        <dataGrid id="entityLogItemsDataGrid"
                  dataContainer="entityLogItemsDc"> (3)
            <columns>
                <column property="eventTs"/>
                <column property="username"/>
                <column property="type"/>
            </columns>
        </dataGrid>
        <dataGrid id="entityLogAttrsDataGrid"
                  dataContainer="entityLogAttrDc"> (4)
            <columns>
                <column property="name"/>
                <column property="oldValue"/>
                <column property="value"/>
            </columns>
        </dataGrid>
    </formLayout>
    <hbox id="detailActions">
        <button id="saveAndCloseBtn" action="saveAction"/>
        <button id="closeBtn" action="closeAction"/>
    </hbox>
</layout>
1 加载 EntityLogItem 集合至 entityLogItemsDc 数据容器。
2 加载相关的 EntityLogAttr 示例至 entityLogAttrDc 数据容器。
3 连接至 entityLogItemsDc 容器的数据网格。
4 连接至 entityLogAttrDc 容器的数据网格。

Order 视图控制器代码如下:

@ViewComponent
private CollectionLoader<EntityLogItem> entityLogItemsDl;

@Subscribe(id = "orderDc", target = Target.DATA_CONTAINER)
public void onOrderDcItemChange(final InstanceContainer.ItemChangeEvent<Order> event) { (1)
    entityLogItemsDl.setParameter("entityOrder",event.getItem().getId());
    entityLogItemsDl.load();
}
1 orderDc 数据容器的 ItemChangeEvent 处理器内,为数据加载器设置参数,并加载数据。