Heim  >  Artikel  >  Java  >  Java-Entwicklungspraxis: SpringMVC verwendet AOP zum Verwalten von Zugriffsprotokollen

Java-Entwicklungspraxis: SpringMVC verwendet AOP zum Verwalten von Zugriffsprotokollen

无忌哥哥
无忌哥哥Original
2018-07-20 10:51:102927Durchsuche

1. Beschreibung

Vor Kurzem hatte ich die Idee, eine persönliche Website zu erstellen, und begann spontan eine Programmierreise. Machen Sie es einfach. Nachdem das Projekt-Framework (SpringMVC+mybatis+mysql) erstellt wurde, beginnen Sie über das Design des Protokolls im Projekt nachzudenken. Nach Überlegung und in Kombination mit Online-Informationen haben wir uns entschieden, Anmerkungen zum Aufzeichnen von Zugriffsprotokollen zu verwenden. Natürlich ist das aktuelle Protokolldesign noch nicht perfekt und wird im Laufe des Entwicklungsprozesses schrittweise verbessert.

2. Implementierung

2.1 Über AOP und verwandte Kommentare

Im Vergleich zu AOP bevorzugen viele Menschen die Verwendung von Interception Ein Server zum Verwalten von Protokollen. Dies hängt von Ihren persönlichen Vorlieben ab. Wie implementiert man den AOP-Interception-Controller? Da der Controller standardmäßig als Proxy an JDK übergeben wird, muss AOP den Controller daher dem cglib-Proxy zuweisen, wenn er ihn abfangen kann.

Das Folgende ist eine Einführung in die vom AOP-Interception-Controller verwendeten Annotationen (die rot markierten Felder stellen diejenigen dar, die verwendet werden). Natürlich können wir auch Konfigurationsdateien verwenden, um sie zu definieren, aber ich persönlich bevorzuge Um die Module zu gruppieren, ist es wirklich ermüdend, die Konfigurationsdatei zu finden ~

@Target: Der Zweck der Annotation, d. Enthält:

Elementtype. .Constructor Constructor

Elementtype.

                           RetentionPolicy.                                                                                                                                     Anmerkungen werden in der Klassenbytecodedatei beibehalten Zur Laufzeit abgerufen. Die Annotation „RetentionPolicy.RUNTIME“ ist in der Klassenbytecodedatei vorhanden und kann abgerufen werden durch Reflexion zur Laufzeit. 🎜>

@Document: Dies bedeutet, dass die Anmerkung in oben in den Kommentaren in Javadoc enthalten ist, plus @ inherited,@reinaatable

>

Annotationen werden in Java als Meta-Annotationen bezeichnet. Was sind Meta-Anmerkungen?

Die Rolle von Meta-Anmerkungen besteht darin, andere Anmerkungen zu kommentieren. Java5.0 definiert vier Standard-Meta-Annotationstypen, die zur Beschreibung anderer Annotationstypen verwendet werden.

Für eine Erläuterung von Annotationen und Meta-Annotationen klicken Sie bitte hier

@Aspect: Wenn @Aspect für eine Klasse deklariert wird, bedeutet dies, dass diese Klasse als Aspekt verwendet wird ist eine Aspektklasse. Zu diesem Zeitpunkt kann der Container diese Klasse lesen, jedoch nur, wenn der cglib-Agent aktiviert ist.

@Component: Deklarieren Sie die Klasse als Bean und injizieren Sie sie in den Container. Spring scannt und lädt sie beim Start. Der Effekt ist derselbe wie beim Definieren der Bean in der Konfigurationsdatei.

@Pointcut: Annotation auf Methodenebene Nach Verwendung dieser Annotation kann von anderen Methoden darauf verwiesen werden.

