日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

我們開發的業務系統通常會提供給很多人使用,那在使用的過程中,日志系統變得非常重要。

日志系統記錄的用戶行為有以下的作用:

  • 從系統用戶角度看:它展示了用戶自身的操作歷史和具體對象的變動歷史,便于用戶進行梳理
  • 從系統管理員角度看:它可以記錄了所有用戶操作,便于我們定位異常行為

例如,在git的project操作中,我們就可以看到這樣的操作日志展示:

如何快速搭建日志系統

 

對于這樣的日志記錄,我們可以在相關記錄點添加對應的日志寫入代碼或者通過切面實現。然而,這樣的日志展示是相對簡單的,只是記錄了操作行為的種類。而有時我們需要記錄每個操作行為對操作對象引發的具體變動,例如展示出這樣的結果:

如何快速搭建日志系統

 

這給日志記錄帶來了不小的挑戰:

  • 在一個系統中,可能涉及到多種對象(例如,學生、課程、老師),而每個對象的屬性是完全不一樣的
  • 在一次操作中,可能改變了對象的一個或者多個屬性,這也使得我們極難逐一記錄

而今天,我們要介紹的是一套強大且易用的JAVA對象日志記錄系統,支持對象屬性變動的記錄與查詢。借助于它,我們可以方便地實現對象屬性變動的記錄與查詢。

1 系統簡介

ObjectLogger是一套強大且易用的對象日志記錄系統。它能夠將任意對象的變動日志記錄下來,并支持查詢??梢詰迷谟脩舨僮魅罩居涗?、對象屬性變更記錄等諸多場景中。

該系統具有以下特點:

  • 一站整合:系統支持日志的記錄與查詢,開發者只需再開發前端界面即可使用。
  • 完全獨立:與業務系統無耦合,可插拔使用,不影響主業務流程。
  • 應用共享:系統可以同時供多個業務系統使用,互不影響。
  • 簡單易用:服務端直接jar包啟動;業務系統有官方Maven插件支持。
  • 自動解析:能自動解析對象的屬性變化,并支持富文本的前后對比。
  • 便于擴展:支持自定義對象變動說明、屬性變動說明。支持更多對象屬性類型的擴展。

整個項目包含四個部分:

  • ObjectLoggerClient:能夠集成到業務系統進行日志分析、發送jar包??梢詮腗aven官方倉庫引入該jar包。該模塊位于client子包下。
  • ObjectLoggerServer:一個web服務,需要數據庫的支持。它能夠接收并保存ObjectLoggerClient發出的日志信息,支持日志的查詢操作。該模塊位于server子包下。
  • react-object-logger:一個React前端組件,用于進行日志的前端展示。可以從npm官方倉庫引入該組件。該子項目位于react-object-logger。
  • ObjectLoggerDemo:一個業務端集成ObjectLoggerClient的示例。該模塊位于demo子包下。

2 快速上手

2.1 創建數據庫

使用該項目的/server/database/init_data_table.sql文件初始化兩個數據表。

2.2 啟動Server

下載該項目下最新的Server服務jar包,地址為/server/target/ObjectLoggerServer-*.jar。

啟動下載的jar包。

java -jar ObjectLoggerServer-*.jar --spring.datasource.url=jdbc:{db}://{db_address}/{db_name} --spring.datasource.username={db_username} --spring.datasource.password={db_password}

上述命令中的用戶配置項說明如下:

  • db:數據庫類型。如果使用MySQL數據庫則為mysql;如果使用SqlServer數據庫則為sqlserver。
  • db_address:數據庫連接地址。如果數據庫在本機則為127.0.0.1。
  • db_name:數據庫名,該數據庫中需包含上一步初始化的兩個數據表。
  • db_username:數據庫登錄用戶名。
  • db_password:數據庫登錄密碼。

啟動jar成功后可以看到下面的界面:

如何快速搭建日志系統

 

使用瀏覽器訪問下面的頁面可以看到系統歡迎頁面:

