如何使用 Mongo 审计和 UUID 作为 id 与 Spring Boot 2.2.x?
How to use Mongo Auditing and a UUID as id with Spring Boot 2.2.x?
我希望使用 UUID id 和 createdAt / updatedAt 字段存储文档。我的解决方案是使用 Spring Boot 2.1.x。在我从 Spring Boot 2.1.11.RELEASE 升级到 2.2.0.RELEASE 之后,我对 MongoAuditing 的测试失败了 createdAt = null
。我需要做什么才能再次填充 createdAt 字段?
这不仅仅是一个测试问题。我 运行 应用程序,它与我的测试具有相同的行为。所有审核字段保持为空。
我有一个启用 MongoAuditing 和 UUID 生成的配置:
@Configuration
@EnableMongoAuditing
public class MongoConfiguration {
@Bean
public GenerateUUIDListener generateUUIDListener() {
return new GenerateUUIDListener();
}
}
侦听器挂接到 onBeforeConvert
- 我想这就是麻烦开始的地方。
public class GenerateUUIDListener extends AbstractMongoEventListener<IdentifiableEntity> {
@Override
public void onBeforeConvert(BeforeConvertEvent<IdentifiableEntity> event) {
IdentifiableEntity entity = event.getSource();
if (entity.isNew()) {
entity.setId(UUID.randomUUID());
}
}
}
文档本身(我删除了 getter 和 setter):
@Document
public class MyDocument extends InsertableEntity {
private String name;
}
public abstract class InsertableEntity extends IdentifiableEntity {
@CreatedDate
@JsonIgnore
private Instant createdAt;
}
public abstract class IdentifiableEntity implements Persistable<UUID> {
@Id
private UUID id;
@JsonIgnore
public boolean isNew() {
return getId() == null;
}
}
可以在此处找到完整的最小示例(包括测试)https://github.com/mab/auditable
使用 2.1.11.RELEASE 测试成功,使用 2.2.0.RELEASE 失败。
MongoTemplate
在 doInsert()
上按以下方式工作
this.maybeEmitEvent
- 发出一个 事件 (onBeforeConvert
、onBeforeSave
等),因此任何 AbstractMappingEventListener
都可以捕获并采取行动就像你对 GenerateUUIDListener
所做的一样
this.maybeCallBeforeConvert
- 在转换前调用 回调 像 mongo auditing
就像你在 MongoTemplate.class
src (831-832) 的源代码中看到的那样
protected <T> T doInsert(String collectionName, T objectToSave, MongoWriter<T> writer) {
BeforeConvertEvent<T> event = new BeforeConvertEvent(objectToSave, collectionName);
T toConvert = ((BeforeConvertEvent)this.maybeEmitEvent(event)).getSource(); //emit event
toConvert = this.maybeCallBeforeConvert(toConvert, collectionName); //call some before convert handlers
...
}
MongoAudit
通过检查 entity.isNew() == true
是否仅对新实体标记 createdAt
因为您的代码 (UUID) 已经设置了 Id
createdAt
未填充(该实体不被视为新实体)
您可以执行以下操作(按最佳到最差排序):
- 忘掉
UUID
并使用 String
作为您的 ID,让 mongo 自己创建和管理它的实体 ID(这就是 MongoTemplate
的实际工作方式,第 811 行-812)
- 在代码级别保留
UUID
,在从 db 插入和检索时转换 from/to String
- 像这样创建自定义存储库 post
- 留在
2.1.11.RELEASE
- 通过
GenerateUUIDListener
和id
设置updateAt
(重命名为NewEntityListener
或smth),基本上实现审计
- 实现一个 new
isNew()
逻辑,它不仅仅依赖于实体 id
in version 2.1.11.RELEASE
the order of the methods was flipped (MongoTemplate.class
804-805) so your code worked fine
作为一种抽象方法,事件的本质是发送后忘记(异步兼容),因此更改对象本身是一种非常糟糕的做法,NO计算顺序的受让人,如果有的话
这就是审计基于 回调 而不是 事件 的原因,这也是 Pivotal 不(需要)保持秩序的原因版本之间
对我来说,最好的解决方案是从事件 UUID 生成切换到基于回调的生成。通过 Ordered
的实现,我们可以将新回调设置为在 AuditingEntityCallback
.
之后执行
public class IdEntityCallback implements BeforeConvertCallback<IdentifiableEntity>, Ordered {
@Override
public IdentifiableEntity onBeforeConvert(IdentifiableEntity entity, String collection) {
if (entity.isNew()) {
entity.setId(UUID.randomUUID());
}
return entity;
}
@Override
public int getOrder() {
return 101;
}
}
我用 MongoConfiguration
注册了回调。对于更通用的解决方案,您可能需要查看 AuditingEntityCallback
与 `MongoAuditingBeanDefinitionParser.
的注册
@Configuration
@EnableMongoAuditing
public class MongoConfiguration {
@Bean
public IdEntityCallback registerCallback() {
return new IdEntityCallback();
}
}
我希望使用 UUID id 和 createdAt / updatedAt 字段存储文档。我的解决方案是使用 Spring Boot 2.1.x。在我从 Spring Boot 2.1.11.RELEASE 升级到 2.2.0.RELEASE 之后,我对 MongoAuditing 的测试失败了 createdAt = null
。我需要做什么才能再次填充 createdAt 字段?
这不仅仅是一个测试问题。我 运行 应用程序,它与我的测试具有相同的行为。所有审核字段保持为空。
我有一个启用 MongoAuditing 和 UUID 生成的配置:
@Configuration
@EnableMongoAuditing
public class MongoConfiguration {
@Bean
public GenerateUUIDListener generateUUIDListener() {
return new GenerateUUIDListener();
}
}
侦听器挂接到 onBeforeConvert
- 我想这就是麻烦开始的地方。
public class GenerateUUIDListener extends AbstractMongoEventListener<IdentifiableEntity> {
@Override
public void onBeforeConvert(BeforeConvertEvent<IdentifiableEntity> event) {
IdentifiableEntity entity = event.getSource();
if (entity.isNew()) {
entity.setId(UUID.randomUUID());
}
}
}
文档本身(我删除了 getter 和 setter):
@Document
public class MyDocument extends InsertableEntity {
private String name;
}
public abstract class InsertableEntity extends IdentifiableEntity {
@CreatedDate
@JsonIgnore
private Instant createdAt;
}
public abstract class IdentifiableEntity implements Persistable<UUID> {
@Id
private UUID id;
@JsonIgnore
public boolean isNew() {
return getId() == null;
}
}
可以在此处找到完整的最小示例(包括测试)https://github.com/mab/auditable 使用 2.1.11.RELEASE 测试成功,使用 2.2.0.RELEASE 失败。
MongoTemplate
在 doInsert()
this.maybeEmitEvent
- 发出一个 事件 (onBeforeConvert
、onBeforeSave
等),因此任何AbstractMappingEventListener
都可以捕获并采取行动就像你对GenerateUUIDListener
所做的一样
this.maybeCallBeforeConvert
- 在转换前调用 回调 像mongo auditing
就像你在 MongoTemplate.class
src (831-832) 的源代码中看到的那样
protected <T> T doInsert(String collectionName, T objectToSave, MongoWriter<T> writer) {
BeforeConvertEvent<T> event = new BeforeConvertEvent(objectToSave, collectionName);
T toConvert = ((BeforeConvertEvent)this.maybeEmitEvent(event)).getSource(); //emit event
toConvert = this.maybeCallBeforeConvert(toConvert, collectionName); //call some before convert handlers
...
}
MongoAudit
通过检查 entity.isNew() == true
createdAt
因为您的代码 (UUID) 已经设置了 Id
createdAt
未填充(该实体不被视为新实体)
您可以执行以下操作(按最佳到最差排序):
- 忘掉
UUID
并使用String
作为您的 ID,让 mongo 自己创建和管理它的实体 ID(这就是MongoTemplate
的实际工作方式,第 811 行-812) - 在代码级别保留
UUID
,在从 db 插入和检索时转换 from/to - 像这样创建自定义存储库 post
- 留在
2.1.11.RELEASE
- 通过
GenerateUUIDListener
和id
设置updateAt
(重命名为NewEntityListener
或smth),基本上实现审计 - 实现一个 new
isNew()
逻辑,它不仅仅依赖于实体id
String
in version
2.1.11.RELEASE
the order of the methods was flipped (MongoTemplate.class
804-805) so your code worked fine
作为一种抽象方法,事件的本质是发送后忘记(异步兼容),因此更改对象本身是一种非常糟糕的做法,NO计算顺序的受让人,如果有的话
这就是审计基于 回调 而不是 事件 的原因,这也是 Pivotal 不(需要)保持秩序的原因版本之间
对我来说,最好的解决方案是从事件 UUID 生成切换到基于回调的生成。通过 Ordered
的实现,我们可以将新回调设置为在 AuditingEntityCallback
.
public class IdEntityCallback implements BeforeConvertCallback<IdentifiableEntity>, Ordered {
@Override
public IdentifiableEntity onBeforeConvert(IdentifiableEntity entity, String collection) {
if (entity.isNew()) {
entity.setId(UUID.randomUUID());
}
return entity;
}
@Override
public int getOrder() {
return 101;
}
}
我用 MongoConfiguration
注册了回调。对于更通用的解决方案,您可能需要查看 AuditingEntityCallback
与 `MongoAuditingBeanDefinitionParser.
@Configuration
@EnableMongoAuditing
public class MongoConfiguration {
@Bean
public IdEntityCallback registerCallback() {
return new IdEntityCallback();
}
}