AuditLog zmian dla DB SpringBoot

0

Cześć,
Potrzebuję dla kilku encji z użyciem spring boot i JPA Repository zrobić mechanizm auditlog. Powinien on zapisywać do tabeli czynność wykonywaną oraz zapisywać to co się zmieniło w danym rekordzie (przy update).
Jednym z rozwiązań jakie przychodzą mi do głowy, to ręczne wywoływanie takiego mechanizmu, tzn przy każdym wywołaniu save, update, delete dla konkretnych repozytoriów, pobierać rekord przed, rekord zmieniony - porównywać i zapisywać dane. Jednak architektura systemu ma wiele do życzenia i przykładowo zapis obiektu użytkownika wywoływany jest w kilku miejscach, przez co prowadziło by to do dodatkowej duplikacji kodu i odszukiwania wszystkich tych miejsc oraz problem w dalszym rozwoju i utrzymaniu, bo ktoś może kiedyś zapomnieć logować dane. Nie wiem czy to rozwiązanie jest poprawne, eleganckie i na "topie" - na pewno zadziała.
Próbuję poszukać innych, lepszych rozwiązań. Widziałem, że sam spring ma mechanizm logowania danych, ale stosowany(przynajmniej w przykładach) był tylko do zapisu daty utworzenia, daty ostatniej zmiany a ja potrzebuję też zapisywać to co się zmieniło i nie mam pewności co do użycia go... Ktoś ma jakiś pomysł?

0

Mimo wszystko sugeruje zrefaktorować ten kod, tak żeby mieć jedno ładne repozytorium a nie X miejsc które na janusza uderzają do bazy.
JPA/Hibernate ma takie coś jak Envers.

0

Jedno eleganckie rozwiązanie już padło - jest ono prawdopodobnie najlepsze ale zależnie od poziomu burdelu w projekcie jednocześnie najbardziej pracochłonne.
Z mniej pracochłonnych rozwiązań - można to aspektowo opędzlować, wtedy można jakiś kawałek kodu wykonać za każdym razem jak jakaś metoda z JpaRepository zostanie wywołana - od razu mówię nie rekomenduję tego bo zaraz przybiegnie @jarekr000000 i mnie wyruguje z forum.
Jest jeszcze opcja triggera na bazie, który zapisze te dane do dodatkowej tabeli - możliwe tylko jeżeli dane, które musisz zalogować są w całości dostępne w bazie. Plusem będzie transakcyjność ogarnięta na poziomi bazy i gwarancja wykonania nawet jeżeli ktoś nagle postanowi wrzucić dane do bazy jakimś skryptem.
Przemyśl i przeanalizuj w kontekście Twojego przypadku bo dobrej odpowiedzi nie ma.

0
Shalom napisał(a):

Mimo wszystko sugeruje zrefaktorować ten kod, tak żeby mieć jedno ładne repozytorium a nie X miejsc które na janusza uderzają do bazy.
JPA/Hibernate ma takie coś jak Envers.

Dobrze rozumiem, że ten Envers jest tylko w hibernate? Używając "czystego" spring-date JPA nie ma Envers? Co w takim przypadku poleciłbyś?
Dodatkowo potrzrebuję zapisywać zmiany z LdapRepository, o czym wcześniej nie wspomniałem, czy Envers obsłuży, jeśli nie ma kopii danych z ldapa w lokalnej bazie?

0
0
turo90 napisał(a):

Cześć,
Potrzebuję dla kilku encji z użyciem spring boot i JPA Repository zrobić mechanizm auditlog.
[...]
i przykładowo zapis obiektu użytkownika wywoływany jest w kilku miejscach, przez co prowadziło by to do dodatkowej duplikacji kodu i odszukiwania wszystkich tych miejsc oraz problem w dalszym rozwoju i utrzymaniu, bo ktoś może kiedyś zapomnieć logować dane.

Masz repozytorium, które implementuje JpaRepository. Normalnym sposobem byłoby zaimplementować drugie repozytorium - dekorator. To drugie repozytorium zwyczajnie logowało by operację i wywoływało to pierwsze repo. Następnie wystarczy zamiast new UserRepository() utworzyć new LoggingRepository(new UserRepository()). Podobnie zrobić z repozytorium LDAP. Taka zmiana jest transparentna dla kodu, który używa tych repozytoriów.

Niestety używasz Springa do tworzenia tych repozytoriów i żeby zrobić taką dekorację potrzebujesz potworka o nazwie @NoRepositoryBean
https://dzone.com/articles/customizing-spring-data-jpa

Ewentualnie tworzyć te repozytoria nie magią adnotacji, a poprosić Springa o jego różdżkę. Wówczas możesz je stworzyć jako @Bean i udekorować swoim logowaniem:
https://docs.spring.io/spring-data/data-commons/docs/current/reference/html/#repositories.create-instances.standalone

RepositoryFactorySupport factory = … // Instantiate factory here
UserRepository repository = factory.getRepository(UserRepository.class);

1 użytkowników online, w tym zalogowanych: 0, gości: 1