1. ภาพรวม
ในระบบทั่วไปเมื่อเราทำการดำเนินการที่สำคัญเช่นการเข้าสู่ระบบในระบบเพิ่มผู้ใช้การลบผู้ใช้ ฯลฯ เราต้องคงพฤติกรรมเหล่านี้ไว้ ในบทความนี้เราใช้การแทรกบันทึกผ่านคำอธิบายประกอบที่กำหนดเองของ Spring AOP และ Java โซลูชันนี้มีการบุกรุกน้อยลงกับธุรกิจดั้งเดิมและมีความยืดหยุ่นมากขึ้นในการตระหนัก
2. คำจำกัดความคลาสที่เกี่ยวข้องของบันทึก
เราสรุปบันทึกลงในสองคลาส: โมดูลการทำงานและประเภทการทำงาน
ใช้คลาสการแจงนับเพื่อกำหนดโมดูลประเภทโมดูลฟังก์ชันเช่นโมดูลนักเรียนและผู้ใช้
Public Enum ModuleType {ค่าเริ่มต้น ("1"), // นักเรียนค่าเริ่มต้น ("2"), // ครูโมดูลนักเรียน ("3"); // โมดูลผู้ใช้โมดูลส่วนตัว (ดัชนีสตริง) {this.module = ดัชนี; } โมดูลสตริงส่วนตัว; สตริงสาธารณะ getModule () {return this.module; -ใช้คลาสการแจงนับเพื่อกำหนดประเภทของการดำเนินการ: EventType เช่นเข้าสู่ระบบ, เพิ่ม, ลบ, อัปเดต, ลบ ฯลฯ
public enum eventtype {default ("1", "ค่าเริ่มต้น"), เพิ่ม ("2", "เพิ่ม"), อัปเดต ("3", "อัปเดต"), delete_single ("4", "ลบ-ร้อง"), เข้าสู่ระบบ ("10", "ล็อกอิน"), login_out ("11", "login_out"); EventType ส่วนตัว (ดัชนีสตริงชื่อสตริง) {this.name = name; this.event = ดัชนี; } เหตุการณ์สตริงส่วนตัว; ชื่อสตริงส่วนตัว; สตริงสาธารณะ getEvent () {return this.event; } สตริงสาธารณะ getName () {ชื่อคืน; -3. กำหนดคำอธิบายประกอบที่เกี่ยวข้องกับบันทึก
3.1. @logenable
ที่นี่เรากำหนดปริมาณสวิตช์ของบันทึก เฉพาะเมื่อค่านี้เป็นจริงในคลาสฟังก์ชั่นบันทึกในคลาสนี้จะเปิดใช้งาน
@documented @retention (RetentionPolicy.runtime) @Target ({elementType.type}) สาธารณะ @interface logenable { / ** * ถ้าเป็นจริง logevent ด้านล่างคลาสจะเปิดใช้งานมิฉะนั้น * @return * / boolean logenable () จริง3.2. @logevent
คำจำกัดความของบันทึกที่นี่ หากคำอธิบายประกอบนี้มีคำอธิบายประกอบบนคลาสพารามิเตอร์นี้จะใช้เป็นค่าเริ่มต้นสำหรับวิธีทั้งหมดของคลาส หากคำอธิบายประกอบอยู่ในวิธีนี้จะใช้ได้กับวิธีนี้เท่านั้น
@documented@retention (RetentionPolicy.runtime) @Target ({java.lang.annotation.elementType.method, ElementType.type}) สาธารณะ @Interface LogEvent {ModuleType Module () ModuleType.default; // โมดูลที่บันทึกเป็นเหตุการณ์ EventType () EventType.default เริ่มต้น; // บันทึกประเภทเหตุการณ์สตริง desc () default ""; // คำอธิบายข้อมูล}3.3. @logkey
หากคำอธิบายประกอบนี้อยู่ในวิธีการพารามิเตอร์ของวิธีทั้งหมดจะถูกบันทึกลงในรูปแบบการเข้าสู่ระบบในรูปแบบ JSON หากคำอธิบายประกอบนี้มีคำอธิบายประกอบทั้งวิธีและคลาสการเพิ่มความคิดเห็นของวิธีการจะเขียนทับค่าในชั้นเรียน
@Target ({ElementType.field, ElementType.Parameter})@retention(retentionPolicy.runtime)@documentedPublic @interface logkey {String Keyname () ค่าเริ่มต้น ""; // ชื่อของคีย์บูลีน isuserid () เท็จเริ่มต้น; // ไม่ว่าจะเป็นฟิลด์นี้เป็นผู้ใช้ของการดำเนินการนี้หรือไม่ที่นี่จะถูกละเว้นบูลีน islog () ค่าเริ่มต้นจริง; // ไม่ว่าจะถูกเพิ่มลงในบันทึก}4. กำหนดคลาสการประมวลผลบันทึก
4.1. logadmmodel
กำหนดคลาสที่เก็บข้อมูลบันทึก
คลาสสาธารณะ Logadmmodel {ID ส่วนตัวส่วนตัว; ผู้ใช้สตริงส่วนตัว // ใช้ชื่อผู้ใช้สตริงส่วนตัวชื่อผู้ใช้; สตริงส่วนตัว admmodel; // โมดูลสตริงส่วนตัวผู้ประกอบการ; // การดำเนินการวันที่ส่วนตัวสร้างขึ้น; // การดำเนินการเนื้อหาสตริงส่วนตัว admoptcontent; // การดำเนินการเนื้อหาสตริงส่วนตัว desc; // หมายเหตุชุด/รับ}4.2. IlogManager
กำหนดคลาสอินเตอร์เฟส ilogManager สำหรับการประมวลผลบันทึก
เราสามารถจัดเก็บบันทึกในฐานข้อมูลหรือส่งบันทึกเพื่อเปิดมิดเดิลแวร์หาก Redis, MQ ฯลฯ คลาสการประมวลผลล็อกแต่ละคลาสเป็นคลาสการใช้งานของอินเทอร์เฟซนี้
อินเตอร์เฟสสาธารณะ ilogManager { / *** โมดูลการประมวลผลบันทึก* @param paramlogadmbean* / void deallog (logadmmodel paramlogadmbean);}4.3. dblogmanager
IlogManager คลาสการใช้งานเพื่อจัดเก็บบันทึก เฉพาะที่เก็บจำลองที่นี่
@ServicePublic คลาส DBLOGMANAGER ใช้ ILOGMANAGER {@Override โมฆะสาธารณะ deallog (logadmmodel paramlogadmbean) {system.out.println ("เก็บบันทึกลงในฐานข้อมูลเนื้อหาบันทึกดังต่อไปนี้:" + json.tojsonstring (paramlogadmbean); -5. การกำหนดค่า AOP
5.1. logaspect กำหนดคลาส AOP
ใส่คำอธิบายประกอบคลาสนี้ด้วย @aspect
ใช้ @pointcut เพื่อกำหนดแพ็คเกจและวิธีการเรียนเพื่อสกัดกั้น
เราใช้ @around เพื่อกำหนดวิธีการ
@component @appectpublic คลาส logaspect {@autowired private loginfogeneration loginfogeneration; @autowired ส่วนตัว IlogManager LogManager; @PointCut ("Execution (*com.hry.spring.mvc.aop.log.service ..*.*(.. ))") โมฆะสาธารณะ ManagerLogpoint () {} @Around ("ManagerLogPoint ()") วัตถุสาธารณะรอบ ๆ - รอบ MANMANAGERLOGPOINT: กระบวนการทางธุรกิจหลักของวิธีการหลัก
1. ตรวจสอบว่าคลาสของวิธีการสกัดกั้นนั้นมีคำอธิบายประกอบโดย @logenable หรือไม่ ถ้าเป็นเช่นนั้นลอจิกล็อกจะถูกติดตามมิฉะนั้นตรรกะปกติจะถูกดำเนินการ
2. ตรวจสอบว่าวิธีการสกัดกั้นเป็น @logevent หรือไม่ ถ้าเป็นเช่นนั้นลอจิกล็อกจะถูกติดตามมิฉะนั้นตรรกะปกติจะถูกดำเนินการ
3. รับค่ามัธยฐานของ @logevent ตามวิธีการรับและสร้างพารามิเตอร์บางอย่างของบันทึก ค่าของ @logevent ถูกกำหนดไว้ในคลาสเป็นค่าเริ่มต้น
4. การโทรหา processManagerlogMessage ของ LoginFogeneration เพื่อเติมพารามิเตอร์อื่น ๆ ในบันทึก เราจะพูดถึงวิธีนี้ในภายหลัง
5. ดำเนินการโทรธุรกิจปกติ
6. หากการดำเนินการสำเร็จ LogManager จะดำเนินการบันทึก (เราจะบันทึกบันทึกการดำเนินการที่ประสบความสำเร็จที่นี่เท่านั้นและคุณยังสามารถกำหนดบันทึกของการบันทึกที่ล้มเหลว)
@Around ("ManagerLogPoint ()") วัตถุสาธารณะรอบ ๆ MANMANAGERLOGPOINT (ดำเนินการ jppoint jp) โยน {class target = jp.getTarget (). getClass (); // รับ logenable logenable logenable = (logenable) target.getAnnotation (logenable.class); if (logenable == null ||! logenable.logenable ()) {return jp.proceed (); } // รับ logeVent ในคลาสเป็นค่าเริ่มต้น logeVent logEventClass = (logEvent) target.getAnnotation (logeVent.class); วิธีการ = getInvokedMethod (JP); if (method == null) {return jp.proceed (); } // รับ logeVent บนวิธีการ logeVent logEventMethod = method.getAnnotation (logeVent.class); if (logeVentMethod == null) {return jp.proceed (); } string opteVent = logEventMethod.event (). getEvent (); String OptModel = LogEventMethod.Module (). getModule (); String desc = logeventmethod.desc (); if (LogEventClass! = null) {// ถ้าค่าบนวิธีนี้เป็นค่าเริ่มต้นให้แทนที่ด้วยค่าทั่วโลก opteVent = opteVent.equals (EventType.default)? logeventclass.event (). getEvent (): opteVent; OptModel = OptModel.equals (ModuleType.default)? LogEventClass.Module (). getModule (): optModel; } logadmmodel logbean = ใหม่ logadmmodel (); logbean.setadmmodel (OptModel); logbean.setadmevent (opteVent); logbean.setdesc (DESC); logbean.setCreatedate (วันที่ใหม่ ()); LoginFogeneration.ProcessingManagerLogMessage (JP, LogBean, วิธีการ); Object returnobj = jp.proceed (); ถ้า (opteVent.equals (EventType.login)) {// todo ถ้ามีการลงชื่อเข้าใช้คุณต้องตัดสินว่าจะประสบความสำเร็จตามค่าผลตอบแทนหรือไม่ หากประสบความสำเร็จให้เพิ่มบันทึก คำพิพากษาที่นี่ค่อนข้างง่ายถ้า (returnobj! = null) {this.logmanager.deallog (logebean); }} else {this.logmanager.deallog (logebean); } returnOrtionObj; } / ** * รับวิธีการร้องขอ * * @param jp * @return * / วิธีการสาธารณะ getInvokedMethod (JoinPoint jp) {// พารามิเตอร์ของวิธีการโทรรายการรายการคลาสคลาส = new ArrayList (); สำหรับ (Object obj: jp.getargs ()) {classlist.add (obj.getclass ()); } คลาส [] argscls = (คลาส []) classlist.toarray (คลาสใหม่ [0]); // ชื่อเมธอดที่เรียกว่าเมธอดนิเมเมเมนต์ = jp.getSignature (). getName (); วิธีการ = null; ลอง {method = jp.getTarget (). getClass (). getMethod (MethodName, ArgsCls); } catch (nosuchmethodexception e) {e.printstacktrace (); } วิธีการส่งคืน; -6. วิธีแก้ปัญหาการใช้โซลูชันข้างต้นในทางปฏิบัติ
ที่นี่เราจำลองธุรกิจของนักเรียนและใช้คำอธิบายประกอบข้างต้นเพื่อนำไปใช้กับพวกเขาและสกัดกั้นบันทึก
6.1. Istudentservice
คลาสอินเตอร์เฟสธุรกิจดำเนินการทั่วไป CRUD
อินเตอร์เฟสสาธารณะ istudentservice {void deleteById (string id, string a); int save (นักเรียนโมเดลโมเดล); การอัปเดตเป็นโมฆะ (StudentModel StudentModel); เป็นโมฆะ queryById (String ID);}6.2. Studentserviceimpl:
@logenable: @logevent กำหนดวิธีโมดูลทั้งหมดในคลาสการสกัดกั้นบันทึกการเริ่มต้น ข้อมูลอื่น ๆ เกี่ยวกับ @logeven กำหนดบันทึก @service @logenable // เริ่มการสกัดกั้นบันทึก @logevent (module = moduleType.student) นักศึกษาระดับสาธารณะ enterviceimpl ดำเนินการ istudentservice {@Override @LogeVent (Event = EventType.delete_single, desc = "delete Record") System.out.printf (this.getClass () + "DELETEBYID ID =" + ID); } @Override @LogeVent (Event = EventType.add, desc = "บันทึกบันทึก") // เพิ่มบันทึกการบันทึกสาธารณะ save (StudentModel StudentModel) {System.out.printf กลับ 1; } @Override @LogeVent (Event = EventType.Update, Desc = "Update Record") // เพิ่มบันทึกการอัปเดตสาธารณะบันทึกการอัปเดตสาธารณะ (StudentModel StudentModel) {System.out.printf (this.getClass () + "บันทึกอัปเดต =" } // ไม่มีตัวระบุบันทึก @Override โมฆะสาธารณะ queryById (รหัสสตริง) {system.out.printf (this.getClass () + "queryById id =" + id); -ดำเนินการคลาสทดสอบและพิมพ์ข้อมูลต่อไปนี้เพื่อระบุว่าเปิดใช้งานการกำหนดค่าคำอธิบายประกอบบันทึกของเรา:
จัดเก็บบันทึกลงในฐานข้อมูลและเนื้อหาบันทึกมีดังนี้:
{"AdmeVent": "4", "AdmModel": "1", "AdmopTcontent": "{/" id/":/" 1/"}", "Creadate": 1525779738111, "Desc": "ลบบันทึก"}}}7. รหัส
ดูด้านล่างสำหรับรหัสโดยละเอียดด้านบน
รหัส GitHub โปรดลองใช้ TAG V0.21 อย่าใช้ Master เพราะฉันไม่สามารถรับประกันได้ว่ารหัสต้นแบบจะยังคงไม่เปลี่ยนแปลง