问题出现

以前通过@EnableMongoAuditing、@CreateDate、@LastModifiedDate进行实体类创建时间、修改时间的自动管理。

但为了实现多数据源的管理以及切换,自己覆盖了mongoTemplate的bean,发现应用所有数据库操作都出现"Couldn't find PersistentEntity"错误,去掉@EnableMongoAuditing注解后才能正常使用,但@CreateDate、@LastModifiedDate失效,创建时间、修改时间这些都要自己去设置,太麻烦了也容易漏,为了方便使用以及偷懒,需要实现所有数据库存储更新操作能自动插入、更新公用字段,如创建时间、修改时间、创建者、修改者信息

解决的思路

为了实现这个功能,翻了下MongoTemplate的源码,下面是关键的几个方法

MongoTemplate.class

    public <T> T save(T objectToSave, String collectionName) {
Assert.notNull(objectToSave, "Object to save must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty!");
AdaptibleEntity<T> source = this.operations.forEntity(objectToSave, this.mongoConverter.getConversionService());
return source.isVersionedEntity() ? this.doSaveVersioned(source, collectionName) : this.doSave(collectionName, objectToSave, this.mongoConverter);
} protected <T> T doSave(String collectionName, T objectToSave, MongoWriter<T> writer) {
objectToSave = ((BeforeConvertEvent)this.maybeEmitEvent(new BeforeConvertEvent(objectToSave, collectionName))).getSource();
objectToSave = this.maybeCallBeforeConvert(objectToSave, collectionName);
AdaptibleEntity<T> entity = this.operations.forEntity(objectToSave, this.mongoConverter.getConversionService());
entity.assertUpdateableIdIfNotSet();
MappedDocument mapped = entity.toMappedDocument(writer);
Document dbDoc = mapped.getDocument();
this.maybeEmitEvent(new BeforeSaveEvent(objectToSave, dbDoc, collectionName));
objectToSave = this.maybeCallBeforeSave(objectToSave, dbDoc, collectionName);
Object id = this.saveDocument(collectionName, dbDoc, objectToSave.getClass());
T saved = this.populateIdIfNecessary(objectToSave, id);
this.maybeEmitEvent(new AfterSaveEvent(saved, dbDoc, collectionName));
return this.maybeCallAfterSave(saved, dbDoc, collectionName);
} protected <T> T maybeCallBeforeConvert(T object, String collection) {
return this.entityCallbacks != null ? this.entityCallbacks.callback(BeforeConvertCallback.class, object, new Object[]{collection}) : object;
} protected <T> T maybeCallBeforeSave(T object, Document document, String collection) {
return this.entityCallbacks != null ? this.entityCallbacks.callback(BeforeSaveCallback.class, object, new Object[]{document, collection}) : object;
}

查看MongoTemplate的源码会发现,新增以及更新操作调用的save方法,在执行前会有BeforeConvertEvent、BeforeSaveEvent两个事件,我们只需要在这两个事件里面将我们需要保存的内容做下处理,就可以实现所有数据库新增、更新操作都自动加上创建时间这些信息,而且原来MongoAudit只有几个固定的字段能用,自定义BeforeConvertCallback事件后,完全可以按自己的需要多管理几个字段。

具体要实现一个接口,并且将自定义的callback处理set到要用的mongTemplate上面

@FunctionalInterface
public interface BeforeConvertCallback<T> extends EntityCallback<T> {
T onBeforeConvert(T var1, String var2);
}

具体实现

BeforeConvertEvent事件自定义处理

class BeforeConvert implements BeforeConvertCallback<Object> {

