Пользователь хочет отредактировать ассоциацию Bbb
объекта Aaa
, то есть связать другой объект Bbb
с рассматриваемым объектом Aaa
. Вы хотели бы реализовать какой-либо контроль версий и сохранить копию объекта Aaa
в состоянии, в котором он до изменения применяется.
I предложил бы следующие решения для решения этой проблемы:
Обработка событий REST Spring Data
Использование Функциональность событий REST Spring Data и ...
Расширение AbstractRepositoryEventListener
... реализовать класс, расширяющий AbstractRepositoryEventListener
, содержащий метод, переопределяющий метод onBeforeLinkSave(...)
.
@Component
public class AaaRepositoryListener extends AbstractRepositoryEventListener<Aaa> {
@Override
protected void onBeforeLinkSave(Aaa parent, Object linked) {
// Handle event, remember to detach the entity using the entity manager if necessary and checking the type of the linked object.
}
}
Аннотирование с помощью @RepositoryEventHandler
... реализовать класс, помеченный @RepositoryEventHandler
, содержащий метод, который обрабатывает BeforeLinkSaveEvent
.
@Component
@RepositoryEventHandler
public class AaaEventHandler {
@PersistenceContext
private EntityManager entityManager;
@HandleBeforeLinkSave
public void handleAaaToBbbSave(Aaa aaa, Bbb bbb) {
// Mind that this only handles changes on Aaa objects
// that affect Bbb links and only takes a single argument.
// As soon as Aaa contains links to other classes, this method
// no longer works.
//
// Copy Aaa object and store it in the repository.
}
}
Заметки о вышеуказанных методах
Пожалуйста, помните, что объект, полученный в методе handleAaaToBbbSave(...)
, может быть прикреплен, и вам может потребоваться отсоединить его (EntityManager.detach(...)
) перед сбросом идентификатора и повторным сохранением.
Кроме того, из-за ошибки в Spring Data REST вам необходимо добавить этот компонент в ваше приложение Таким образом, события на самом деле обрабатываются.
@Configuration
public class BugFixForSpringDATAREST524 implements InitializingBean {
private ValidatingRepositoryEventListener eventListener;
private Map<String, Validator> validators;
@Autowired
public BugFixForSpringDATAREST524(ValidatingRepositoryEventListener eventListener,
Map<String, Validator> validators) {
this.eventListener = eventListener;
this.validators = validators;
}
@Override
public void afterPropertiesSet() {
List<String> events = Arrays.asList("beforeCreate",
"afterCreate",
"beforeSave",
"afterSave",
"beforeLinkSave",
"afterLinkSave",
"beforeDelete",
"afterDelete");
for (Map.Entry<String, Validator> entry : validators.entrySet()) {
events.stream()
.filter(p -> entry.getKey().startsWith(p))
.findFirst()
.ifPresent(p -> eventListener.addValidator(p, entry.getValue()));
}
}
}
Обратите внимание, что события запускаются, только если Spring Data REST действительно используется. Если в репозитории используется метод save(...)
, событие не инициируется, и копия затронутого объекта Aaa
не сохраняется.
Spring AOP (Аспектно-ориентированное программирование)
Если вы хотите поддержать метод save(...)
хранилища, я рекомендую использовать Spring AOP для создания @Before
или @Around
совета (зависит от ваших потребностей) для перехвата вызова на метод хранилища. Вот базовые c строительные леса такого компонента:
@Aspect
@Component
public class AaaRepositoryAspect {
@Pointcut(value = "execution(* com.example.backend.repository.aaa.AaaRepository.save()) && args(aaa)")
private void repositorySave(Aaa aaa) {
}
@Before(value = "repositorySave(aaa)")
private void beforeSave(Aaa aaa) throws Throwable {
// Save a copy of the object.
}
}
Обоснование
До Почему Я рекомендую вышеуказанные методы вместо один из ваших методов:
Вам потребуется создать контроллер, который переопределит метод, представленный Spring Data REST. Кроме того, вам нужно обработать возвращаемые значения и (если вы, например, используете Spring HATEOAS) собрать ресурсы самостоятельно. Кроме того, это относится только к вызовам к конечной точке, а не к внутренним вызовам метода save(...)
хранилища.
Опять же, вам нужно написать много кода, который вы на самом деле делаете не нужно.
Это создает зависимость между вашей моделью и вашими репозиториями, потому что вам нужен экземпляр репозитория в вашем классе модели.
Использование обработчика событий, предоставляемого Spring Data REST, сохраняет код, который вы используете для управления версиями, близко к хранилищу и в Spring Data REST. Использование аспекта аналогично, это просто более абстрактная версия обработчика событий (без учета фактической реализации).