Один из подходов - реализовать вашу бизнес-логику с помощью настраиваемого контроллера и службы. Но этот способ нейтрализует «преимущества» Spring Data REST.
Другой вариант (на мой взгляд, это более естественно для SDR) - использовать опубликованные события из совокупных корней . В этом случае вы должны расширить свои сущности с AbstractAggregateRoot и реализовать метод, который будет публиковать некоторые «события». Затем вы сможете обработать это событие (с помощью @EventListener
) в той же транзакции в процессе сохранения вашей сущности. Например:
@Entity
public class Order extends AbstractAggregateRoot {
//...
public void registerItems(List<Item> items) {
this.registerEvent(new RegisterItemsEvent(this, items));
}
}
@Getter
@RequiredArgsConstructor
public class RegisterItemsEvent {
private final Order order;
private final List<Item> items;
}
@RequiredArgsConstructor
@Component
public class EventHandler {
private final ItemRepo itemRepo;
@EventListener
@Transactional(propagation = MANDATORY)
public void handleRegisterItemsEvent(RegisterItemsEvent e) {
Order order = e.getOrder();
List<Item> items = e.getItems();
// update items with order - skipped...
itemRepo.saveAll(items);
}
}
Пример использования:
@Component
@RepositoryEventHandler
public class OrderEventHandler {
@BeforeCreate
public void handleOrderCreate(Order order) {
// prepare a List of items - skipped...
order.registerItems(items);
}
}
Когда SDR сохраняет Order
, тогда он генерирует RegisterItemsEvent
, который обрабатывается handleRegisterItemsEvent
методом вашего EventHandler
, который сохраняет подготовленные элементы в той же транзакции (мы используем параметр propagation = MANDATORY
аннотации @Transaction
чтобы убедиться, что транзакция присутствует).
Дополнительная информация: Публикация событий домена из совокупных корней
ОБНОВЛЕНО
Что касается вашей конкретной задачи, вы можете создать класс ItemChangedEvent
:
@Getter
@RequiredArgsConstructor
public class ItemChangedEvent {
private final Item item;
}
Реализация метода markAsChanged
в Item
сущности:
@Entity
public class Item extends AbstractAggregateRoot {
//...
public void markAsChanged() {
this.registerEvent(new ItemChangedEvent(this));
}
}
Когда item
изменяется, вы помечаете его как «измененный»:
@Component
@RepositoryEventHandler
public class ItemRepositoryEventHandler {
@BeforeCreate
@BeforeSave
@BeforeDelete
public void itemChanged(Item item) {
item.markAsChanged();
}
}
И записать его в файл в обработчике ItemChangedEvent
в той же транзакции:
@Component
public class EventHandler {
@EventListener
@Transactional(propagation = MANDATORY)
public void handleItemChangedEvent(ItemChangedEvent e) {
Item item = e.getItem();
writeToFile(item);
}
}