Es gibt 5 Benachrichtigungsanmerkungen, die mit @Aspect und @Pointcut verwendet werden und auch erweiterte Annotationen genannt werden:

                                       Die Methode -Leiterin, verwenden Sie die Rückkehr, um auf den Methodenrückgabewert '' Out '' s 1 Way Out Out Out Out Through Avhe Through Ray Out Out Out Out Out Out Out Out Out Out Out Out Out Out Out Out Out Out Out Out Out Out Out Out Out Out of Out Out Out) aus Ofto After-To also so- w-i's tossing to base,        Surround-Benachrichtigung, an der Spitze der Methode platziert, bestimmt diese Methode die tatsächliche Methode Ob sie ausgeführt werden soll, und es muss ein Rückgabewert vorhanden sein

2.2 cglib-Agent konfigurieren

Fügen Sie den folgenden Code zur Datei spring-mvc.xml hinzu:

<aop:aspectj-autoproxy proxy-target-class="true" />

2.3 Benutzerdefinierte Anmerkungen zur Beschreibung von Protokollinformationen

Wenn wir benutzerdefinierte Anmerkungen erstellen, führt die Verwendung von @interface im Allgemeinen dazu, dass diese Klasse standardmäßig Anmerkungen erbt. Der Code lautet wie folgt:

package com.t1heluosh1.system.log.annotion;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 日志controller层注解
 * 
 * @author xuyong
 *
 */
//作用于参数和方法上
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysControllerLog {

	int logType() default 100;				//日志类型,默认为100-系统
	
	int module() default 100;				//操作模块,默认为100-登录
	
	String description() default "";		//操作描述
}
Nachdem die benutzerdefinierte Annotation erstellt wurde, müssen wir die Annotation als Bean in den Container einfügen und den folgenden Code zur Datei spring-mvc.xml hinzufügen:

<context:component-scan base-package="com.t1heluosh1.system.log" >
         <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

2.4 Definieren Sie Aspektklassen, um die Protokollierungsfunktion zu implementieren

Hier gibt es nichts mehr zu sagen, schauen Sie sich einfach den Code an:

package com.t1heluosh1.system.log.aspect;

import java.lang.reflect.Method;
import java.util.Date;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.t1heluosh1.pullulate.biz.sysLog.service.SysLogService;
import com.t1heluosh1.pullulate.biz.sysLog.vo.SysLogVo;
import com.t1heluosh1.pullulate.biz.user.model.User;
import com.t1heluosh1.system.constant.SysParams;
import com.t1heluosh1.system.log.annotion.SysControllerLog;
import com.t1heluosh1.util.IPUtil;


/**
 * 日志切点类即实现类
 * 
 * @author xuyong
 *
 */
@Aspect  
@Component 
public class SysLogAspect {

	//本地异常日志记录对象
	private static final Logger logger = Logger.getLogger(SysLogAspect.class);
	
	@Resource
	private SysLogService logService;
	
	
	//切入点定义:controller
	@Pointcut("@annotation(com.t1heluosh1.system.log.annotion.SysControllerLog)")
	public void controllerAspect() {
		System.out.println("---------------------controllerAspect for log start----------------------------");
	}
	
	
	
	/**
	 * controller切入点方法实现
	 * 
	 * @param joinPoint
	 */
	@Before("controllerAspect()")
	public void doBefore(JoinPoint joinPoint) {
		 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder  
	                .getRequestAttributes()).getRequest();
		 
		 //获取登录用户的信息
		 User user = (User)request.getSession().getAttribute(SysParams.CURRENT_USER);
		 
		 //获取请求IP地址
		 String ip = IPUtil.getRemoteHost(request);
		 
