Home  >  Article  >  Java  >  Java development practice: springMVC uses AOP to manage access logs

Java development practice: springMVC uses AOP to manage access logs

无忌哥哥
无忌哥哥Original
2018-07-20 10:51:102887browse

1. Explanation

Recently, the idea of ​​making a personal website sprouted in my mind, and I started a programming journey at the drop of a hat. Just do it. After the project framework (SpringMVC mybatis mysql) is built, start thinking about the design of the log in the project. After consideration and combined with online information, we decided to use annotations to record access logs. Of course, the current log design is not perfect yet and will be gradually improved during the development process.

2. Implementation

2.1 About AOP and related comments

Compared with AOP, many people prefer to use interception Use a server to manage logs. This depends on personal preference. So how to implement AOP interception controller? Since by default, the controller is handed over to jdk for proxy, therefore, if AOP can intercept the controller, it must be assigned to the cglib proxy.

The following is an introduction to using AOP to intercept the annotations used by the controller (fields marked in red represent those that will be used). Of course, we can also use configuration files to define them, but personally I prefer to group the modules together. , it’s really tiring to find the configuration file~

@Target: The purpose of the annotation, that is, which objects the annotation will have an effect on. Including:

# ElementType.Type interface, class, enumeration, annotation

# ElementType.field field, enumerated constant

## Elementtype.method method

                                                                                                                                                                 ElementType.CONSTRUCTOR                                   Constructor

                                                                         ElementType. LOCAL_VARIABLE                                                                                                 using           using ’ s ’ using ’ s ’       through ’ ’s ‐ ‐ ‐ ‐ ‐‐ ‐ ‐ ​ ​ ​ ​ ​ ​ ​ ​ ​ 1 ElementType.PACKAGE                                                                                                                                          ElementType. The Retention annotation is responsible for defining the scope or conditions under which the annotation will take effect.                              RetentionPolicy.SOURCE                                                                                                                                                                                 RetentionPolicy.CLASS Default retention policy, annotations will exist in class bytecode files, But it cannot be obtained at runtime.

@Document: It means that the annotation will be included in Javadoc

or above, plus

@inherited,@Repeatable

############################################################################################################################################################## # ###Annotations are called meta-annotations in java. What are meta-annotations? ###

The role of meta-annotations is to annotate other annotations. Java5.0 defines four standard meta-annotation types, which are used to provide descriptions of other annotation types.

On the explanation of annotations and meta annotations, please click here

# @aspect: When the @Aspect statement and class are on, it indicates that this class will be used as a cut surface, that is, the cut classes. At this time, the container can read this class, but only if the cglib agent is turned on.

@Component: Declare the class as a bean and inject it into the container. Spring will scan and load it at startup. The effect is the same as defining the bean in the configuration file.

@Pointcut: Method-level annotation. After using this annotation, it can be referenced by other methods.

and@aspect,@PointCut also have 5 notification type annotations, also known as enhanced annotations:

#@before Professor notification, execute in the method method execution Execute before

## Place it on the method head and use returning to refer to the method return value

@aFTERTHROWING Rear [CATCH] notification, put it on the method header, use throwing to quote the abnormal abnormality

@Around surround notification, put it on the method header, this method must determine the real method of the real method Whether to execute, and there must be a return value

2.2 Configure cglib agent

Add the following code to the spring-mvc.xml file:

2.3 Custom annotations, used to describe log information

Generally when we create custom annotations, using @interface will cause this class to inherit annotation by default. The code is as follows:

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

After the custom annotation is created, we need to inject the annotation into the container as a bean and add the following code to the spring-mvc.xml file:


         
    

2.4 Define aspect classes to implement the logging function

There is nothing more to say here, just look at the code:

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 Using demo

The specific method used is as follows:

/**
	 * 跳转到登陆页面
	 * 
	 * @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;
	}

When the user refreshes the page, the console will print the relevant access information and store this information in the database. Of course, the use of logs needs to be decided according to the project. Annotations are added before each method. First, it affects the performance of the system and greatly reduces the effect of access logs; second, recording logs in this way still has a certain intrusion into the code. sexual. Finally, take a look at the information recorded in the database:

The above is the detailed content of Java development practice: springMVC uses AOP to manage access logs. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn