最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Data Envers支持有條件變動紀(jì)錄的保存和查詢的方法

 更新時間:2023年10月18日 10:54:02   作者:QiHY  
通過spring-data-envers可以很容易的實現(xiàn)數(shù)據(jù)變動紀(jì)錄的保存和查詢,本文介紹支持有條件變動紀(jì)錄的保存和查詢的方法,通過spring-data-envers很容易的實現(xiàn)變動紀(jì)錄的保存和查詢,只需要增加幾個注解就可以,感興趣的朋友跟隨小編一起看看吧

數(shù)據(jù)審計是業(yè)務(wù)系統(tǒng)的一個基本能力,需要系統(tǒng)能夠?qū)㈥P(guān)鍵數(shù)據(jù)的變動紀(jì)錄都保存下來,并支持變動紀(jì)錄的查詢。

通過spring-data-envers可以很容易的實現(xiàn)數(shù)據(jù)變動紀(jì)錄的保存和查詢。

有些情況下,我們需要只保存滿足特定條件的數(shù)據(jù)變動紀(jì)錄,不滿足條件的變動紀(jì)錄不進(jìn)行保存,例如只保存某個字段有值的變動紀(jì)錄。

本文介紹支持有條件變動紀(jì)錄的保存和查詢的方法。

具體的代碼參照 示例項目 https://github.com/qihaiyan/springcamp/tree/master/spring-data-envers-conditional

一、概述

可以通過 spring-data-envers 很容易的實現(xiàn)變動紀(jì)錄的保存和查詢,只需要增加幾個注解就可以。但是要實現(xiàn)有條件的變動紀(jì)錄的保存和查詢就需要進(jìn)行一些復(fù)雜的處理。

二、使用 spring-data-envers

首先引入 spring-data-envers 依賴。

在 build.gradle 中增加一行代碼:

implementation 'org.springframework.data:spring-data-envers'

在實體類上增加 Audited 注解:

@Data
@Entity
@Audited
public class MyData {
    @Id
    @GeneratedValue
    private Long id;
    private String author;
}

Repository 擴(kuò)展 RevisionRepository 方法:

public interface MyDataRepository extends JpaRepository<MyData, Long>, RevisionRepository<MyData, Long, Integer> {
}

通過以上3步操作,就添加好了變動紀(jì)錄的保存功能,我們可以通過調(diào)用變動紀(jì)錄查詢方法確認(rèn)變動紀(jì)錄保存成功。

當(dāng) Repository 擴(kuò)展 RevisionRepository 方法后,會有一個默認(rèn)實現(xiàn)的 findRevisions 方法,我們可以直接調(diào)用:

public Revisions<Integer, MyData> findRevisions(Long id) {
        return myDataRepository.findRevisions(id);
}

最后我們可以執(zhí)行完整的主體數(shù)據(jù)的保存,在控制臺中打印變動紀(jì)錄:

@Override
public void run(String... args) {
        MyData myData = new MyData();
        myData.setId(1L);
        myData.setAuthor("test");
        dbService.saveData(myData);
        dbService.findRevisions(myData.getId()).forEach(r -> System.out.println("revision: " + r.toString()));
        myData.setAuthor("newAuthor");
        dbService.saveData(myData);
        dbService.findRevisions(myData.getId()).forEach(r -> System.out.println("revision: " + r.toString()));
}

執(zhí)行完程序后,可以看到兩次保存數(shù)據(jù)的操作都可以查詢到對應(yīng)的變動紀(jì)錄,并且變動紀(jì)錄還通過 revisionType 顯示了是插入還是更新操作:

revision: Revision 1 of entity MyData(id=1, author=test) - Revision metadata DefaultRevisionMetadata{entity=DefaultRevisionEntity(id = 1, revisionDate = Oct 15, 2023, 11:41:15 AM), revisionType=INSERT}
revision: Revision 2 of entity MyData(id=1, author=newAuthor) - Revision metadata DefaultRevisionMetadata{entity=DefaultRevisionEntity(id = 2, revisionDate = Oct 15, 2023, 11:41:16 AM), revisionType=UPDATE}

三、通過自定義 Event Listener 實現(xiàn)有條件的變動紀(jì)錄的保存

在進(jìn)行數(shù)據(jù)變動時, Envers 通過監(jiān)聽事件來進(jìn)行對應(yīng)的處理,總共有以下幾個監(jiān)聽事件:

EventType.POST_INSERT
EventType.PRE_UPDATE
EventType.POST_UPDATE
EventType.POST_DELETE
EventType.POST_COLLECTION_RECREATE
EventType.PRE_COLLECTION_REMOVE
EventType.PRE_COLLECTION_UPDATE

每個監(jiān)聽事件都對應(yīng)著特定的 Listener ,在本文實例中,我們期望當(dāng) author 的值被更新為空時,不保存變動紀(jì)錄,我們可以通過自定義 PRE_UPDATE 和 POST_UPDATE 的Listener來實現(xiàn)。

