转载请注明出处:https://blog.csdn.net/l1028386804/article/details/80295737
1、定义日志类SystemLog
package io.mykit.annotation.spring.log.entity; import java.util.Date; /** * 定义日志实体信息 * @author liuyazhuang * */ public class SystemLog { private String id; private String description; private String method; private Long logType; private String requestIp; private String exceptioncode; private String exceptionDetail; private String params; private String createBy; private Date createDate; public String getId() { return id; } public void setId(String id) { this.id = id == null ? null : id.trim(); } public String getDescription() { return description; } public void setDescription(String description) { this.description = description == null ? null : description.trim(); } public String getMethod() { return method; } public void setMethod(String method) { this.method = method == null ? null : method.trim(); } public Long getLogType() { return logType; } public void setLogType(Long logType) { this.logType = logType; } public String getRequestIp() { return requestIp; } public void setRequestIp(String requestIp) { this.requestIp = requestIp == null ? null : requestIp.trim(); } public String getExceptioncode() { return exceptioncode; } public void setExceptioncode(String exceptioncode) { this.exceptioncode = exceptioncode == null ? null : exceptioncode.trim(); } public String getExceptionDetail() { return exceptionDetail; } public void setExceptionDetail(String exceptionDetail) { this.exceptionDetail = exceptionDetail == null ? null : exceptionDetail.trim(); } public String getParams() { return params; } public void setParams(String params) { this.params = params == null ? null : params.trim(); } public String getCreateBy() { return createBy; } public void setCreateBy(String createBy) { this.createBy = createBy == null ? null : createBy.trim(); } 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 + ", logType=" + logType + ", requestIp=" + requestIp + ", exceptioncode=" + exceptioncode + ", exceptionDetail=" + exceptionDetail + ", params=" + params + ", createBy=" + createBy + ", createDate=" + createDate + "]"; } }
2、定义SystemLogService接口
package io.mykit.annotation.spring.log.service; import io.mykit.annotation.spring.log.entity.SystemLog; /** * 日志的Service接口 * @author liuyazhuang * */ public interface SystemLogService { int deleteSystemLog(String id); int insert(SystemLog record); int insertTest(SystemLog record); SystemLog selectSystemLog(String id); int updateSystemLog(SystemLog record); }
3、接口实现类SystemLogServiceImpl
package io.mykit.annotation.spring.log.service.impl; import java.util.Date; import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import io.mykit.annotation.spring.log.entity.SystemLog; import io.mykit.annotation.spring.log.service.SystemLogService; @Service("systemLogService") public class SystemLogServiceImpl implements SystemLogService { private final Logger logger = LoggerFactory.getLogger(SystemLogServiceImpl.class); @Override public int deleteSystemLog(String id) { logger.info("deleteSystemLog===>>>" + id); return 1; } @Override public int insert(SystemLog record) { logger.info("insert===>>>" + record.toString()); return 1; } @Override public int insertTest(SystemLog record) { logger.info("insertTest===>>>" + record.toString()); return 1; } @Override public SystemLog selectSystemLog(String id) { logger.info("selectSystemLog===>>>" + id); SystemLog log = new SystemLog(); log.setId(UUID.randomUUID().toString()); log.setDescription("查询日志"); log.setMethod("selectSystemLog"); log.setLogType((long)0); log.setRequestIp("127.0.0.1"); log.setExceptioncode( null); log.setExceptionDetail( null); log.setParams( null); log.setCreateBy("刘亚壮"); log.setCreateDate(new Date()); return log; } @Override public int updateSystemLog(SystemLog record) { logger.info("updateSystemLog===>>>" + record.toString()); return 1; } }
4、自定义注解Log
package io.mykit.annotation.spring.log.provider; 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; /** * 自定义日志注解 * @author liuyazhuang * */ @Target({ElementType.PARAMETER, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Log { /** 要执行的操作类型比如:add操作 **/ public String operationType() default ""; /** 要执行的具体操作比如:添加用户 **/ public String operationName() default ""; }
5、实现注解解析器SystemLogAspect
package io.mykit.annotation.spring.log.aspect; import java.lang.reflect.Method; import java.util.Date; import java.util.UUID; import javax.annotation.Resource; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import com.alibaba.fastjson.JSONObject; import io.mykit.annotation.spring.log.entity.SystemLog; import io.mykit.annotation.spring.log.entity.User; import io.mykit.annotation.spring.log.provider.Log; import io.mykit.annotation.spring.log.service.SystemLogService; /** * 具体切片类的实现 * @author liuyazhuang * */ @Aspect @Component public class SystemLogAspect { //注入Service用于把日志保存数据库 @Resource //这里我用resource注解,一般用的是@Autowired,他们的区别如有时间我会在后面的博客中来写 private SystemLogService systemLogService; private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect. class); //Controller层切点 @Pointcut("execution (* io.mykit.annotation.spring.log.user.service..*.*(..))") public void controllerAspect() { } /** * 前置通知 用于拦截Controller层记录用户的操作 * * @param joinPoint 切点 */ @Before("controllerAspect()") public void doBefore(JoinPoint joinPoint) { System.out.println("==========执行controller前置通知==============="); if(logger.isInfoEnabled()){ logger.info("before " + joinPoint); } } //配置controller环绕通知,使用在方法aspect()上注册的切入点 @Around("controllerAspect()") public void around(JoinPoint joinPoint){ System.out.println("==========开始执行controller环绕通知==============="); long start = System.currentTimeMillis(); try { ((ProceedingJoinPoint) joinPoint).proceed(); long end = System.currentTimeMillis(); if(logger.isInfoEnabled()){ logger.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms!"); } System.out.println("==========结束执行controller环绕通知==============="); } catch (Throwable e) { long end = System.currentTimeMillis(); if(logger.isInfoEnabled()){ logger.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms with exception : " + e.getMessage()); } } } /** * 后置通知 用于拦截Controller层记录用户的操作 * * @param joinPoint 切点 */ @SuppressWarnings("rawtypes") @After("controllerAspect()") public void after(JoinPoint joinPoint) { /* HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); HttpSession session = request.getSession(); */ //读取session中的用户 // User user = (User) session.getAttribute("user"); //请求的IP //String ip = request.getRemoteAddr(); User user = new User(); user.setId(1); user.setName("刘亚壮"); String ip = "127.0.0.1"; 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 operationType = ""; String operationName = ""; for (Method method : methods) { if (method.getName().equals(methodName)) { Class[] clazzs = method.getParameterTypes(); if (clazzs.length == arguments.length) { if(method.isAnnotationPresent(Log.class)){ operationType = method.getAnnotation(Log.class).operationType(); operationName = method.getAnnotation(Log.class).operationName(); break; } } } } //*========控制台输出=========*// System.out.println("=====controller后置通知开始====="); System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")+"."+operationType); System.out.println("方法描述:" + operationName); System.out.println("请求人:" + user.getName()); System.out.println("请求IP:" + ip); //*========数据库日志=========*// SystemLog log = new SystemLog(); log.setId(UUID.randomUUID().toString()); log.setDescription(operationName); log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")+"."+operationType); log.setLogType((long)0); log.setRequestIp(ip); log.setExceptioncode( null); log.setExceptionDetail( null); log.setParams( null); log.setCreateBy(user.getName()); log.setCreateDate(new Date()); //保存数据库 systemLogService.insert(log); System.out.println("=====controller后置通知结束====="); } catch (Exception e) { //记录本地异常日志 logger.error("==后置通知异常=="); logger.error("异常信息:{}", e.getMessage()); } } //配置后置返回通知,使用在方法aspect()上注册的切入点 @AfterReturning("controllerAspect()") public void afterReturn(JoinPoint joinPoint){ System.out.println("=====执行controller后置返回通知====="); if(logger.isInfoEnabled()){ logger.info("afterReturn " + joinPoint); } } /** * 异常通知 用于拦截记录异常日志 * * @param joinPoint * @param e */ @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格式字符串 User user = new User(); user.setId(1); user.setName("刘亚壮"); String ip = "127.0.0.1"; String params = ""; if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) { for ( int i = 0; i < joinPoint.getArgs().length; i++) { // params += JsonUtil.getJsonStr(joinPoint.getArgs()[i]) + ";"; params += JSONObject.toJSONString(joinPoint.getArgs()[i]) + ";"; } } 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 operationType = ""; String operationName = ""; for (Method method : methods) { if (method.getName().equals(methodName)) { Class[] clazzs = method.getParameterTypes(); if (clazzs.length == arguments.length) { if(method.isAnnotationPresent(Log.class)){ operationType = method.getAnnotation(Log.class).operationType(); operationName = method.getAnnotation(Log.class).operationName(); break; } } } } /*========控制台输出=========*/ System.out.println("=====异常通知开始====="); System.out.println("异常代码:" + e.getClass().getName()); System.out.println("异常信息:" + e.getMessage()); System.out.println("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")+"."+operationType); System.out.println("方法描述:" + operationName); System.out.println("请求人:" + user.getName()); System.out.println("请求IP:" + ip); System.out.println("请求参数:" + params); /*==========数据库日志=========*/ SystemLog log = new SystemLog(); log.setId(UUID.randomUUID().toString()); log.setDescription(operationName); log.setExceptioncode(e.getClass().getName()); log.setLogType((long)1); log.setExceptionDetail(e.getMessage()); log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")); log.setParams(params); log.setCreateBy(user.getName()); log.setCreateDate(new Date()); log.setRequestIp(ip); //保存数据库 systemLogService.insert(log); System.out.println("=====异常通知结束====="); } catch (Exception ex) { //记录本地异常日志 logger.error("==异常通知异常=="); logger.error("异常信息:{}", ex.getMessage()); } /*==========记录本地异常日志==========*/ logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}", joinPoint.getTarget().getClass().getName() + joinPoint.getSignature().getName(), e.getClass().getName(), e.getMessage(), params); } }
6、实现User实体类
package io.mykit.annotation.spring.log.entity; /** * 测试AOP切面的类 * @author liuyazhuang * */ public class User { private Integer id; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User [id=" + id + ", name=" + name + "]"; } }
7、定义UserService接口
package io.mykit.annotation.spring.log.user.service; /** * 日志切面的UserService * @author liuyazhuang * */ public interface UserService { void addUser(); }
8、接口实现类UserServiceImpl
我们在这个类上加上了注解@Log(operationType="add操作", operationName = "添加用户")
package io.mykit.annotation.spring.log.user.service.impl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import io.mykit.annotation.spring.log.provider.Log; import io.mykit.annotation.spring.log.user.service.UserService; @Service("logUserService") public class UserServiceImpl implements UserService { private final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class); @Override @Log(operationType="add操作", operationName = "添加用户") public void addUser() { logger.info("执行了添加用户的操作"); } }
9、spring-log-annotation.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd" default-autowire="byName"> <mvc:annotation-driven /> <!-- 激活组件扫描功能,在包io.mykit.annotation.spring.log及其子包下面自动扫描通过注解配置的组件 --> <context:component-scan base-package="io.mykit.annotation.spring.log" /> <!-- 启动对@AspectJ注解的支持 --> <!-- proxy-target-class等于true是强制使用cglib代理,proxy-target-class默认是false,如果你的类实现了接口 就走JDK代理,如果没有走cglib代理 --> <!-- 注:对于单利模式建议使用cglib代理,虽然JDK动态代理比cglib代理速度快,但性能不如cglib --> <aop:aspectj-autoproxy proxy-target-class="true"/> <context:annotation-config /> <bean id="systemLogAspect" class="io.mykit.annotation.spring.log.aspect.SystemLogAspect"/> </beans>
10、测试类LogAnnotationTest
package io.mykit.annotation.spring.log.provider; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; import io.mykit.annotation.spring.log.user.service.UserService; /** * 测试日志注解信息 * @author liuyazhuang * */ public class LogAnnotationTest { @SuppressWarnings("resource") @Test public void testLogAnnotation(){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"spring/spring-log-annotation.xml"}); UserService userService = (UserService) context.getBean("logUserService"); userService.addUser(); } }
11、pom.xml的Jar包依赖
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <skip_maven_deploy>false</skip_maven_deploy> <jdk.version>1.8</jdk.version> <spring.version>4.1.0.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</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-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> <version>1.9.1</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.2</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib-nodep</artifactId> <version>2.1_3</version> </dependency> </dependencies>
12、log4j.properties
log4j.rootCategory=INFO,stdout,file,ERROR #log4j.rootCategory=ERROR,stdout,file log4j.appender.stdout=org.apache.log4j.ConsoleAppender #log4j.appender.stdout=org.apache.log4j.FileAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=[mykit-annotation-spring-provider]%d %p [%t] %C{1}.%M(%L) | %m%n #log4j.appender.file=org.apache.log4j.DailyRollingFileAppender #log4j.appender.file.MaxFileSize=100KB #log4j.appender.file.DatePattern = '.'yyyy-MM-dd'.log' log4j.appender.file=org.apache.log4j.DailyRollingFileAppender log4j.appender.file.File=/home/mykit/logs/mykit-annotation-spring-provider/mykit-annotation-spring-provider log4j.appender.file.DatePattern='.'yyyy-MM-dd'.log' log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} [%c-%L]-[%t]-[%p] %m%n
13、测试结果
==========开始执行controller环绕通知=============== ==========执行controller前置通知=============== [mykit-annotation-spring-provider]2018-05-12 22:58:19,617 INFO [main] SystemLogAspect.doBefore(59) | before execution(void io.mykit.annotation.spring.log.user.service.impl.UserServiceImpl.addUser()) [mykit-annotation-spring-provider]2018-05-12 22:58:19,629 INFO [main] UserServiceImpl.addUser(16) | 执行了添加用户的操作 [mykit-annotation-spring-provider]2018-05-12 22:58:19,629 INFO [main] SystemLogAspect.around(72) | around execution(void io.mykit.annotation.spring.log.user.service.impl.UserServiceImpl.addUser()) Use time : 14 ms! ==========结束执行controller环绕通知=============== =====controller后置通知开始===== 请求方法:io.mykit.annotation.spring.log.user.service.impl.UserServiceImpl.addUser().add操作 方法描述:添加用户 请求人:刘亚壮 请求IP:127.0.0.1 [mykit-annotation-spring-provider]2018-05-12 22:58:19,912 INFO [main] SystemLogServiceImpl.insert(26) | insert===>>>SystemLog [id=dfc4415f-0151-4e3e-8268-9397ab264288, description=添加用户, method=io.mykit.annotation.spring.log.user.service.impl.UserServiceImpl.addUser().add操作, logType=0, requestIp=127.0.0.1, exceptioncode=null, exceptionDetail=null, params=null, createBy=刘亚壮, createDate=Sat May 12 22:58:19 CST 2018] =====controller后置通知结束===== =====执行controller后置返回通知===== [mykit-annotation-spring-provider]2018-05-12 22:58:19,912 INFO [main] SystemLogAspect.afterReturn(155) | afterReturn execution(void io.mykit.annotation.spring.log.user.service.impl.UserServiceImpl.addUser())
备注:
本实例中我们在具体切面实现类SystemLogAspect中打印出了相关操作日志,具体项目业务中,大家可以根据具体业务需求将日志存储到相关的数据库或者分布式文件系统中。