自定义注解实现日志功能

介绍:现在做的项目,需要通过aop实现添加日志功能,在需要的方法上加注解即可对该方法执行拦截并添加日志

1.      添加相关依赖

<spring.version>4.1.7.RELEASE</spring.version>
<aspectj.version>1.6.8</aspectj.version>
<!—springaop相关—>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<!—aspectj相关—>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>

2.编写自定义注解类

package com.sen.log;

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;

@Target({ElementType.PARAMETER, ElementType.METHOD}) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
public @interface Log {

	/**方法描述*/
	public String  methodDesc() default "";

}
3.编写日志实体类,用于保存到数据库
package com.sen.pojo;

import java.util.Date;

/**
 * ClassName: SystemLog
 * 
 * @Description: 日志实体类
 * @author shaosen
 * @date 2018年5月9日
 */
public class SystemLog {

	/**唯一标识*/
	private String id;
	/**方法描述*/
	private String description;
	/**方法名*/
	private String method;
	/**请求ip*/
	private String requestIp;
	/**异常code*/
	private String exceptioncode;
	/**异常描述*/
	private String exceptionDetail;
	/**创建日期*/
	private Date createDate;
	/**请求参数*/
	private String params;

	public String getParams() {
		return params;
	}

	public void setParams(String params) {
		this.params = params;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getMethod() {
		return method;
	}

	public void setMethod(String method) {
		this.method = method;
	}

	public String getRequestIp() {
		return requestIp;
	}

	public void setRequestIp(String requestIp) {
		this.requestIp = requestIp;
	}

	public String getExceptioncode() {
		return exceptioncode;
	}

	public void setExceptioncode(String exceptioncode) {
		this.exceptioncode = exceptioncode;
	}

	public String getExceptionDetail() {
		return exceptionDetail;
	}

	public void setExceptionDetail(String exceptionDetail) {
		this.exceptionDetail = exceptionDetail;
	}


	public Date getCreateDate() {
		return createDate;
	}

	public void setCreateDate(Date createDate) {
		this.createDate = createDate;
	}

	@Override
	public String toString() {
		return "SystemLog [id=" + id + ", description=" + description + ", method=" + method + ", requestIp="
				+ requestIp + ", exceptioncode=" + exceptioncode + ", exceptionDetail=" + exceptionDetail
				+ ", createDate=" + createDate + "]";
	}

	

}
4.编写日志切面
package com.sen.log;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.UUID;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import com.sen.pojo.SystemLog;

/**
 * ClassName: LogAdvice
 * 
 * @Description: 日志切面
 * @author shaosen
 * @date 2018年5月9日
 */
@Aspect
@Component
public class LogAdvice {
	
	private Logger log = Logger.getLogger(LogAdvice.class);

	/** 配置切入点 */
	@Pointcut("execution(* com.sen.controller..*.*(..))")
	public void controllerAspect() {
	}

	/**
	 * @Description: 后置通知
	 * @param @param joinPoint
	 * @param @throws ClassNotFoundException
	 * @return void
	 * @throws @author shaosen
	 * @date 2018年5月9日
	 */
	@After("controllerAspect()")
	public void after(JoinPoint joinPoint) {

		try {
			String ip = "127.0.0.1";
			String username = "peter";

			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 methodDesc = "";
			String params = "";
			for (Method method : methods) {
				if (method.getName().equals(methodName)) {
					Class[] clazzs = method.getParameterTypes();
					if (clazzs.length == arguments.length) {

						if (!method.isAnnotationPresent(Log.class))
							return;
						// 获取注解字段
						methodDesc = method.getAnnotation(Log.class).methodDesc();
						// 获取参数
						for (int i = 0; i < arguments.length; i++) {
							params = params + arguments[i] + (i == arguments.length - 1 ? "" : ",");
						}

						break;
					}
				}
			}
			// 控制台输出
			log.info("*******Log start*******");
			log.info("请求方法:"
					+ (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
			log.info("方法描述:" + methodDesc);
			log.info("请求人:" + username);
			log.info("请求IP:" + ip);
			log.info("请求参数:" + params);

			// 写入数据库
			log.info("*写入数据库*");
			SystemLog syslog = new SystemLog();
			syslog.setId(UUID.randomUUID().toString().replaceAll("-", ""));
			syslog.setMethod(joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()");
			syslog.setDescription(methodDesc);
			syslog.setRequestIp(ip);
			syslog.setExceptioncode(null);
			syslog.setExceptionDetail(null);
			syslog.setCreateDate(new Date());
			syslog.setParams(params);
			// TODO

			log.info("*写入数据库完成*");
			log.info("*******Log end*******");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * @Description: 异常通知
	 * @param @param joinPoint
	 * @param @param e
	 * @return void
	 * @throws ClassNotFoundException
	 * @throws                        @author shaosen
	 * @date 2018年5月9日
	 */
	@AfterThrowing(pointcut = "controllerAspect()", throwing = "e")
	public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
		/*
		 * HttpServletRequest request = ((ServletRequestAttributes)
		 * RequestContextHolder.getRequestAttributes()).getRequest(); HttpSession
		 * session = request.getSession(); //读取session中的用户 User user = (User)
		 * session.getAttribute(WebConstants.CURRENT_USER); //获取请求ip String ip =
		 * request.getRemoteAddr();
		 */
		// 获取用户请求方法的参数并序列化为JSON格式字符串

		String ip = "127.0.0.1";
		String username = "peter";

		try {
			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 methodDesc = "";
			String params = "";
			for (Method method : methods) {
				if (method.getName().equals(methodName)) {
					Class[] clazzs = method.getParameterTypes();
					if (clazzs.length == arguments.length) {

						if (!method.isAnnotationPresent(Log.class))
							return;

						methodDesc = method.getAnnotation(Log.class).methodDesc();
						// 获取参数
						for (int i = 0; i < arguments.length; i++) {
							params = params + arguments[i] + (i == arguments.length - 1 ? "" : ",");
						}
						break;
					}
				}
			}

			// 控制台数据
			log.info("*******ExceptionLog start*******");
			log.info("请求方法:"
					+ (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
			log.info("方法描述:" + methodDesc);
			log.info("异常代码:" + e.getClass().getName());
			log.info("异常信息:" + e.getMessage());
			log.info("请求人:" + username);
			log.info("请求IP:" + ip);
			log.info("请求参数:" + params);

			// 写入数据库
			log.info("*写入数据库*");
			SystemLog syslog = new SystemLog();
			syslog.setId(UUID.randomUUID().toString().replaceAll("-", ""));
			syslog.setMethod(
					joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()");
			syslog.setDescription(methodDesc);
			syslog.setRequestIp(ip);
			syslog.setExceptioncode(e.getClass().getName());
			syslog.setExceptionDetail(e.getMessage());
			syslog.setCreateDate(new Date());
			syslog.setParams(params);

			// save
			log.info("*写入数据库完成*");
			log.info("*******ExceptionLog end*******");
		} catch (ClassNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (SecurityException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

	}
}




6.spring配置文件,需要开启aop注解扫描

<!-- 开启aop包扫描 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>


7.controller如下

package com.sen.controller;
import org.springframework.stereotype.Controller;

import com.sen.log.Log;
import com.sen.log.MyLog;

@Controller
public class UserController {

//	private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(UserController.class);
	
	
	
	
	
	@Log(methodDesc="添加用户")
	public void addUser(String username,String password) {
		System.out.println("用户保存了。。。");
//		MyLog.info("test save");
		
	}
	
	@Log(methodDesc="查询用户")
	public void findUser(String id) {
		int i = 1/0;
		System.out.println("查询用户。。。");
	}
	
	public void deleteUser() {
		System.out.println("user already deleted...");
	}
	
}

8.编写测试类

package com.sen.test;

import org.apache.log4j.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.sen.controller.UserController;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:spring/spring*")
public class LogTest {

	
	@Autowired
	private UserController userController;
	
	@Test
	public void test() {
		
		userController.addUser("zhangsan","18");
		userController.findUser("11");
		userController.deleteUser();
	}

}

9.测试结果如下:

16:58:00,964  INFO DefaultTestContextBootstrapper:256 - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
16:58:00,980  INFO DefaultTestContextBootstrapper:182 - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@29e54f45, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@db75080, org.springframework.test.context.support.DirtiesContextTestExecutionListener@7e060a88, org.springframework.test.context.transaction.TransactionalTestExecutionListener@3e9da75b, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@6056677a]
16:58:01,083  INFO XmlBeanDefinitionReader:317 - Loading XML bean definitions from file [D:\workspace\aoptest\target\classes\spring\spring-core.xml]
16:58:02,662  INFO XmlBeanDefinitionReader:317 - Loading XML bean definitions from file [D:\workspace\aoptest\target\classes\spring\spring-mvc.xml]
16:58:02,691  INFO GenericApplicationContext:510 - Refreshing org.springframework.context.support.GenericApplicationContext@129e76f3: startup date [Fri May 11 16:58:02 CST 2018]; root of context hierarchy
用户保存了。。。
16:58:03,038  INFO LogAdvice:76 - *******Log start*******
16:58:03,038  INFO LogAdvice:77 - 请求方法:com.sen.controller.UserController.addUser()
16:58:03,038  INFO LogAdvice:79 - 方法描述:添加用户
16:58:03,038  INFO LogAdvice:80 - 请求人:peter
16:58:03,039  INFO LogAdvice:81 - 请求IP:127.0.0.1
16:58:03,039  INFO LogAdvice:82 - 请求参数:zhangsan,18
16:58:03,039  INFO LogAdvice:85 - *写入数据库*
16:58:03,050  INFO LogAdvice:97 - *写入数据库完成*
16:58:03,050  INFO LogAdvice:98 - *******Log end*******
16:58:03,051  INFO LogAdvice:76 - *******Log start*******
16:58:03,051  INFO LogAdvice:77 - 请求方法:com.sen.controller.UserController.findUser()
16:58:03,052  INFO LogAdvice:79 - 方法描述:查询用户
16:58:03,052  INFO LogAdvice:80 - 请求人:peter
16:58:03,052  INFO LogAdvice:81 - 请求IP:127.0.0.1
16:58:03,052  INFO LogAdvice:82 - 请求参数:11
16:58:03,052  INFO LogAdvice:85 - *写入数据库*
16:58:03,052  INFO LogAdvice:97 - *写入数据库完成*
16:58:03,053  INFO LogAdvice:98 - *******Log end*******
16:58:03,053  INFO LogAdvice:159 - *******ExceptionLog start*******
16:58:03,053  INFO LogAdvice:160 - 请求方法:com.sen.controller.UserController.findUser()
16:58:03,053  INFO LogAdvice:162 - 方法描述:查询用户
16:58:03,053  INFO LogAdvice:163 - 异常代码:java.lang.ArithmeticException
16:58:03,053  INFO LogAdvice:164 - 异常信息:/ by zero
16:58:03,053  INFO LogAdvice:165 - 请求人:peter
16:58:03,053  INFO LogAdvice:166 - 请求IP:127.0.0.1
16:58:03,053  INFO LogAdvice:167 - 请求参数:11
16:58:03,054  INFO LogAdvice:170 - *写入数据库*
16:58:03,054  INFO LogAdvice:183 - *写入数据库完成*
16:58:03,054  INFO LogAdvice:184 - *******ExceptionLog end*******
16:58:03,081  INFO GenericApplicationContext:862 - Closing org.springframework.context.support.GenericApplicationContext@129e76f3: startup date [Fri May 11 16:58:02 CST 2018]; root of context hierarchy

注意:使用AOP拦截不到SpringMVC的Controller层的解决方法 

最后找到一种方法, 将Controller的代理权交给cglib, 解决了这个问题,如下:
  1. ApplicatonContext.xml中启动@AspectJ注解支持
  2. springMVC.xml中通知spring使用cglib而不是jdk来生成代理方法

<!-- 启动对@AspectJ注解的支持 -->
< aop:aspectj-autoproxy />


<!-- 通知spring使用 cglib 而不是 jdk 的来生成代理方法,这样 AOP可以拦截到Controller -->
< aop:aspectj-autoproxy proxy-target-class = "true" />



猜你喜欢

转载自blog.csdn.net/csdn_ss1991/article/details/80281930