http://127.0.0.1:12301/ObjectLoggerServer/

訪問上述地址可以看到下面的歡迎界面:

如何快速搭建日志系統

 

至此,ObjectLoggerServer系統已經搭建結束,可以接受業務系統的日志寫入和查詢操作。

3 業務系統接入

該部分講解如何配置業務系統來將業務系統中的對象變化通過ObjectLoggerClient分析,然后記錄到ObjectLoggerServer中。

這一部分的使用可以參照ObjectLoggerDemo項目,該項目給出了業務系統集成ObjectLoggerClient的詳細示例。ObjectLoggerDemo的制品包可以從/demo/target/ObjectLoggerDemo-*.jar獲得,無需其他配置直接運行java -jar ObjectLoggerDemo-*.jar便可以直接啟動該項目。

可以直接根據啟動頁面的提示訪問相關地址來體驗:

如何快速搭建日志系統

 

3.1 引入依賴包

在pom中增加下面的依賴:

<dependency>
 <groupId>com.github.yeecode.objectlogger</groupId>
 <artifactId>ObjectLoggerClient</artifactId>
 <version>{最新版本}</version>
</dependency>

3.2 添加對ObjectLoggerClient中bean的自動注入

3.2.1 對于SpringBoot應用

在SpringBoot的啟動類前添加@ComponentScan注解,并在basePackages中增加ObjectLoggerClient的包地址:com.github.yeecode.objectlogger,如:

@SpringBootApplication
@ComponentScan(basePackages={"{your_beans_root}","com.github.yeecode.objectlogger"})
public class MyBootAppApplication {
public static void main(String[] args) {
 // 省略其他代碼
 }
}

3.2.2 對于Spring應用

在applicationContext.xml增加對ObjectLoggerClient包地址的掃描:

<context:component-scan base-package="com.github.yeecode.objectlogger">
</context:component-scan>

3.3 完成配置

在application.properties中增加:

yeecode.objectLogger.serverAddress=http://{ObjectLoggerServer_address}
yeecode.objectLogger.businessAppName={your_app_name}
yeecode.objectLogger.autoLogAttributes=true
  • ObjectLoggerServer_address:屬性指向上一步的ObjectLoggerServer的部署地址,例如:127.0.0.1:12301
  • your_app_name:指當前業務系統的應用名。以便于區分日志來源,實現同時支持多個業務系統
  • yeecode.objectLogger.autoLogAttributes:是否對對象的所有屬性進行變更日志記錄

至此,業務系統的配置完成。已經實現了和ObjectLoggerServer端的對接。

4 日志查詢

系統運行后,可以通過http://127.0.0.1:12301/ObjectLoggerServer/log/query查詢系統中記錄的日志,并通過傳入參數對日志進行過濾。

如何快速搭建日志系統

 

通過這里,我們可以查詢下一步中寫入的日志。

5 日志展示

ObjectLogger有前端React組件react-object-logger支持,用于進行日志信息的展示。體驗頁面:react-object-logger 示例頁面

展示效果如圖:

如何快速搭建日志系統

 

感興趣的用戶可以前往react-object-logger進行了解。

同時也歡迎各位開發者開發面向其它前端技術棧的組件。

6 日志寫入

業務系統在任何需要進行日志記錄的類中引入LogClient。例如:

@Autowired
private LogClient logClient;

6.1 簡單使用

直接將對象的零個、一個、多個屬性變化放入List<BaseAttributeModel>后調用logAttributes方法發出即可。List<BaseAttributeModel>置為null則表示此次對象無需要記錄的屬性變動。例如,業務應用中調用:

logClient.logAttributes(
 "CleanRoomTask",
 5,
 "Tom",
 "add",
 "Add New Task",
 "Create a cleanRoomTask",
 "taskName is :Demo Task",
 null);

在ObjectLoggerServer中使用如下查詢條件:

http://127.0.0.1:12301/ObjectLoggerServer/log/query?appName=ObjectLoggerDemo&objectName=CleanRoomTask&objectId=5

查詢到日志:

{
 "respMsg": "SUCCESS",
 "respData": [
 {
 "id": 1,
 "appName": "ObjectLoggerDemo",
 "objectName": "CleanRoomTask",
 "objectId": 5,
 "operator": "Jone",
 "operationName": "start",
 "operationAlias": "Start a Task",
 "extraWords": "Begin to clean room...",
 "comment": "Come on and start cleaning up.",
 "operationTime": "2019-07-04T06:53:40.000+0000",
 "attributeModelList": [
 {
 "attributeType": "NORMAL",
 "attributeName": "status",
 "attributeAlias": "Status",
 "oldValue": "TODO",
 "newValue": "DOING",
 "diffValue": null,
 "id": 1,
 "operationId": 1
 }
 ]
 }
 ],
 "respCode": "1000"
}

6.2 對象變動自動記錄

該功能可以自動完成新老對象的對比,并根據對比結果,將多個屬性變動一起寫入日志系統中。使用時,要確保傳入的新老對象屬于同一個類。

例如,業務系統這樣調用:

CleanRoomTask oldTask = new CleanRoomTask();
oldTask.setId(5);
oldTask.setTaskName("Demo Task");
oldTask.setStatus("TODO");
oldTask.setDescription("Do something...");
CleanRoomTask newTask = new CleanRoomTask();
newTask.setId(5);
newTask.setTaskName("Demo Task");
newTask.setStatus("DOING");
newTask.setDescription("The main job is to clean the floor.");
newTask.setAddress("Sunny Street");
newTask.setRoomNumber(702);
logClient.logObject(
 cleanRoomTask.getId().toString(),
 "Tom",
 "update",
 "Update a Task",
 null,
 null,
 oldTask,
 newTask);

則我們可以使用下面查詢條件:

http://127.0.0.1:12301/ObjectLoggerServer/log/query?appName=ObjectLoggerDemo&objectName=CleanRoomTask&objectId=5

查詢到如下結果:

{
 "respMsg": "SUCCESS",
 "respData": [
 {
 "id": 4,
 "appName": "ObjectLoggerDemo",
 "objectName": "CleanRoomTask",
 "objectId": 5,
 "operator": "Tom",
 "operationName": "update",
 "operationAlias": "Update a Task",
 "extraWords": null,
 "comment": null,
 "operationTime": "2019-07-04T07:22:59.000+0000",
 "attributeModelList": [
 {
 "attributeType": "NORMAL",
 "attributeName": "roomNumber",
 "attributeAlias": "roomNumber",
 "oldValue": "",
 "newValue": "702",
 "diffValue": null,
 "id": 5,
 "operationId": 4
 },
 {
 "attributeType": "NORMAL",
 "attributeName": "address",
 "attributeAlias": "address",
 "oldValue": "",
 "newValue": "Sunny Street",
 "diffValue": null,
 "id": 6,
 "operationId": 4
 },
 {
 "attributeType": "NORMAL",
 "attributeName": "status",
 "attributeAlias": "Status",
 "oldValue": "TODO",
 "newValue": "DOING",
 "diffValue": null,
 "id": 7,
 "operationId": 4
 },
 {
 "attributeType": "TEXT",
 "attributeName": "description",
 "attributeAlias": "Description",
 "oldValue": "Do something...",
 "newValue": "The main job is to clean the floor.",
 "diffValue": "Line 1<br/> -: <del> Do something... </del> <br/> +: <u> The main job is to clean the floor. </u> <br/>",
 "id": 8,
 "operationId": 4
 }
 ]
 }
 ],
 "respCode": "1000"
}

7 對象屬性過濾

有些對象的屬性的變動不需要進行日志記錄,例如updateTime、hashCode等。ObjectLoggerClient支持對對象的屬性進行過濾,只追蹤我們感興趣的屬性。

并且,對于每個屬性我們可以更改其記錄到ObjectLoggerClient系統中的具體方式,例如修改命名等。

