JeeSite | 保存信息修改記錄

来源:https://www.cnblogs.com/tosser/archive/2019/10/14/11674268.html
-Advertisement-
Play Games

需求點 在很多場景中信息是不能輕易被修改的,修改時要麼需要具備許可權,要麼需要審批,但是無論是哪種方式,修改前後的數據都是需要留有“案底”的,也就是說關鍵的信息被修改後是有修改記錄的,一般修改記錄會記錄修改人、修改日期和修改的數據欄位。 比如,修改一個人的姓名從“張三”變為了“李四”,那麼在進行記錄的 ...


需求點

        在很多場景中信息是不能輕易被修改的,修改時要麼需要具備許可權,要麼需要審批,但是無論是哪種方式,修改前後的數據都是需要留有“案底”的,也就是說關鍵的信息被修改後是有修改記錄的,一般修改記錄會記錄修改人、修改日期和修改的數據欄位。

        比如,修改一個人的姓名從“張三”變為了“李四”,那麼在進行記錄的時候,記錄的信息可能如下:

        姓名:(張三)=>(李四);性別:(女)=>(男);

        這樣就很好的體現出了修改了哪個欄位,修改前後的數據分別是什麼。關鍵的信息無論怎麼修改都會有據可查,時間、人物、修改數據前後信息等。

 

判斷被修改的數據

        在頁面中將數據修改並提交頁面後,數據會從 JSP 傳遞到 Controller 中,這時數據還沒有被更新到資料庫中,從提交到 Controller 的對象中用數據的 id 從資料庫中查出它現有的數據,然後使用現有的數據和提交的數據進行對比,就可以得到被修改過的數據欄位有哪些了。

        這裡比較繁瑣的是如何進行比對,逐個欄位的使用 if 進行判斷肯定不是好方法,畢竟欄位太多的時候是要寫死人的。那麼如何進行,直接比較兩個對象就行,源碼我是從網上找的,好用,符合需求,源碼如下:

 1 /** 
 2  * 獲取兩個對象同名屬性內容不相同的列表 
 3  * @param class1 對象1 
 4  * @param class2 對象2 
 5  * @return 
 6  * @throws ClassNotFoundException 
 7  * @throws IllegalAccessException 
 8  */  
 9 public static List<Map<String ,Object>> compareTwoClass(Object class1, Object class2) {  
10     List<Map<String,Object>> list=new ArrayList<Map<String, Object>>();  
11     // 獲取對象的class  
12     Class<?> clazz1 = class1.getClass();  
13     Class<?> clazz2 = class2.getClass();  
14     // 獲取對象的屬性列表  
15     Field[] field1 = clazz1.getDeclaredFields();  
16     Field[] field2 = clazz2.getDeclaredFields();  
17     // 遍歷屬性列表field1  
18     for(int i=0;i<field1.length;i++){  
19         // 遍歷屬性列表field2  
20         for(int j=0;j<field2.length;j++){  
21             // 如果field1[i]屬性名與field2[j]屬性名內容相同  
22             if(field1[i].getName().equals(field2[j].getName())){  
23                 if(field1[i].getName().equals(field2[j].getName())){  
24                     field1[i].setAccessible(true);  
25                     field2[j].setAccessible(true);  
26                     // 如果field1[i]屬性值與field2[j]屬性值內容不相同  
27                     try {
28                         if (!compareTwo(field1[i].get(class1), field2[j].get(class2))){  
29                             Map<String,Object> map2=new HashMap<String, Object>();  
30                             map2.put("name",field1[i].getName());  
31                             map2.put("old",field1[i].get(class1));  
32                             map2.put("new",field2[j].get(class2));  
33                             list.add(map2);  
34                         }
35                     } catch (IllegalArgumentException e) {
36                         // TODO Auto-generated catch block
37                         e.printStackTrace();
38                     } catch (IllegalAccessException e) {
39                         // TODO Auto-generated catch block
40                         e.printStackTrace();
41                     }  
42                     break;  
43                 }  
44             }
45         }
46     }
47     return list;
48 }
49 
50 /**  
51  * 對比兩個數據是否內容相同  
52  *  
53  * @param  object1,object2  
54  * @return boolean類型  
55  */  
56 public static boolean compareTwo(Object object1,Object object2){  
57     if ( object1 == null && object2 == null ) {  
58         return true;  
59     }  
60     if ( object1 == null && object2 != null ) {  
61         return false;  
62     }  
63     if ( object1.equals(object2) ) {  
64         return true;  
65     }  
66     return false;  
67 }

        源碼是從哪裡找到的忘記了,在這裡感謝願意分享的網友,是你的源碼讓我快速解決了項目中的問題。(當時雖然不懂 Java,但是對於類似的處理我認為一定有相應的方法,而不是傻傻的去逐個比較,後來瞭解到這是 Java 中的反射,發現反射與註解真是好東西,用在項目當中會省很多事,現在我寫 PHP 時,雖然 PHP 不支持註解,但是我也會通過反射去解析註釋的方式,實現類似 Java 中註解的功能,真的很省事。)

 

