实体日志
实体日志是一种监控系统内 JPA 实体变更的机制。它记录实体属性的改动并提供用户视图用于查找和展示变更的信息:
-
修改了什么实体实例。
-
属性变更前后的旧值和新值。
-
修改实体的时间。
-
修改实体的用户。
变更注册
如果 JPA 实体是通过 DataManager 或 EntityManager 保存,实体日志会自动监控实体的变更。但使用原生 SQL 时,实体日志不会起作用。
另一中方法是使用 EntityLog
bean 在应用程序代码中注册变更的实体,此时,需要调用 registerCreate()
、registerModify()
和 registerDelete()
方法并设置 auto
参数为 false
。当框架自动调用实体日志时,该参数设置为 true。
配置实体日志
为了在运行时使用管理界面,用户必须具有该扩展组件提供的 entity-log 资源角色。
|
可以在应用程序的 Audit → Entity Log 视图中配置实体日志。切换至 Setup tab:
点击 Create 按钮开始配置实体日志。
从 Name 下拉框中选择实体,并选择需要审计的属性。
Auto 复选框配置当使用 auto
= true
参数调用 EntityLog
时(即,由实体监听器调用时),系统是否需要记录变更。
Manual 复选框配置当使用 auto
= false
参数调用 EntityLog
时,系统是否需要记录变更。
Export 和 Import 操作支持导入或导出 JSON、ZIP 格式的配置。
另外,如果需要在数据库初始化脚本中配置实体日志,则可以用插入数据库记录的方式进行配置。
实体日志的配置通过 LoggedEntity
和 LoggedAttribute
实体完成,对应数据库的 AUDIT_LOGGED_ENTITY
和 AUDIT_LOGGED_ATTR
表。
LoggedEntity
定义需要记录日志的实体类型。
LoggedAttribute
定义需要记录的实体属性,带有属性名,并包含至 LoggedEntity
的引用。
如需为特定实体配置日志,需要在 AUDIT_LOGGED_ENTITY
和 AUDIT_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 即可查看实体日志的内容。可以在过滤器中设置必要的条件查找日志记录。
另外,也可以从任何应用程序视图访问特定实体的日志。
日志记录保存在 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 处理器内,为数据加载器设置参数,并加载数据。 |