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ł?
- Rejestracja:ponad 13 lat
- Ostatnio:ponad 3 lata
- Postów:48

- Rejestracja:ponad 21 lat
- Ostatnio:około 3 lata
- Lokalizacja:Space: the final frontier
- Postów:26433
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.

- Rejestracja:około 11 lat
- Ostatnio:ponad rok
- Postów:182
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.
- Rejestracja:ponad 13 lat
- Ostatnio:ponad 3 lata
- Postów:48
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?


- Rejestracja:około 17 lat
- Ostatnio:dzień
- Postów:1875
- Użyj Hibernate Envers albo
- Użyj eventów wbudowanych w Spring Data https://www.baeldung.com/spring-data-rest-events albo
- Zaimplementuj Event Sourcing albo
- Dodaj warstwę logującą operacje biznesowe albo
- Na grubo https://vladmihalcea.com/how-to-extract-change-data-events-from-mysql-to-kafka-using-debezium/

- Rejestracja:około 9 lat
- Ostatnio:około 10 godzin
- Lokalizacja:Kraków
- Postów:402
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);



Zarejestruj się i dołącz do największej społeczności programistów w Polsce.
Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.
ShalomJpaRepository
to nie jest repozytorium tylko taka niskopoziomowa CRUDowa nakładka na bazę. Ja mówię o repozytorium w sensie operacji biznesowych.