		 try {
			 String methodDesc = getControllerMethodDescription(joinPoint);
			 System.out.println("request method : " + joinPoint.getTarget().getClass().getName()+"."+joinPoint.getSignature().getName()+"()");
			 System.out.println("method description : " + methodDesc);
			 System.out.println("request username : " + (user==null?"no login info found":user.getUserName()));
			 
			 System.out.println("request ip address : "+ ip);
			 
			 System.out.println("insert log infos into db start ...");
			 
			 //获取相关日志参数
			 Object[] orgs = joinPoint.getArgs();
			 SysLogVo sysLogVo = null;
			 if (orgs != null && orgs.length > 0) {
				 for (Object obj:orgs) {
					 if (obj instanceof SysLogVo)
						 sysLogVo = (SysLogVo)obj;
					 
				 }
			 }
			 if (sysLogVo == null) {
				 sysLogVo = new SysLogVo();
			 }
			 //执行日志入库操作
			 
			 //获取注解的信息
			 MethodSignature ms = (MethodSignature)joinPoint.getSignature();
			 Method method = ms.getMethod();
			 SysControllerLog log = method.getAnnotation(SysControllerLog.class);
			 sysLogVo.setLogType(log.logType());
			 sysLogVo.setModule(log.module());
			 sysLogVo.setIpAddr(ip);
			 sysLogVo.setUrl(request.getRequestURI());
			 sysLogVo.setMethodName(joinPoint.getTarget().getClass().getName()+"."+joinPoint.getSignature().getName()+"()");
			 sysLogVo.setMethodDesc(methodDesc);
			 //TODO:remark可根据业务来进行改变,暂时为方法描述
			 sysLogVo.setRemark(log.description());
			 Date date = new Date();
			 sysLogVo.setAddTime(date);
			 sysLogVo.setAddUser(user==null?SysParams.ADMIN_ID:String.valueOf(user.getId()));
			 sysLogVo.setUpdateTime(date);
			 sysLogVo.setUpdateUser(user==null?SysParams.ADMIN_ID:String.valueOf(user.getId()));
			 logService.save(sysLogVo);
			 System.out.println("insert log infos into db successful.");
		 } catch (Exception e) {
			 logger.error("--------------controllerAspect for log fail-----------------------");  
	         logger.error("exception info : ", e);  
		 }
		 
	}
	
	 
	/**
	 * 获取方法的描述
	 * 
	 * @param joinPoint
	 * @return
	 * @throws Exception 
	 */
	@SuppressWarnings("rawtypes")
	private String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
		 //获取目标类名  
        String targetName = joinPoint.getTarget().getClass().getName();  
        //获取方法名  
        String methodName = joinPoint.getSignature().getName();  
        //获取相关参数  
        Object[] arguments = joinPoint.getArgs();  
        //生成类对象  
        Class targetClass = Class.forName(targetName);  
        //获取该类中的方法  
        Method[] methods = targetClass.getMethods();  
          
        String description = "";  
          
        for(Method method : methods) {  
            if(!method.getName().equals(methodName)) {  
                continue;  
            }  
            Class[] clazzs = method.getParameterTypes();  
            if(clazzs.length != arguments.length) {  
                continue;  
            }  
            description = method.getAnnotation(SysControllerLog.class).description();  
        }  
        return description;  
	}
	
	
}

2.5 Verwendung demo

Die spezifische Methode ist wie folgt:

/**
	 * 跳转到登陆页面
	 * 
	 * @param request
	 * @return
	 * @throws Exception 
	 */
	@RequestMapping(value="login")
	@SysControllerLog(description="跳转到登录页面",logType=100,module=100)
	public ModelAndView gotoLogin(HttpServletRequest request) {
		ModelAndView modelAndView = new ModelAndView("/show/login");
		return modelAndView;
	}
Wenn der Benutzer die Seite aktualisiert, druckt die Konsole die relevanten Zugriffsinformationen und speichert diese Informationen in der Datenbank. Natürlich muss die Verwendung von Protokollen je nach Projekt entschieden werden. Erstens beeinträchtigt dies die Leistung des Systems und verringert zweitens die Protokollierung auf diese Weise der Code bis zu einem gewissen Grad sexuell. Werfen Sie abschließend einen Blick auf die in der Datenbank erfassten Informationen:

Das obige ist der detaillierte Inhalt vonJava-Entwicklungspraxis: SpringMVC verwendet AOP zum Verwalten von Zugriffsprotokollen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn