Spring и обработка событий в Hibernate

от автора

Как-то обделена на хабре такая тема, как обработка событий при работе с сущностями с использованием Hibernate — я смог найти только один пост уже почти мохнатого года. Но то аудит, а нам нужна возможность автоматизировать работу с некоторыми атрибутами сущностей и при этом упростить процедуру работы с ними.

Для начала создадим демонстрационный стенд с двумя сущностями User и AnObject, а так же DAO-слоем для них.

Код

Здесь и далее привожу только значимые куски кода — в полной версии можно посмотреть на github

@Entity @Table(name = "user") public class User {         @Id         @GeneratedValue         private long id;         @Basic         @Column(name = "username", updatable = false, unique = true, nullable = false)         private String username;          // getter and setter }

@Entity @Table(name = "anObject") public class AnObject {         @Id         @GeneratedValue         private long id;         @Column         private String value;          // getter and setter }

Добавим в сущность AnObject атрибут с двумя свойствами — дата последнего редактирования и автор правки:

Код

@Embeddable public class LastModified {         @Column         @Temporal(TemporalType.TIMESTAMP)         private Calendar lastUpdated;         @OneToOne         @JoinColumn(name = "lastEditor_id")         private User lastEditor;          // getter and setter }

public interface LastModifiable {         LastModified getLastModified();          void setLastModified(LastModified modified); }

@Entity @Table(name = "anObject") public class AnObject implements LastModifiable {         @Id         @GeneratedValue         private long id;         @Column         private String value;         @Embedded         private LastModified lastModified;          // getter and setter }

И не забудем поправить тестовый класс с учётом нововведений.

С этого момента у нас уже есть всё необходимое для внесения данных о дате/авторе изменений в ручном режиме, но… люди мы «ленивые», поэтому давайте автоматизируем и эту работу — пусть за нас везде это делает Hibernate. Для этого добавляем Listener и просим Hibernate его использовать при возникновении события save или update (commit):

Код

@Component public class LastModifiedListener extends DefaultSaveOrUpdateEventListener {         private transient static final Logger LOG = LoggerFactory.getLogger(LastModifiedListener.class.getName());          @Autowired         private UserDao userDao;          @Override         public void onSaveOrUpdate(SaveOrUpdateEvent event) {                 LOG.trace("object: {}", event.getObject());                 if (event.getObject() instanceof LastModifiable) {                         LastModified lastModified = new LastModified((User) userDao.get(2));                         ((LastModifiable) event.getObject()).setLastModified(lastModified);                         LOG.trace("object: {}", event.getObject());                 }                 super.onSaveOrUpdate(event);         } }

@Component public class HibernateEventWiring {         @Autowired         private SessionFactory sessionFactory;          @Autowired         private LastModifiedListener lastModifiedListener;          @PostConstruct         public void registerListeners() {                 EventListenerRegistry registry = ((SessionFactoryImpl) sessionFactory).getServiceRegistry().getService(                         EventListenerRegistry.class);                  registry.getEventListenerGroup(EventType.SAVE_UPDATE).prependListener(lastModifiedListener);         } }

Теперь остался заключительный штрих — поправить тесты так, чтобы они учитывали новые изменения (хотя правильнее было бы сперва тесты поправить, а потом уже добавлять Listener)

На этом можно поставить финальную точку — у любой сущности, которая имплементирует интерфейс LastModifiable автоматически при каждом сохранении в БД будут изменяться поля lastUpdated и lastEditor.

ссылка на оригинал статьи http://habrahabr.ru/post/204854/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *