tp5記錄用戶的操作日志-用戶操作日志系統(tǒng)如何實(shí)現(xiàn)?架構(gòu)師必讀_第1頁
tp5記錄用戶的操作日志-用戶操作日志系統(tǒng)如何實(shí)現(xiàn)?架構(gòu)師必讀_第2頁
tp5記錄用戶的操作日志-用戶操作日志系統(tǒng)如何實(shí)現(xiàn)?架構(gòu)師必讀_第3頁
tp5記錄用戶的操作日志-用戶操作日志系統(tǒng)如何實(shí)現(xiàn)?架構(gòu)師必讀_第4頁
tp5記錄用戶的操作日志-用戶操作日志系統(tǒng)如何實(shí)現(xiàn)?架構(gòu)師必讀_第5頁
已閱讀5頁,還剩7頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

tp5記錄?戶的操作?志_?戶操作?志系統(tǒng)如何實(shí)現(xiàn)?架構(gòu)師必讀!★?戶操作?志是系統(tǒng)中常見的功能,可它該如何開發(fā)呢?這篇?章將給你答案。本?將詳細(xì)介紹?戶?志系統(tǒng)的設(shè)計(jì)、開發(fā)過程?!毕到y(tǒng)開發(fā)中我們經(jīng)常使??些?志框架(如JAVA中的log4j/logback/slf4j等),?來調(diào)試、追蹤、輸出系統(tǒng)運(yùn)?狀況等,這些?志通常是給程序員看的,暫且叫它”系統(tǒng)?志“。?對(duì)于普通?戶來說,也需要?個(gè)?志功能,可以?便查閱??做過哪些操作,這些?志是?向普通??戶的,暫且叫它”?戶操作?志“。那?戶操作?志系統(tǒng)該如何實(shí)現(xiàn)呢?這涉及軟件架構(gòu)設(shè)計(jì)與開發(fā)的多個(gè)??,具有很強(qiáng)的通?性。研究好這個(gè)問題對(duì)于開發(fā)能?的提升很?。今天有時(shí)間,我們來解答?下這個(gè)問題。并且,最后還會(huì)附上實(shí)現(xiàn)代碼。實(shí)現(xiàn)的效果如下,這是實(shí)際截取的圖:整個(gè)回答不僅包含實(shí)現(xiàn),還包括架構(gòu)設(shè)計(jì)過程,會(huì)?較長(zhǎng)。如果有不清楚的地?,?家可以在評(píng)論區(qū)提問。整個(gè)解答包括問題定義、模型設(shè)計(jì)、?案設(shè)計(jì)、最終實(shí)現(xiàn)等多個(gè)環(huán)節(jié)。展現(xiàn)了系統(tǒng)架構(gòu)設(shè)計(jì)的全部流程。?錄如下:1功能定義2模型設(shè)計(jì)2.1上層切?2.2下層切?2.3混合切?3對(duì)象屬性對(duì)?功能實(shí)現(xiàn)4對(duì)象屬性處理4.1普通屬性4.2特殊屬性4.3業(yè)務(wù)屬性5易?性注1功能定義在開發(fā)?個(gè)系統(tǒng)之前,我們先要對(duì)系統(tǒng)進(jìn)?明確的定義。在?個(gè)軟件系統(tǒng)中,通常存在增刪改查四類操作。對(duì)于?志系統(tǒng)?已,這四類操作的處理難度不同。查詢操作往往不需要記錄?志,增加和刪除操作涉及?個(gè)對(duì)象狀態(tài),編輯操作涉及對(duì)象編輯前和編輯后的兩個(gè)狀態(tài)。因此,編輯操作是整個(gè)?志模塊中最難處理的。只要掌握了編輯操作,則新增操作、刪除操作、查詢操作都很簡(jiǎn)單了。畢竟,新增操作可以理解為null到新對(duì)象的編輯,刪除操作可以理解為舊對(duì)象到null的編輯,查詢操作可以理解為舊對(duì)象到舊對(duì)象的編輯。因此,本?主要以編輯操作為例進(jìn)?介紹。為了便于描述,我們假設(shè)?個(gè)學(xué)校衛(wèi)??掃除系統(tǒng)。這個(gè)系統(tǒng)中包含很多?法,例如分配?掃除?作的assignTask?法,開始某個(gè)具體?作的startTask?法,驗(yàn)收某個(gè)具體?作的checkTask?法,增加新的?員的addUser?法等。每個(gè)?法都有不同的參數(shù),涉及不同的對(duì)象。以startTask?法為例,開始?個(gè)任務(wù)需要在任務(wù)中記錄開始時(shí)間、責(zé)任?、使?的?具,整個(gè)?法如下:publicStringstartTask(StringtaskId,IntegeruserId,DatestartTime,Tooltool){//業(yè)務(wù)代碼}最簡(jiǎn)單的記錄?志的?法便是在代碼中直接根據(jù)業(yè)務(wù)邏輯寫??志操作語句,例如:publicStringstartTask(StringtaskId,IntegeruserId,DatestartTime,Tooltool){//業(yè)務(wù)代碼log.add("操作類型:開始任務(wù)。任務(wù)編號(hào):"+taskId+";責(zé)任?:如果你真的打算使?上述的?法記錄?志,那已經(jīng)沒有什么可以教你的了。你要做的就是提升??Ctrl+C和Ctrl+V的速度,努?成為?個(gè)真正的CV?神直到頂級(jí)CRUD?程師。?如果你想要設(shè)計(jì)?個(gè)較為專業(yè)、通?、易?的?志模塊,那請(qǐng)繼續(xù)向下閱讀。我們必須從模型設(shè)計(jì)開始慢慢展開。2模型設(shè)計(jì)設(shè)計(jì)系統(tǒng)的第?步是抽象,抽象出?個(gè)簡(jiǎn)單的便于處理的模型。我們可以把?戶操作抽象為下?的模型,即?戶通過業(yè)務(wù)邏輯修改了持久層中的數(shù)據(jù)。要想記錄?志,那我們需要在整個(gè)流程中設(shè)置?道切?,?以獲取和記錄操作的影響。?這?道切?的位置?分關(guān)鍵,我們下?探討這?點(diǎn)。本章節(jié)主要討論?個(gè)問題:?jiǎn)?切?能否實(shí)現(xiàn)?戶操作?志的記錄。如果使?單?的切?能實(shí)現(xiàn)?志記錄功能,那就太好了。這意味著我們只要在系統(tǒng)中定義?個(gè)?志切?,則所有的?戶操作都會(huì)被記錄。?如果單?的切??法做到,那我們的?志操作就需要侵?業(yè)務(wù)邏輯。在展開討論之前要注意,這?只是模型設(shè)計(jì),請(qǐng)忽略?些細(xì)節(jié)。例如,參數(shù)是英?變量名,不便于表意;某些參數(shù)是id,與系統(tǒng)強(qiáng)耦合等。這些都不是模型層需要考慮的,我們會(huì)在后續(xù)的設(shè)計(jì)中解決這些問題。2.1上層切??先,我們考慮在整個(gè)業(yè)務(wù)邏輯的最上層設(shè)置切?如下圖所?:這?層其實(shí)就是業(yè)務(wù)邏輯??處,以下?的?法為例:publicStringstartTask(StringtaskId,IntegeruserId,DatestartTime,Tooltool){//業(yè)務(wù)代碼}我們可以得到的?志信息有:startTask:?法的名稱-taskId:?法的參數(shù)名,及其對(duì)應(yīng)的參數(shù)值,例如15-userId:?法的參數(shù)名,及其對(duì)應(yīng)的參數(shù)值,例如3-startTime:?法的參數(shù)名,及可見這些信息的特點(diǎn)是貼近業(yè)務(wù)邏輯。因?yàn)閟tartTask表明了我們要進(jìn)?的業(yè)務(wù)邏輯的操作類型,?后?的操作參數(shù)則表明了業(yè)務(wù)邏輯的參數(shù)。然?缺點(diǎn)也很明顯:?先,?法獲得編輯前的舊對(duì)象。即我們不知道startTask執(zhí)?前task對(duì)象的狀態(tài)。其次,它不能反映真正的數(shù)據(jù)變動(dòng)。這?點(diǎn)是致命的。好,我們接下來說明?下第?點(diǎn)。因?yàn)槲覀兪巧蠈忧?,從?參處獲取信息。但是,?參的信息卻不?定是最終持久化的信息。假設(shè)?法中存在下?的業(yè)務(wù)邏輯:publicStringstartTask(StringtaskId,IntegeruserId,DatestartTime,Tooltool){//其他業(yè)務(wù)代碼while(taskBusiness.queryByTaskId(taskId).isFinished()){則上層切?獲得的taskId信息可能是效的,甚?,整個(gè)操作都是效的。因此,上層切?的特點(diǎn)是:貼近業(yè)務(wù)邏輯、不能反映真實(shí)數(shù)據(jù)變動(dòng)。因此,上層切??法直接采?。2.2下層切?下層切?就是在業(yè)務(wù)邏輯的最下層設(shè)置切?,如下圖所?:這?層其實(shí)就是在持久層獲取?志信息。startTask?法可能在持久層對(duì)應(yīng)了下?的update操作:updateTask(TaskModeltaskModel);//該?法對(duì)應(yīng)了MyBatis等?具中的SQL語句通過這個(gè)?法可以得到的?志信息有:updateTask:-taskId-userId-startTime-toolId-taskName-taskDescription?先,以上信息是準(zhǔn)確的。因?yàn)檫@些信息是從寫?持久層的操作中獲取的,例如從SQL語句的前?步獲取。這??的taskId、userId等值可能和?參的值不?樣,但?定是準(zhǔn)確的。但是,它仍然存在兩個(gè)問題:?先,?法獲得編輯前的舊對(duì)象。同上。其次,它脫離業(yè)務(wù)邏輯。我們還是主要說明?下第?點(diǎn),例如,?志信息中的updateTask反應(yīng)了這是?次任務(wù)編輯操作,但是任務(wù)編輯操作是很多的:assignTask、startTask、checkTask、changeTaskName等不同的業(yè)務(wù)操作可能都會(huì)映射為?次SQL操作中的update操作。在這?,我們?法區(qū)分了。并且,編輯操作?般寫的??全,例如常寫為下?的形式:UPDATEtaskuserId=#{userId},startTime=#{startTime},toolId=#{toolId},taskName=#{taskName},taskDes當(dāng)我們調(diào)?updateTask?法時(shí),task對(duì)象的各個(gè)屬性都會(huì)被傳?。但是這些屬性中,有很多并沒有發(fā)變動(dòng),是沒有必要被?志系統(tǒng)記錄的??梢?,下層切?的特點(diǎn)是:反映真實(shí)數(shù)據(jù)變動(dòng),脫離業(yè)務(wù)邏輯。因此,下層切??法直接采?。2.3混合切?上層切?和下層切?都不能單獨(dú)使?,這意味著我們不可能使??個(gè)簡(jiǎn)單的切?完成?志操作。那最終怎么解決呢?使?混合“切?”,即吸收下層切?的準(zhǔn)確性、整合上層切?的業(yè)務(wù)邏輯信息,并順便解決舊對(duì)象的獲取問題。對(duì)“切?”加引號(hào)是因?yàn)檫@不是?個(gè)絕對(duì)純粹的切?,它對(duì)業(yè)務(wù)邏輯存在?定的侵?性。但這是沒有辦法的。我們需要在業(yè)務(wù)邏輯中增加??類似下?的代碼:logClient.logXXX(params...);?于這?代碼如何寫,后?的邏輯如何,我們后?細(xì)化。但是我們知道,這?代碼中傳?的參數(shù)要既包含上層信息也包含下層信息。以下層信息為主(因?yàn)樗鼫?zhǔn)確),以上層信息為輔(因?yàn)樗瑯I(yè)務(wù)信息)。如下圖所?。接下來我們會(huì)?步?步介紹其實(shí)現(xiàn)。3對(duì)象屬性對(duì)?功能實(shí)現(xiàn)我們說道在下??法中,獲得的信息以下層信息為主,以上層信息為輔。那我們先說下層信息,顯然就是數(shù)據(jù)庫(kù)中的?對(duì)象和修改后的新對(duì)象,因此,其?參形式如下:logClient.logObject(oldObject,newObject);?在處理?志的第?步,就是找出新對(duì)象和?對(duì)象之間屬性的不同。假設(shè)tool對(duì)象的屬性如下:toolId:編號(hào)toolName:?具名稱price:價(jià)格position:存放位置要想把新舊兩個(gè)tool對(duì)象的屬性不同找出來,可以使?類似下?的代碼。//對(duì)??具的名稱toolNameif(!oldTool.getToolName().equals(newTool.getToolName())){log.add("toolName",diff(oldTool.getToolName(),newTool.getToolNam這種代碼可以實(shí)現(xiàn)功能,但是…僅僅適?于tool對(duì)象。如果換成了task對(duì)象,則?要重新寫?套。假設(shè)task對(duì)象的屬性如下:taskId:編號(hào)userId:責(zé)任?編號(hào)startTime:開始時(shí)間toolId:需要的?具的編號(hào)taskName:任務(wù)名taskDescription:任務(wù)描述那是不是只能根據(jù)task對(duì)象的屬性再寫?套if……如果你真的就是打算使?上述的?法記錄?志,那我已經(jīng)沒有什么可以教你的了。你要做的就是提升??Ctrl+C和Ctrl+V的速度,努?成為?個(gè)真正的CV?神直到頂級(jí)CRUD?程師。?志模塊的使?場(chǎng)景不同,要處理的對(duì)象(即oldObject和newObject)千奇百怪。因此,上?的這種代碼顯然也是不可取的。所以說,我們要?動(dòng)分析對(duì)象的屬性不同,然后記錄。即將對(duì)象拆解開來,逐?對(duì)?兩個(gè)對(duì)象(來?同?個(gè)類)的各個(gè)屬性,然后將不同的記錄下來。顯然,要?反射。那這個(gè)問題就解決了,如果對(duì)反射不了解的,可以學(xué)習(xí)反射相關(guān)知識(shí)。這些?較基本,我就不贅述了。使?反射之后,我們要記錄新?對(duì)象的變動(dòng)則只需要如下調(diào)?:logClient.logObject(oldObj,newObj);然后在這個(gè)?法中采?反射找出對(duì)象的各個(gè)屬性,然后依次進(jìn)??對(duì)。其實(shí)現(xiàn)代碼如下:/***?較兩個(gè)任意對(duì)象的屬性不同*@paramoldObj第?個(gè)對(duì)象*@paramnewObj第?個(gè)對(duì)象*@return兩個(gè)對(duì)象的屬性不同*/publicstaticMapdiffObj(Objectold這樣,下層的新?對(duì)象信息就處理完成了。我們可以在?法中通過參數(shù)補(bǔ)充?些上層業(yè)務(wù)信息。因此,上述?法可以修改為:logClient.logObject("操作?法","操作?法別名","觸發(fā)該操作的?戶等其他信息",oldObj,newObj);logObject?法就是我們要實(shí)現(xiàn)的?法,其核?操作邏輯就是分析對(duì)?新對(duì)象和舊對(duì)象的不同,將不同記錄下來,作為此次操作引發(fā)的變動(dòng)。4對(duì)象屬性處理我們已經(jīng)介紹了實(shí)現(xiàn)新舊對(duì)象屬性?對(duì)的基本實(shí)現(xiàn)邏輯,但是?切并沒有這么簡(jiǎn)單。因?yàn)?,?duì)象的屬性本?就?常復(fù)雜。例如,有些屬性(例如userId)是對(duì)其他對(duì)象的引?,把它們寫??志會(huì)讓?覺著摸不著頭腦(例如應(yīng)該換成?戶姓名或?號(hào));有些屬性(例如富?本)則?分復(fù)雜,在寫??志前需要進(jìn)?特殊的處理。在這?節(jié),我們將介紹這些特殊的屬性處理邏輯。4.1普通屬性當(dāng)我們?較出新?對(duì)象的屬性時(shí),有?些屬性可以直接計(jì)??志。直接記錄為“從{oldValue}修改為{newValue}”的形式即可。例如,tool對(duì)象的價(jià)格,可以計(jì)?為:price:從47修改為51其中47是屬性的舊值,51是屬性的新值。4.2特殊屬性但是有?些屬性不可以,例如長(zhǎng)?本。我們采?新值舊值的形式記錄其變動(dòng)是不合理的。例如:description:從“今天天?好\n真好\n哈哈嘿嘿哈哈”修改為“今天天?好\n哈哈嘿嘿哈哈”這種形式顯然很難看、很難懂。我們想要的結(jié)果應(yīng)該是:description:刪除了第2?“真好”這時(shí),我們可以設(shè)置?種機(jī)制,對(duì)復(fù)雜?本的屬性進(jìn)?特殊的處理。最終得到下?的結(jié)果。這樣?來,效果是不是好多了。在具體實(shí)現(xiàn)上,我們可以使?注解來標(biāo)明?個(gè)屬性的值需要特殊處理的類型,如下:@LogTag(innerType=InnerType.FullText)privateStringdescription;這樣,我們?cè)?志模塊設(shè)計(jì)機(jī)制,識(shí)別出InnerType.FullText的屬性后使?富?本處理?式對(duì)其進(jìn)?新舊值的?對(duì)處理。當(dāng)然,這種機(jī)制不僅適?于富?本,還有?些其他的屬性,例如圖?。我們可以引?新舊圖?的地址進(jìn)?展?。4.3業(yè)務(wù)屬性還有?種屬性,更為特殊。task對(duì)象中的責(zé)任?。我們采?下?的?式記錄顯然不太友好:userId:從4修改為5在task對(duì)象的userId屬性中存放的是?戶編號(hào),4、5都是?戶編號(hào)。但在?志中我們更希望看到?員姓名??墒?戶編號(hào)到姓名信息?志模塊是沒有的。因此,這時(shí)候我們需要業(yè)務(wù)模塊實(shí)現(xiàn)?志模塊提供的接?,來完成上述映射。得到如下結(jié)果:userId:從“王?丫”修改為“李?笨”不只是userId,還有toolId等各種業(yè)務(wù)屬性也適?這種處理?式。這樣處理還帶了?個(gè)優(yōu)點(diǎn):解耦。當(dāng)?個(gè)?志系統(tǒng)記錄下某個(gè)?志時(shí),例如,記錄下“?明刪除了?件A”時(shí),即使業(yè)務(wù)系統(tǒng)將?明的userId和?李的userId互換,則?志系統(tǒng)也不能將?志變?yōu)椤?李刪除了?件A”。因此,?志系統(tǒng)中的數(shù)據(jù)應(yīng)該是?經(jīng)落庫(kù)?刻封存。在具體實(shí)現(xiàn)上,我們可以使?注解來標(biāo)明?個(gè)屬性的值需要由業(yè)務(wù)系統(tǒng)輔助處理,如下:@LogTag(extendedType="userIdType")privateintuserId;這樣,我們?cè)?志模塊設(shè)計(jì)機(jī)制,識(shí)別出userId屬性后使?userIdType處理?式調(diào)?業(yè)務(wù)模塊提供的接?對(duì)其進(jìn)?新舊值的?對(duì)處理。5易?性注解經(jīng)過上?的處理,我們已經(jīng)能夠拿到類似下?的?志結(jié)果:userId:從“王?丫”修改為“李?笨”description:刪除了第2?“真好”price:從47修改為51其形式已經(jīng)不錯(cuò)了。但是這?的userId、description、price是?個(gè)屬性名,當(dāng)給?戶展?時(shí),?戶并不知道其確切含義。因此,我們需要提升其易?性。在具體實(shí)現(xiàn)上,我們可以使?注解來標(biāo)明?個(gè)屬性的值需要由業(yè)務(wù)系統(tǒng)輔助處理,如下:@LogTag(alias="責(zé)任?",extendedType="userIdType")privateintuserId;@LogTag(alias="說明",innerType=InnerType.FullText)privateStringdescription;然后在?志模塊中,我們對(duì)注解進(jìn)?處理,可以得到下?形式的?志信息:責(zé)任?:從“王?丫”修改為“李?笨”說明:刪除了第2?“真好”價(jià)格:從47修改為51這樣,整個(gè)?志的輸出形式就?較友好了。6存儲(chǔ)設(shè)計(jì)獲取了對(duì)象的不同之后,我們應(yīng)該將其存儲(chǔ)起來。顯然,最簡(jiǎn)單的:CREATETABLE`log`(`objectId`varchar(500)NOTNULLDEFAULT'',`operationName`varchar(500)NOTNULL,`diff`varchar(5000)DEFAULTNULL這樣就記錄了objectId的對(duì)象因?yàn)閛perationName操作發(fā)?了diff的變動(dòng)。然后把下?的?字作為?個(gè)完整的字符串存?diff字段中。責(zé)任?:從“王?丫”修改為“李?笨”說明:刪除了??“真好”價(jià)格:從47修改為51如果你真的打算使?上述的?法記錄?志,那我已經(jīng)沒有什么可以教你的了。沒,開玩笑。這個(gè)不?于,因?yàn)檫@個(gè)只是考慮不全?導(dǎo)致的個(gè)?問題。我們不能使?diff就簡(jiǎn)簡(jiǎn)單單地將各個(gè)屬性雜糅在?起,將原本結(jié)構(gòu)化的數(shù)據(jù)變?yōu)榱?結(jié)構(gòu)化的數(shù)據(jù)。我們可以采?操作表+屬性表的形式來存儲(chǔ)。?次操作會(huì)操作?個(gè)對(duì)象,這些都記錄到操作表中;這次操作會(huì)變更多個(gè)屬性,這些都記錄到屬性表中。進(jìn)?步,我們可以在操作表中記錄被操作對(duì)象的類型,這樣,防?不同對(duì)象具有相同的id?混淆。?且,我們還可以設(shè)置?個(gè)appName字段,從?使得這個(gè)?志模塊可以供多個(gè)應(yīng)?共?,成為?個(gè)獨(dú)?的?志應(yīng)?。我們也可以在記錄操作名“startTask”的同時(shí)記錄下其別名“開始任務(wù)”,等等。從?全?提升?志模塊的功能性、易?性。同樣的,屬性表中我們可以記錄各個(gè)屬性的類型,便于我們進(jìn)?分別的展?。記錄屬性的舊值、新值、前后變化等。不多說了,我直接給出兩個(gè)表的DDL:CREATETABLE`operation`(`id

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論