以前通过@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上面
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(); } 最后的一些话