        @NotNull
@Override
public Object onBeforeConvert(Object o, String s) {
log.info("before convert callback"); Map<String, Field> fieldMap = ReflectUtil.getFieldMap(o.getClass());
String userName = SecurityUtils.getUsername();
Date now = new Date(); if (fieldMap.containsKey("id")) {
Field id = fieldMap.get("id"); if (id == null || StringUtils.isBlank((String) ReflectUtil.getFieldValue(o, id))) {
//没有id时为新增
//创建时间
if (fieldMap.containsKey("createTime")) {
ReflectUtil.setFieldValue(o, "createTime", now);
}
//创建者
if (fieldMap.containsKey("createUser") && StringUtils.isNotBlank(userName)) {
ReflectUtil.setFieldValue(o, "createUser", userName);
}
}
}
//更新日期
if (fieldMap.containsKey("updateTime")) {
ReflectUtil.setFieldValue(o, "updateTime", now);
}
//更新者
if (fieldMap.containsKey("updateUser") && StringUtils.isNotBlank(userName)) {
ReflectUtil.setFieldValue(o, "updateUser", userName);
}
//这里还可以加上其他各种需要设置的值 return o;
}
}
    @Bean(name = "mongoTemplate")
public DynamicMongoTemplate dynamicMongoTemplate() {
Iterator<SimpleMongoClientDatabaseFactory> iterator = MONGO_CLIENT_DB_FACTORY_MAP.values().iterator();
DynamicMongoTemplate mongoTemplate = new DynamicMongoTemplate(iterator.next());
//将自定义事件处理放进mongoTemplate中
mongoTemplate.setEntityCallbacks(EntityCallbacks.create(new BeforeConvert()));
return mongoTemplate;
}
@Bean(name = "mongoDbFactory")
public MongoDatabaseFactory mongoDbFactory() {
Iterator<SimpleMongoClientDatabaseFactory> iterator = MONGO_CLIENT_DB_FACTORY_MAP.values().iterator();
return iterator.next();
}

最后的一些话

一开始我自定义BeforeSaveCallback,在里面修改了object的内容,但发现并没有保存在数据库中。在官方的文档中说,在这事件里面修改object内容只是临时的不会做持久化,需要修改转换后document的内容才会保存进数据库,官方原话:Entity callback method invoked before a domain object is saved. Can return either the same or a modified instance of the domain object and can modify Document contents. This method is called after converting the entity to a Document so effectively the document is used as outcome of invoking this callback. Changes to the domain object are not taken into account for saving, only changes to the document. Only transient fields of the entity should be changed in this callback. To change persistent the entity before being converted, use the BeforeConvertCallback.

官方文档

为了避免实体转document后字段名发生改变不好找,就选用了BeforeConvertEvent,在转换前进行了处理,但其实在BeforeSaveEvent处理也是可以的

事件的发生顺序

Event:
BeforeDeleteEvent AfterDeleteEvent BeforeConvertEvent BeforeSaveEvent AfterSaveEvent AfterLoadEvent

最新文章

  1. python爬虫学习(5) —— 扒一下codeforces题面
  2. spring mvc 请求转发和重定向(转)
  3. XHTML标签的嵌套规则分析
  4. .NET EXCEL NPOI 图片
  5. VS2008中调试dll
  6. mac os下获得root权限
  7. HBase学习笔记-高级(一)
  8. Mysql的主从数据库没有同步的解决办法
  9. 【BZOJ】【2819】NIM
  10. android可拖动排序GridView实现
  11. SqlHelp
  12. tornado学习 - TCPClient 实现聊天功能
  13. jQuery选择器分类
  14. 版本控制工具--svn和git的使用(一) -----版本控制的好处以及分类
  15. 代码,java_web
  16. 软件开发者路线图梗概&amp;书摘chapter7
  17. LeetCode 24. Swap Nodes in Pairs 成对交换节点 C++/Java
  18. iic 之24C256存储器 及PCF8563
  19. Confluence 6 匿名访问远程 API
  20. Could not load file or assembly &#39;System.Web.Mvc, Version=5.2.3.0...

热门文章

  1. XML从入门到深入(超详细)
  2. GitHub Desktop的使用,创建项目、上传文件,设置忽略文件
  3. 使用远程Docker进行集成测试
  4. 7.6、openstack网络拓扑
  5. SpringBoot Cache 入门
  6. 痞子衡嵌入式:对比i.MXRT与LPC在RTC外设GPREG寄存器使用上的异同
  7. phpstorm之&quot;Can not run PHP Code Sniffer&quot;
  8. php安裝7.3版本
  9. 全网唯一开源java开发的支持高扩展,高性能的Mqtt集群broker!
  10. Java+Selenium3.3.1环境搭建