1. Обзор
В общих системах, когда мы выполняем некоторые важные операции, такие как вход в систему, добавление пользователей, удаление пользователей и т. Д., Мы должны сохранять такое поведение. В этой статье мы реализуем вставку журнала через пользовательские аннотации Spring Aop и Java. Это решение имеет меньше вторжения в исходный бизнес и более гибко в реализации
2. Определения связанных классов журналов
Мы абстрагируем журнал в два класса: функциональный модуль и тип работы
Используйте классы перечисления для определения модулетипа типа функционального модуля, таких как студент и пользовательский модуль
public enum moduletype {default ("1"), // Значение по умолчанию ("2"), // Студенческий модуль учитель ("3"); // пользовательский модуль Private ModuleType (String Index) {this.Module = index; } частный строковый модуль; public String getModule () {return this.module; }}Используйте класс перечисления, чтобы определить тип операции: EventType. Например, вход, добавление, удаление, обновление, удаление и т. Д.
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; } private String Event; Приватное название строки; public String getEvent () {return this.event; } public String getName () {return name; }}3. Определите аннотации, связанные с журналом,
3.1. @Logenable
Здесь мы определяем количество переключателя журнала. Только когда это значение верно в классе, функция журнала в этом классе будет включена.
@Документально @hareveration (artententionpolicy.runtime) @target ({elementtype.type}) public @Interface Logenable { / ** * Если True, логическое значение ниже класса будет включено, иначе * @Return * / boolean logenable () default true;}3.2. @Logevent
Определение журнала здесь. Если эта аннотация аннотирована в классе, этот параметр используется в качестве значения по умолчанию для всех методов класса. Если аннотация находится на методе, она будет работать только для этого метода
@Документирован@hareveration (armentpolicy.runtime) @target ({java.lang.annotation.elementtype.method, elementtype.type}) public @Interface logEvent {moduleType module () default moduleType.default; // модуль, к которому журнал принадлежит eventType event () default eventtype.default; // журнал тип события string desc () по умолчанию ""; // Описание Информация}3.3. @Logkey
Если эта аннотация находится на методе, параметры всего метода сохраняются в формате журнала в JSON. Если эта аннотация аннотирована как на методе, так и на классе, аннотация на методе перезаписывает значение в классе.
@Target ({elementtype.field, elementtype.parameter})@haretention(retentionpolicy.runtime)@documentedPublic @Interface Logkey {String KeyName () default ""; // Имя ключа логии isuserid () по умолчанию false; // Является ли это поле пользователем этой операции, здесь пропущено логическое islog () по умолчанию true; // Будь то добавлено в журнал}4. Определить класс обработки журнала
4.1. Logadmmodel
Определите класс, который содержит информацию о журнале
открытый класс logadmmodel {private long id; Private String userId; // управлять пользователем частной строки имени пользователя; частная строка Admmodel; // модуль частной строки admevent; // Операция частная дата создана; // Операция содержимого частной строки AdmoptContent; // Операция содержимого частного строки desc; // Замечание SET/GET OPIT}4.2. Илогманагер
Определите класс интерфейса ilogmanager для обработки журнала
Мы можем сохранить журналы в базе данных или отправлять журналы для открытия промежуточного программного обеспечения, если Redis, MQ и т. Д. Каждый класс обработки журнала является классом реализации этого интерфейса
Публичный интерфейс ilogmanager { / *** Модуль обработки журнала* @param paramlogadmbean* / void deallog (logadmomodel paramlogadmbean);}4.3. Dblogmanager
Класс реализации Ilogmanager для хранения журналов. Только смоделированное хранилище здесь
@Servicepublic class dblogmanager реализует ilogmanager {@override public void deallog (logadmmodel paramlogadmbean) {System.out.println («Хранить журнал в базу данных, содержимое журнала следующим образом:« + json.tojSonsting (paramlogadmbean)); }}5. Конфигурация AOP
5.1. LogAspect определяет класс AOP
Аннотировать этот класс @Asepe
Используйте @pointcut, чтобы определить методы пакета и класса для перехвата
Мы используем @Around для определения метода
@Component @AspectPublic Class LogAspect {@Autowired Private LoginFogeneration LoginFogeneration; @Autowired частный Ilogmanager Logmanager; @Pointcut ("execution (*com.hry.spring.mvc.aop.log.service ..*.*(..)") ") public void managerlogpoint () {} @Around (" ManagerLogPoint () ") public mananagerlogpoint (areyingjoinpoint jp) throwsable {…. }} Around Managerlogpoint: основной бизнес -процесс основного метода
1. Проверьте, аннотируется ли класс метода перехвата @Logenable. Если это так, будет выполнена логика журнала, в противном случае будет выполнена нормальная логика.
2. Проверьте, является ли метод перехвата @logevent. Если это так, будет соблюдаться логика журнала, в противном случае будет выполнена нормальная логика.
3. Получите среднее значение @LogeVent на основе метода получения и генерируйте некоторые параметры журнала. Значение @logevent определено в классе как значение по умолчанию
4. Вызовите LoginFogeneration ProcessManagerLogmessage, чтобы заполнить другие параметры в журнале. Мы поговорим об этом методе позже.
5. выполнять обычные деловые звонки
6. Если выполнение успешно, Logmanager выполняет журнал (мы записываем только журналы успешного выполнения здесь, и вы также можете определить журналы неудачной записи)
@Around ("ManagerLogPoint ()") public oblog Managerlogpoint (resportingjoinpoint jp) бросает {class target = jp.getTarget (). GetClass (); // Получить логируемый logenable logenable = (logenable) target.getannotation (logenable.class); if (logenable == null ||! logenable.logenable ()) {return jp.proecd (); } // Получить logEvent в классе как значение значения по умолчанию logEventClass = (logEvent) target.getannotation (logevent.class); Метод метод = getInvokedMethod (JP); if (method == null) {return jp.proecd (); } // Получить LogEvent в методе logEvent LogEventMethod = method.getAnnotation (logevent.class); if (logEventMethod == null) {return jp.proecd (); } 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 = new logadmmodel (); logbean.setadmomodel (optmodel); logbean.setadmevent (Optevent); logbean.setDesc (desc); logbean.setCreatedate (new Date ()); LoginFogeneration.ProcessingManagerLogmessage (JP, Logbean, Method); Object returnObj = jp.proecd (); if (optevent.equals (eventtype.login)) {// todo Если он вошел в систему, вам нужно судить, успешно ли она на основе возврата. Если это успешно, добавьте журналы. Суждение здесь относительно простое if (returnobj! = Null) {this.logmanager.deallog (logbean); }} else {this.logmanager.deallog (logbean); } return returnObj; } / ** * Получить метод запроса * * @param jp * @return * / public method getInvokedMethod (joinpoint jp) {// Параметры списка методов вызова classlist = new ArrayList (); for (Object obj: jp.getargs ()) {classlist.add (obj.getClass ()); } Class [] argscls = (class []) classlist.toarray (новый класс [0]); // вызываемый метод имени string methodname = jp.getSignature (). GetName (); Метод метод = null; try {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); Обновление void (StudentModel StudentModel); void QueryById (String Id);}6.2. Студент HerviceImpl:
@Logenable: @logevent определяет все методы модуля в классе перехвата журнала запуска. Другая информация о @logeven определяет журнал. @Service @logenable // start class inteppt @logevent (module = moduletype.student) открытый класс. System.out.printf (this.getClass () + "deleteByid id =" + id); } @Override @logevent (event = eventtype.add, desc = "Сохранить запись") // Добавить идентификатор журнала public int save (studentModel StudentModel) {System.out.printf (this.getClass () + "Сохранить =" + json.tojsonstring (studentModel)); возврат 1; } @Override @logevent (event = eventType.update, desc = "update record") // Добавить идентификатор журнала public void update (StudentModel StudentModel) {System.out.printf (this.getClass () + "Сохранить Update =" + json.tojSonsting (studentModel)); } // Нет идентификатор журнала @Override public void QueryByID (String Id) {System.out.printf (this.getClass () + "QueryByID ID =" + id); }}Выполните тестовый класс и распечатайте следующую информацию, чтобы указать, что наша конфигурация аннотации журнала включена:
Сохраните журналы в базе данных, а содержимое журнала следующее:
{"Admevent": "4", "Admmodel": "1", "Admoptcontent": "{/" id/":/" 1/"}", "Создан": 15257797381111, "desc": "Удалить запись"}7. Код
См. Ниже подробный код выше
Код GitHub, пожалуйста, попробуйте использовать тег v0.21, не используйте Master, потому что я не могу гарантировать, что основной код останется неизменным