屬性解析

        上面的函數會返回兩個對象中屬性值不同的 List,獲得該列表後,再次遍歷解析屬性對應的欄位含義,進而拼接成一個字元串就可以生成修改日誌進行保存了。

        通常情況下只要把類中的屬性和屬性對應的中文進行關聯後就可以了,但是在 JeeSite 中存在字典類型,比如“男”和“女”,在頁面上會顯示“男”和“女”,而在資料庫中可能是以 “0” 和 “1” 進行存儲的,所以一般在選擇“男”或“女”後頁面提交的也是 “0” 或 “1”,以這種方式進行日誌記錄顯然不直觀,因此在這種情況下就需要將欄位的中文和字典名也進行關聯,這樣就可以將欄位中文匹配到字典的值的描述。

具體代碼如下:

 1 public String catModifyInfo(List<Map<String, Object>> list) {
 2     Map<String, String> mapField = new HashMap<String, String>() {{ 
 3         // 類中的屬性,屬性對應的中文
 4         put("sex","性別");
 5     }};
 6     Map<String, String> mapDict = new HashMap<String, String>() {{ 
 7         // 屬性對應的中文,在JeeSite中字典的描述
 8         put("性別", "SEX");
 9     }}; 
10     
11     // 構造的修改字元串
12     String modInfo = "";
13     
14     for ( Map<String, Object> mp : list) {
15         System.out.println(mp.get("name") + "---" + mp.get("old") + "---" + mp.get("new"));
16         System.out.println(mapField.get(mp.get("name")));
17                     
18         // 判斷修改的值是否為字典
19         if ( mapDict.containsKey(mapField.get(mp.get("name"))) ) {
20             String oldValue = mp.get("old").toString();
21             String newValue = mp.get("new").toString();
22             String type     = mapDict.get(mapField.get(mp.get("name")));
23             String oldStr = DictUtils.getDictLabel(oldValue, type, "");
24             String newStr = DictUtils.getDictLabel(newValue, type, "");
25             System.out.println(mapField.get(mp.get("name")) + ":(" + oldStr + ") => (" + newStr + ");");
26             modInfo += mapField.get(mp.get("name")) + ":(" + oldStr + ") => (" + newStr + ");"; 
27         } else {
28             modInfo += mapField.get(mp.get("name")) + ":(" + mp.get("old") + ") => (" + mp.get("new") + ");"; 
29         }
30     }
31     
32     return modInfo;
33 }

        函數傳入的參數是兩個對象差異的屬性,在迴圈進行解析併進行字元串拼接後,就可以獲得對應的日誌了。

 

