Maison  >  Article  >  Java  >  Pratique de développement Java : springMVC utilise AOP pour gérer les journaux d'accès

Pratique de développement Java : springMVC utilise AOP pour gérer les journaux d'accès

无忌哥哥
无忌哥哥original
2018-07-20 10:51:102927parcourir

1. Description

Récemment, j'ai eu l'idée de créer un site Web personnel et j'ai commencé un parcours de programmation en un clin d'œil. Faites-le. Une fois le framework du projet (SpringMVC+mybatis+mysql) construit, commencez à réfléchir à la conception du journal dans le projet. Après réflexion et en combinaison avec des informations en ligne, nous avons décidé d'utiliser des annotations pour enregistrer les journaux d'accès. Bien entendu, la conception actuelle des journaux n’est pas encore parfaite et sera progressivement améliorée au cours du processus de développement.

2. Mise en œuvre

2.1 À propos de l'AOP et des commentaires associés

Par rapport à l'AOP, de nombreuses personnes préfèrent utiliser l'interception. un serveur pour gérer les journaux. Cela dépend des préférences personnelles. Alors, comment implémenter le contrôleur d’interception AOP ? Puisque par défaut, le contrôleur est confié à jdk pour le proxy, donc si AOP peut intercepter le contrôleur, il doit être attribué au proxy cglib.

Ce qui suit est une introduction aux annotations utilisées par le contrôleur d'interception AOP (les champs marqués en rouge représentent celles qui seront utilisées Bien sûr, on peut aussi utiliser des fichiers de configuration pour les définir, mais personnellement je préfère). pour regrouper les modules. , c'est vraiment fatigant de trouver le fichier de configuration~

@Target : Le but de l'annotation, c'est-à-dire sur quels objets l'annotation aura un effet. Comprend:

elementType. Variables                                                                                                    .                               ElementType.PACKAGE                                                                                                                                                                                          L'annotation Retention est chargée de définir la portée ou les conditions dans lesquelles l'annotation prendra effet.

                                                                                                                         à conserver. obtenue au moment de l'exécution.

L'annotation RetentionPolicy.RUNTIME existera dans le fichier de bytecode de la classe et pourra être obtenue. par réflexion au moment de l'exécution. 🎜> @Docume : Cela signifie que l'annotation sera incluse dans Javadoc

au-dessus des annotations, plus @inherited > Les annotations sont appelées méta-annotations en Java. Que sont les méta-annotations ?

Le rôle des méta-annotations est d'annoter d'autres annotations. Java5.0 définit quatre types de méta-annotations standard, qui sont utilisés pour fournir des descriptions d'autres types d'annotations.

Pour une explication des annotations et méta-annotations, veuillez cliquer ici

@Aspect : Lorsque @Aspect est déclaré sur une classe, cela indique que cette classe sera utilisée comme aspect, que c'est-à-dire une classe d'aspect. A ce moment, le conteneur peut lire cette classe, mais seulement si l'agent cglib est activé.

@Component : Déclarez la classe comme bean et injectez-la dans le conteneur. Spring l'analysera et la chargera au démarrage. L'effet est le même que celui de la définition du bean dans le fichier de configuration.

@Pointcut : annotation au niveau de la méthode Après avoir utilisé cette annotation, elle peut être référencée par d'autres méthodes.

Il existe 5 annotations de notification utilisées avec @Aspect et @Pointcut, également appelées annotations améliorées :

                                      Pré-notification, avant l'exécution de la méthode Exécution avant @AfterReturning Post [try] notification, activez-la l'en-tête de la méthode, utilisez return pour faire référence à la valeur de retour de la méthode                                                                                                                                   '     '                                                                                    dehors, dehors, dehors out Ofto After-To so so- w-i's to jeter à la base,        Notification Surround, placée en tête de la méthode, cette méthode détermine si la méthode réelle doit être exécutée, et il doit y avoir une valeur de retour

2.2 Configurer l'agent cglib

Ajoutez le code suivant au fichier spring-mvc.xml :

2.3 Annotations personnalisées, utilisées pour décrire les informations du journal

Généralement, lorsque nous créons des annotations personnalisées, l'utilisation de @interface fera que cette classe héritera de l'annotation par défaut. Le code est le suivant :

Une fois l'annotation personnalisée créée, nous devons injecter l'annotation dans le conteneur en tant que bean et ajouter le code suivant au fichier spring-mvc.xml :

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

2.4 Définir les classes d'aspect pour implémenter la fonction de journalisation

Il n'y a rien d'autre à dire ici, il suffit de regarder le code :

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 "";		//操作描述
}

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

La méthode spécifique est la suivante :

Lorsque l'utilisateur actualise la page, la console imprimera les informations d'accès pertinentes et les stockera informations dans la base de données. Bien entendu, l'utilisation des journaux doit être décidée en fonction du projet. Des annotations sont ajoutées avant chaque méthode. Premièrement, cela affecte les performances du système et réduit considérablement l'effet des journaux d'accès. Deuxièmement, l'enregistrement des journaux de cette manière reste une intrusion ; le code dans une certaine mesure. Enfin, jetez un œil aux informations enregistrées dans la base de données :

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;  
	}
	
	
}

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn