1. Présentation
Dans les systèmes généraux, lorsque nous effectuons des opérations importantes, telles que la connexion au système, l'ajout d'utilisateurs, la suppression des utilisateurs, etc., nous devons persister ces comportements. Dans cet article, nous implémentons l'insertion de journaux par le biais d'annotations personnalisées de Spring AOP et Java. Cette solution a moins d'intrusion pour l'entreprise d'origine et est plus flexible pour réaliser
2. Définitions de classe connexes des journaux
Nous abstraions la connexion en deux classes: module fonctionnel et type d'opération
Utilisez des classes d'énumération pour définir le module de module de module de fonction, tels que l'élève et le module d'utilisateur
Public Enum moduleType {Default ("1"), // valeur par défaut Student ("2"), // Student Module Teacher ("3"); // Module utilisateur ModuleType privé (chaîne index) {this.module = index; } module de chaîne privée; public String getModule () {return this.module; }}Utilisez une classe d'énumération pour définir le type d'opération: EventType. Tels que la connexion, l'ajout, la suppression, la mise à jour, la suppression, etc.
public enum EventType {Default ("1", "Default"), Add ("2", "Add"), Update ("3", "Update"), Delete_Single ("4", "Delete-Single"), Login ("10", "Login"), Login_out ("11", "Login_out"); private EventType (String index, String Name) {this.name = name; this.event = index; } événement de chaîne privée; nom de chaîne privé; public String getEvent () {return this.event; } public String getName () {Nom de retour; }}3. Définir les annotations liées à la logarithme
3.1. @Logenable
Ici, nous définissons la quantité de commutation du journal. Uniquement lorsque cette valeur est vraie sur la classe, la fonction de journal de cette classe sera activée.
@ Documentée @ rétention (retentionPolicy.runtime) @target ({elementType.type}) public @Interface Logenable {/ ** * Si true, le logevent ci-dessous la classe sera activé, sinon * @return * / boolean logenable () par défaut;}3.2. @Logevent
Définition du journal ici. Si cette annotation est annotée sur la classe, ce paramètre est utilisé comme valeur par défaut pour toutes les méthodes de la classe. Si l'annotation est sur la méthode, cela ne fonctionnera que pour cette méthode
@ Documentée @ rétention (retentionPolicy.runtime) @target ({java.lang.annotation.elementType.Method, elementType.Type}) public @Interface LoGevent {modulape module () par défaut ModuleType.default; // Le module auquel le journal appartient à EventType Event () default EventType.Default; // Log Type d'événement String desc () par défaut ""; // Description Informations}3.3. @Logkey
Si cette annotation est sur une méthode, les paramètres de la méthode entière sont enregistrés au format JSON du journal. Si cette annotation est annotée à la fois sur la méthode et la classe, l'annotation sur la méthode écrase la valeur de la classe.
@Target ({elementType.field, elementType.Parameter}) @ rétention(retentionPolicy.runtime)@documendedpublic @interface logkey {String keyName () Default ""; // le nom de la clé booléenne iSUserID () par défaut false; // Si ce champ est l'utilisateur de cette opération, ici est omis booléen islog () par défaut True; // s'il est ajouté au journal}4. Définir la classe de traitement des journaux
4.1. Librètement
Définissez la classe qui contient des informations sur le journal
classe publique LogadMmodel {ID long privé; String privé utilisateur IDID; // Faire fonctionner le nom d'utilisateur de chaîne privée utilisateur; String privé Admmodel; // Module Private String Admivent; // Opération Date privée CréationDate; // Opération Contenu Private String AdmoptContent; // Operation Content Private String desc; // Remarquez / soyez omis}4.2. Ilogmanager
Définissez la classe d'interface IlogManager pour le traitement des journaux
Nous pouvons stocker des journaux dans la base de données, ou envoyer des journaux à ouvrir le middleware, si redis, mq, etc. Chaque classe de traitement de journal est une classe d'implémentation de cette interface
Interface publique IlogManager {/ ** * Module de traitement de journal * @param paramlogadmbbean * / void deallog (logadmmodel paramlogadmbbean);}4.3. Dblogmanager
Classe d'implémentation d'IlogManager pour stocker les journaux. Seule stockage simulé ici
@ServicePublic Classe DBlogManager implémente IlogManager {@Override public void DealLog (LogadmmOdel ParamlogAdMbean) {System.out.println ("Stockez le connexion à la base de données, le contenu du journal est comme suit:" + JSON.TOJSONSTRIGH (paramlogadMbean)); }}5. Configuration AOP
5.1. Logaspect définit la classe AOP
Annoter cette classe avec @aspect
Utilisez @PointCut pour définir le package et la méthode de classe pour intercepter
Nous utilisons @around pour définir la méthode
@ Component @ AspectPublic Class LogaSpect {@Autowired Private LoginfoGeeneration LoginFoGeeneration; @Autowired Private IlogManager Logmanager; @Pointcut ("EXECUTION (* com.hry.spring.mvc.aop.log.service .. *. * (..))") public void ManagerLogPoint () {} @around ("ManagerLogPoint ()") Objet public autour demanagerlogpoint (ProcedingJoinpoint JP) lance Throws {…. }} Autoundmanagerlogpoint: le processus commercial principal de la méthode principale
1. Vérifiez si la classe de la méthode d'interception est annotée par @Logenable. Si c'est le cas, la logique du journal sera suivie, sinon la logique normale sera exécutée.
2. Vérifiez si la méthode d'interception est @logevent. Si c'est le cas, la logique du journal sera suivie, sinon la logique normale sera exécutée.
3. Obtenez la valeur médiane de @LoGevent en fonction de la méthode d'obtention et générez certains paramètres du journal. La valeur de @logevent est définie sur la classe comme la valeur par défaut
4. Appelez ProcessManagerLogMessage de ProcessManagerLogMessage de LoginFoGeeneration pour remplir d'autres paramètres dans le journal. Nous parlerons de cette méthode plus tard.
5. Effectuer des appels commerciaux normaux
6. Si l'exécution est réussie, le logManager exécute le journal (nous enregistrons uniquement les journaux de l'exécution réussie ici, et vous pouvez également définir les journaux de l'enregistrement échoué)
@Around ("ManagerLogPoint ()") Objet public AroundManArLogPoint (ProcedingJoinpoint JP) lance Throwsable {class cible = jp.getTarget (). GetClass (); // Get Logenable Logenable Logenableable = (Logenable) Target.getAnnotation (Logenable.Class); if (logenable == null ||! Logenable.Logenable ()) {return jp.proceed (); } // Obtenez le logevent sur la classe comme valeur par défaut LOGEvent LOGEventClass = (LoGevent) Target.getAnTannotation (logevent.class); Méthode méthode = getInvokedMethod (jp); if (méthode == null) {return jp.proceed (); } // Obtenez le logevent sur la méthode 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) {// Si la valeur sur la méthode est la valeur par défaut, remplacez-la par la valeur globale. Optevent = optevent.equals (EventType.default)? logeventClass.event (). getEvent (): Optevent; optModel = optmodel.equals (moduleype.default)? logeventClass.module (). getModule (): optmodel; } Logadmmodel logBean = new LogadMmodel (); LogBean.SetAdMmodel (OptModel); Logbean.SetAdMevent (Optevent); Logbean.setDesc (DESC); logBean.setCreatEdate (new Date ()); LoginFoGeeneration.ProcessingManagerLogMessage (JP, Logbean, méthode); Objet returnObj = jp.proceed (); if (optevent.equals (eventType.login)) {// todo si elle est connectée, vous devez juger si elle réussit en fonction de la valeur de retour. S'il réussit, ajoutez des journaux. Le jugement ici est relativement simple if (returnObj! = Null) {this.logmanager.dealllog (logBean); }} else {this.logmanager.dealllog (logBean); } return returnObj; } / ** * Obtenez la méthode de la demande * * @param jp * @return * / Méthode publique getInvokedMethod (joinpoint jp) {// paramètres de la méthode d'appel classList = new ArrayList (); pour (objet obj: jp.getargs ()) {classList.add (obj.getClass ()); } Class [] argscls = (class []) classList.toArray (new class [0]); // Le nom de méthode appelée méthode méthodyname = jp.getSignature (). GetName (); Méthode méthode = null; essayez {méthode = jp.getTarget (). getClass (). getMethod (méthodyname, argscls); } catch (NosuchMethodexception e) {e.printStackTrace (); } méthode de retour; }}6. La solution pour appliquer la solution ci-dessus en pratique
Ici, nous simulons les affaires des étudiants et utilisons les annotations ci-dessus pour les appliquer et intercepter les journaux.
6.1. Service de service
Classe d'interface d'entreprise, exécuter General Crud
Interface publique IstudentService {void DeleteById (String ID, String A); int save (StudentModel StudentModel); Mise à jour void (StudentModel StudentModel); void queryByid (ID de chaîne);}6.2. StudentServiceImpl:
@Logenable: @Logevent définit toutes les méthodes de module @Logeven définit d'autres informations sur le log @ service @ logenable // Démarrer l'interception du journal @logevent (module = moduletype.student) classe publique StudentServiceImpl implémente IsTudentService {@Override @Logevent (event = eventType DeleteById (@LogKey (keyName = "id") String id, String A) {System.out.printf (this.getClass () + "DeleteById id =" + id); } @Override @Logevent (event = eventType.add, desc = "enregistre de sauvegarde") // Ajouter un identifiant de journal public int save (StudentModel StudentModel) {System.out.printf (this.getClass () + "Save Save =" + JSON.tojSontring (StudentModel)); retour 1; } @Override @logevent (event = eventType.update, desc = "Update Record") // Ajouter un identifiant de journal public Void Update (StudentModel StudentModel) {System.out.printf (this.getClass () + "Save Update =" + json.tojSontring (StudentModel)); } // pas d'identifiant de journal @Override public void queryByid (String id) {System.out.printf (this.getClass () + "queryById id =" + id); }}Exécutez la classe de test et imprimez les informations suivantes pour indiquer que notre configuration d'annotation de journal est activée:
Stockez les journaux dans la base de données et le contenu du journal est le suivant:
{"Admivent": "4", "Admmodel": "1", "AdmoptContent": "{/" id / ": /" 1 / "}", "CreateDate": 1525779738111, "DESC": "Delete Record"}7. Code
Voir ci-dessous pour le code détaillé ci-dessus
Code github, veuillez essayer d'utiliser la balise V0.21, n'utilisez pas de maître, car je ne peux pas garantir que le code maître restera inchangé