要想啟用這個功能,首先將配置中的yeecode.objectLogger.autoLogAttributes改為false。

yeecode.objectLogger.autoLogAttributes=true

然后在需要進行變化日志記錄的屬性上增加@LogTag注解。凡是沒有增加該注解的屬性在日志記錄時會被自動跳過。

例如,注解配置如下則id字段的變動將被忽略。

private Integer id;
@LogTag
private String taskName;
@LogTag(alias = "UserId", extendedType = "userIdType")
private int userId;
@LogTag(alias = "Status")
private String status;
@LogTag(alias = "Description", builtinType = BuiltinTypeHandler.TEXT)
private String description;

該注解屬性介紹如下:

  • alias:屬性別名。默認情況下會將屬性名寫入。
  • builtinType:ObjectLoggerClient的內置類型,為BuiltinTypeHandler的值。默認為BuiltinTypeHandler.NORMAL。
  • BuiltinTypeHandler.NORMAL:記錄屬性的新值和舊值,對比值為null
  • BuiltinTypeHandler.RICHTEXT: 用戶富文本對比。記錄屬性值的新值和舊值,并將新舊值轉化為純文本后逐行對比差異,對比值中記錄差異
  • extendedType:擴展屬性類型。使用ObjcetLogger時,用戶可以擴展某些字段的處理方式,此時,alias等信息均可以被用戶自主覆蓋。

8 屬性處理擴展

很多情況下,用戶希望能夠自主決定某些對象屬性的處理方式。例如,對于例子中Task對象的userId屬性,用戶可能想將其轉化為姓名后存入日志系統,從而使得日志系統與userId完全解耦。

ObjectLoggerClient完全支持這種情況,可以讓用戶自主決定某些屬性的日志記錄方式。要想實現這種功能,首先在需要進行擴展處理的屬性上為@LogTag的extendedType屬性賦予一個字符串值。例如:

@LogTag(alias = "UserId", extendedType = "userIdType")
private int userId;

然后在業務系統中聲明一個Bean繼承BaseExtendedTypeHandler,作為自由擴展的鉤子。代碼如下:

@Service
public class ExtendedTypeHandler implements BaseExtendedTypeHandler {
 @Override
 public BaseAttributeModel handleAttributeChange(String extendedType, String attributeName, String attributeAlias, Object oldValue, Object newValue) {
 // TODO
 }
}

接下來,當ObjectLoggerClient處理到該屬性時,會將該屬性的相關信息傳入到擴展Bean的handleAttributeChange方法中,然后用戶可以自行處理。傳入的四個參數解釋如下:

  • extendedType:擴展類型值,即@LogTag注解的extendedType值。本示例中為userIdType。
  • attributeName:屬性名。本示例中為userId。
  • attributeAlias:屬性別名,@LogTag注解的alias值。本示例中為UserId。
  • oldValue:該屬性的舊值。
  • newValue:該屬性的新值。

例如我們可以采用如下的方式處理userIdType屬性:

@Service
public class ExtendedTypeHandler implements BaseExtendedTypeHandler {
 @Override
 public BaseAttributeModel handleAttributeChange(String extendedType, String attributeName, String attributeAlias, Object oldValue, Object newValue) {
 BaseAttributeModel baseAttributeModel = new BaseAttributeModel();
 if (extendedType.equals("userIdType")) {
 baseAttributeModel.setOldValue("USER_" + oldValue);
 baseAttributeModel.setNewValue("USER_" + newValue);
 baseAttributeModel.setDiffValue(oldValue + "->" + newValue);
 }
 return baseAttributeModel;
 }
}

9 總結

怎么樣,是不是有了這一套系統之后,再負責的日志系統都變得簡單起來。快收藏起來當作自己的秘技吧!


易哥,高級軟件架構師、網絡工程師、數據庫工程師、注冊電氣工程師。現從事軟件架構架構設計工作。

分享架構師知識! 歡迎關注我們,不錯過每期的原創干貨!

分享到:
標簽:系統 日志
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定