Как использовать Mon go Auditing и UUID в качестве идентификатора в Spring Boot 2.2.x? - PullRequest
2 голосов
/ 09 января 2020

Я бы хотел, чтобы Документы хранились с идентификатором UUID и полями createAt / updatedAt. Мое решение работало с Spring Boot 2.1.x. После того, как я обновил Spring Boot 2.1.11.RELEASE до 2.2.0.RELEASE, мой тест для MongoAuditing не прошел с createdAt = null. Что мне нужно сделать, чтобы снова заполнить поле createAt?

Это не просто проблема тестирования. Я запустил приложение, и оно работает так же, как и мой тест. Все поля аудита остаются нулевыми.

У меня есть Конфигурация для включения 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());
        }
    }
}

Сам документ (я отбросил геттер и сеттеры):

@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 не проходит.

Ответы [ 2 ]

1 голос
/ 17 марта 2020

Для меня лучшим решением было переключиться с генерации 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();
  }
}
1 голос
/ 10 января 2020

MongoTemplate работает следующим образом на doInsert()

  • this.maybeEmitEvent - генерирует событие (onBeforeConvert, onBeforeSave и т. Д.), Поэтому любой AbstractMappingEventListener может поймать и действовать так же, как вы сделали с GenerateUUIDListener
  • this.maybeCallBeforeConvert - вызов до преобразования обратные вызовы как mongo auditing

как у вас можно видеть в исходном коде MongoTemplate.class sr c (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 отмечает createdAt только для новых объектов, проверяя, если entity.isNew() == true

поскольку ваш код (UUID) уже установил Id, createdAt не заполняется (сущность не считается новой)

, вы можете сделать следующее (от лучшего к худшему):

  • забудьте о UUID и используйте String для своего идентификатора, пусть mon go сам создает и управляет идентификаторами своих сущностей (вот как MongoTemplate на самом деле работает строки 811-812)
  • сохранить UUID на уровне кода, преобразовать из / в String при вставке и извлечении из базы данных
  • создать собственный репозиторий, как в этом post
  • остаться с * 1 051 *
  • установить updateAt на GenerateUUIDListener, а также id (переименовать его NewEntityListener или что-л.), В основном реализовать аудит
  • внедрить новый isNew() logi c, который не зависит только от сущности id

в версии 2.1.11.RELEASE порядок методов был изменен (MongoTemplate.class 804 -805) чтобы ваш код работал нормально

в качестве абстрактного подхода, характер события должен быть своего рода отправкой и забыванием (совместимым с asyn c), так что это очень плохая практика для изменения самого объекта существует NO грантополучатель для порядка вычисления, если таковой имеется

, поэтому аудит основывается на обратных вызовах , а не событиях , и именно поэтому Pivotal не (должен) поддерживать порядок между версиями

...