調用方法

        在 JeeSite 中提交數據後,無論是修改還是新建,都會調用相關 Controller 中的 save 方法,因此上面的方法需要在 save 方法中進行調用。

        相同的方法如何判斷當前是新建,還是修改呢?判斷的方法就是判斷傳入的對象中是否有 id,如果有 id 則說明是修改,如果沒有 id 則說明是新建。

        具體代碼如下:

 1 /*
 2  * 如果id不為空,則表示為修改
 3  */
 4 if ( StringUtils.isNotBlank(newXxx.getId()) ) {
 5     Xxx oldXxx = new Xxx();
 6     // 獲取原來的信息
 7     oldXxx = xxxService.get(newXxx.getId());
 8     
 9     // 比較修改後的信息和未修改的信息
10     List<Map<String, Object>> modList = compareTwoClass(oldXxx, newXxx);
11     // 生成差異信息
12     String strModifyInfo = catModifyInfo(modList);
13     // 輸出差異字元串
14     System.out.println(strModifyInfo);
15     
16     // 把修改記錄保存到日誌表中
17     // ...
18 }

有了以上的方式就可以實現修改信息前後的日誌記錄了,修改後的情況如下:

        不過該方式並不完美,如果修改了表欄位的名稱或數量,那麼代碼也要相應的修改,如果新添加的欄位有對應的字典,那麼也要添加字典對應的關聯,這樣就需要每次修改代碼,十分的不方便了。

        解決的方式很簡單,使用 JeeSite 中代碼生成的功能,就可以解決該問題。

 


 

我的微信公眾號:“碼農UP2U”


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • JqueryMobile提交表單到php時,會出現空白頁面,需要手動刷新才會顯示php頁面。 修正方法:form元素中添加data-ajax=“false”。 具體原理:https://blog.csdn.net/qw_xingzhe/article/details/37342887 ...
  • 在模板文件中,可以使用“${{...}}”表達式進行數據轉換,Thymeleaf會使用配置好的數據轉換類,來實現轉換。 例如一個User對象,簡單起見假設有姓名和年齡兩個欄位,對象的toString()方法拼接所有欄位,使用“${user}”會調用對象的 toString()方法得到所有欄位,... ...
  • URL配置(URLconf)就像Django 所支撐網站的目錄。它的本質是URL與要為該URL調用的視圖函數之間的映射表;你就是以這種方式告訴Django,對於客戶端發來的某個URL調用哪一段邏輯代碼對應執行。 簡單的路由配置 註意: 1、使用URL,必須先將應用程式中的視圖函數導入到urls.py ...
  • Thymeleaf表達式語法之常量分為字元串常量、數字常量、布爾值常量、空值常量; 運算符分為算術運算符、關係運算符、條件運算符、無操作符。 ...
  • 只要你在 resources 目錄下放置名為 banner.txt、banner.gif 、banner.jpg 或 banner.png 的文件,Spring Boot 會自動載入,將其作為啟動時列印的 logo。 ...
  • Spring Boot 二十個註解 占據無力擁有的東西是一種悲哀。 Cold on the outside passionate on the insede. 背景:Spring Boot 註解的強大毋庸置疑,使用其註解可以大量減少XML 等複雜的配置文件,令Java 代碼更純,開發更簡單高效,記下 ...
  • 摘要 Guava Cache是Google開源的Java工具集庫Guava里的一款緩存工具,一直覺得使用起來比較簡單,沒想到這次居然還踩了一個坑 背景 功能需求抽象出來很簡單,就是將資料庫的查詢 的結果緩存起來。但同時還有批量請求,為了提高效率,肯定要批量查詢資料庫, 對於的guava cache ...
  • Python多任務之進程,內容包括 Process多進程,使用進程池完成多任務;其中 Process多進程 包括 進程的概念,使用Process完成多任務,進程和線程對比,通過隊列完成進程間通信,進程的狀態,獲取進程id;使用進程池完成多任務 包括 進程池的概念和語法,進程池拷貝文件夾等內容 ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...