因為框架提供了默認(rèn)的Listener,因此自定義 Listener 只需要擴(kuò)展默認(rèn)的Listener,并加入我們自己的特有邏輯就可以。

MyEnversPostUpdateEventListenerImpl :

public class MyEnversPreUpdateEventListenerImpl extends EnversPreUpdateEventListenerImpl {
    public MyEnversPreUpdateEventListenerImpl(EnversService enversService) {
        super(enversService);
    }
    @Override
    public boolean onPreUpdate(PreUpdateEvent event) {
        if (event.getEntity() instanceof MyData
                && ((MyData) event.getEntity()).getAuthor() == null) {
            return false;
        }
        return super.onPreUpdate(event);
    }
}

MyEnversPostUpdateEventListenerImpl:

public class MyEnversPostUpdateEventListenerImpl extends EnversPostUpdateEventListenerImpl {
    public MyEnversPostUpdateEventListenerImpl(EnversService enversService) {
        super(enversService);
    }
    @Override
    public void onPostUpdate(PostUpdateEvent event) {
        if (event.getEntity() instanceof MyData && ((MyData) event.getEntity()).getAuthor() == null) {
            return;
        }
        super.onPostUpdate(event);
    }
}

在自定義 Listener 中,我們增加了 對于 author 字段是否為空的判斷邏輯。

四、自定義 Event Listener 注冊到系統(tǒng)中

自定義 Event Listener 完成后,我們還需要讓框架執(zhí)行我們自定義的 Listener, 而不是用默認(rèn)的 Listener。

框架通過 EnversIntegrator 類注冊的 Listener, 我們要做的是重新實現(xiàn) EnversIntegrator , 在本實例中重新實現(xiàn)的類為 MyEnversIntegrator :

public class MyEnversIntegrator implements Integrator {
    @Override
    public void integrate(Metadata metadata,
                          BootstrapContext bootstrapContext,
                          SessionFactoryImplementor sessionFactory) {
        final ServiceRegistry serviceRegistry = sessionFactory.getServiceRegistry();
        final EnversService enversService = serviceRegistry.getService(EnversService.class);
        final EventListenerRegistry listenerRegistry = serviceRegistry.getService(EventListenerRegistry.class);
        listenerRegistry.addDuplicationStrategy(EnversListenerDuplicationStrategy.INSTANCE);
        if (enversService.getEntitiesConfigurations().hasAuditedEntities()) {
            listenerRegistry.appendListeners(
                    EventType.POST_DELETE,
                    new EnversPostDeleteEventListenerImpl(enversService)
            );
            listenerRegistry.appendListeners(
                    EventType.POST_INSERT,
                    new EnversPostInsertEventListenerImpl(enversService)
            );
            listenerRegistry.appendListeners(
                    EventType.PRE_UPDATE,
                    new MyEnversPreUpdateEventListenerImpl(enversService)
            );
            listenerRegistry.appendListeners(
                    EventType.POST_UPDATE,
                    new MyEnversPostUpdateEventListenerImpl(enversService)
            );
            listenerRegistry.appendListeners(
                    EventType.POST_COLLECTION_RECREATE,
                    new EnversPostCollectionRecreateEventListenerImpl(enversService)
            );
            listenerRegistry.appendListeners(
                    EventType.PRE_COLLECTION_REMOVE,
                    new EnversPreCollectionRemoveEventListenerImpl(enversService)
            );
            listenerRegistry.appendListeners(
                    EventType.PRE_COLLECTION_UPDATE,
                    new EnversPreCollectionUpdateEventListenerImpl(enversService)
            );
        }
    }
    @Override
    public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
        // nothing to do
    }
}

通過代碼可以發(fā)現(xiàn),我們只是修改了 PRE_UPDATE 和 POST_UPDATE 注冊的 Listener , 其它事件的 Listener 仍然用框架默認(rèn)的。

最后我們需要把我們實現(xiàn)的 MyEnversIntegrator 放到 META-INF/services/org.hibernate.integrator.spi.Integrator 這個配置文件中。

cn.springcamp.springdata.envers.MyEnversIntegrator

五、確認(rèn)有條件變動紀(jì)錄的保存是否生效

最后我們修改控制臺打印程序,將 author 字段更新為 null 并保存,查看變動紀(jì)錄里是否有這個更新操作的紀(jì)錄。

增加保存代碼 :

// won't generate audit record when author is null
myData.setAuthor(null);
dbService.saveData(myData);
dbService.findRevisions(myData.getId()).forEach(r -> System.out.println("revision: " + r.toString()));

執(zhí)行程序并觀察控制臺打印內(nèi)容:

revision: Revision 1 of entity MyData(id=1, author=test) - Revision metadata DefaultRevisionMetadata{entity=DefaultRevisionEntity(id = 1, revisionDate = Oct 15, 2023, 11:41:15 AM), revisionType=INSERT}
revision: Revision 2 of entity MyData(id=1, author=newAuthor) - Revision metadata DefaultRevisionMetadata{entity=DefaultRevisionEntity(id = 2, revisionDate = Oct 15, 2023, 11:41:16 AM), revisionType=UPDATE}

通過打印內(nèi)容可以確認(rèn),author 字段更新為 null 的變動紀(jì)錄沒有被紀(jì)錄,說明我們的處理是生效的。

到此這篇關(guān)于Spring Data Envers支持有條件變動紀(jì)錄的保存和查詢的方法的文章就介紹到這了,更多相關(guān)Spring Data Envers內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • nginx代理模式下java獲取客戶端真實ip地址實例代碼

    nginx代理模式下java獲取客戶端真實ip地址實例代碼

    在web開發(fā)中,獲取客戶端真實ip是常見需求,但在反向代理(如nginx)環(huán)境下,直接通過request.getremoteaddr()獲取的可能是代理服務(wù)器ip而非真實客戶端ip,這篇文章主要介紹了nginx代理模式下java獲取客戶端真實ip地址的相關(guān)資料,需要的朋友可以參考下
    2026-04-04
  • 使用Java編寫一個輸出九九口訣乘法表的程序

    使用Java編寫一個輸出九九口訣乘法表的程序

    在學(xué)習(xí)編程的過程中,編寫簡單的程序來實現(xiàn)基本的數(shù)學(xué)運算是一個很好的練習(xí),本文將介紹如何使用Java語言編寫一個程序,用于輸出9*9的乘法口訣表,需要的朋友可以參考下
    2026-01-01
  • SpringBoot整合Dubbo+ZK注冊失敗的坑及解決

    SpringBoot整合Dubbo+ZK注冊失敗的坑及解決

    使用Dubbo框架時,需在公共pom添加依賴,啟動類加@EnableDubbo,實現(xiàn)類用@DubboService替代@Service,配置中base-packages存在識別bug,可通過zkCli命令或監(jiān)控中心驗證服務(wù)注冊狀態(tài)
    2025-07-07
  • java對接支付寶支付項目的實戰(zhàn)記錄

    java對接支付寶支付項目的實戰(zhàn)記錄

    最近公司有一個需求是接入第三方支付(微信&支付寶),我接到了支付寶支付,所以下面這篇文章主要給大家介紹了關(guān)于java對接支付寶支付項目的相關(guān)資料,需要的朋友可以參考下
    2022-06-06
  • Springboot配置管理Externalized?Configuration深入探究

    Springboot配置管理Externalized?Configuration深入探究

    這篇文章主要介紹了Springboot配置管Externalized?Configuration深入探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Java如何使用Optional與Stream取代if判空邏輯(JDK8以上)

    Java如何使用Optional與Stream取代if判空邏輯(JDK8以上)

    這篇文章主要給大家介紹了關(guān)于Java如何使用Optional與Stream取代if判空邏輯(JDK8以上)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • java和matlab畫多邊形閉合折線圖示例講解

    java和matlab畫多邊形閉合折線圖示例講解

    由于要將“哈密頓回路問題(TSP)”的求解中間結(jié)果表示出來,查了一下使用程序畫多邊形圖形?,F(xiàn)在在總結(jié)一下,這個圖是“由給定節(jié)點首尾相連的”閉合多邊形
    2014-02-02
  • SpringBoot處理form-data表單接收對象數(shù)組的方法

    SpringBoot處理form-data表單接收對象數(shù)組的方法

    form-data則是一種更加靈活的編碼方式,它可以處理二進(jìn)制數(shù)據(jù)(如圖片、文件等)以及文本數(shù)據(jù),這篇文章主要介紹了SpringBoot處理form-data表單接收對象數(shù)組,需要的朋友可以參考下
    2023-11-11
  • @scope("prototype") @loadbalanced注解負(fù)載均衡失效問題

    @scope("prototype") @loadbalanced注解負(fù)載均衡失效問題

    這篇文章主要為大家介紹了@scope("prototype") @loadbalanced注解負(fù)載均衡失效問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • 解決執(zhí)行Junit單元測試報錯java.lang.ClassNotFoundException問題

    解決執(zhí)行Junit單元測試報錯java.lang.ClassNotFoundException問題

    這篇文章主要介紹了解決執(zhí)行Junit單元測試報錯java.lang.ClassNotFoundException問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11

最新評論

措勤县| 泽州县| 延寿县| 定结县| 屏东县| 阳信县| 高清| 云浮市| 凤城市| 津市市| 香河县| 伊春市| 武清区| 峨眉山市| 连山| 丰城市| 辉县市| 兴仁县| 宜兴市| 龙里县| 大庆市| 荔浦县| 喀什市| 丁青县| 沭阳县| 汝南县| 平武县| 巴塘县| 清镇市| 海林市| 梁平县| 乌兰浩特市| 永嘉县| 乌鲁木齐县| 获嘉县| 新乐市| 汶川县| 新建县| 日土县| 嘉义市| 海南省|