1、引入springboot-aop集成jar

Spring-boot-start-aop

2、application.yml中启用声明

#spring配置

spring:

#切面启用

aop:

proxy-target-class: true

auto: true

3、自定义一个拦截controller的注解

package cn.annotation;


import java.lang.annotation.*;


/**

* Title: SystemControllerLog

* @date 2018年8月31日

* @version V1.0

* Description: 自定义注解,拦截controller

*/


@Target({ElementType.PARAMETER, ElementType.METHOD})//作用在参数和方法上

@Retention(RetentionPolicy.RUNTIME)//运行时注解

@Documented//表明这个注解应该被 javadoc工具记录

public @interface SystemControllerLog {

String description() default "";

}

4、自定义一个拦截service的注解

package cn.annotation;


import java.lang.annotation.*;


/**

* Title: SystemControllerLog

* @date 2018年8月31日

* @version V1.0

* Description: 自定义注解,拦截service

*/

@Target({ElementType.PARAMETER, ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface SystemServiceLog {

String description() default "";

}


5、定义日志记录切面

package cn.annotation;


import cn.pojo.Action;

import cn.pojo.User;

import cn.service.ActionService;

import cn.utils.IpUtils;

import cn.utils.JsonUtils;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.AfterThrowing;

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 org.springframework.web.context.request.RequestContextHolder;

import org.springframework.web.context.request.ServletRequestAttributes;


import javax.annotation.Resource;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpSession;

import java.lang.reflect.Method;

import java.util.Date;


/**

* Title: SystemControllerLog

* @date 2018年8月31日

* @version V1.0

* Description: 切点类

*/

@Aspect

@Component

@SuppressWarnings("all")

public class SystemLogAspect {

//注入Service用于把日志保存数据库,实际项目入库采用队列做异步

@Resource

private ActionService actionService;

//本地异常日志记录对象

private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect.class);

//Service层切点

@Pointcut("@annotation(cn.annotation.SystemServiceLog)")

public void serviceAspect(){

}


//Controller层切点

@Pointcut("@annotation(cn.oa.annotation.SystemControllerLog)")

public void controllerAspect(){

}


/**

* @Description 前置通知 用于拦截Controller层记录用户的操作

* @date 2018年9月3日 10:38

*/


@Before("controllerAspect()")

public void doBefore(JoinPoint joinPoint){

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

HttpSession session = request.getSession();

//读取session中的用户

User user = (User) session.getAttribute("user");


String ip = IpUtils.getIpAddr(request);


try {

//*========控制台输出=========*//

System.out.println("==============前置通知开始==============");

System.out.println("请求方法" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName()));

System.out.println("方法描述:" + getControllerMethodDescription(joinPoint));

System.out.println("请求人:"+user.getUsername());

System.out.println("请求ip:"+ip);


//*========数据库日志=========*//

Action action = new Action();

action.setActionDes(getControllerMethodDescription(joinPoint));

action.setActionType("0");

action.setActionIp(ip);

action.setUserId(user.getId());

action.setActionTime(new Date());

//保存数据库

actionService.add(action);


}catch (Exception e){

//记录本地异常日志

logger.error("==前置通知异常==");

logger.error("异常信息:{}",e.getMessage());

}

}


/**

* @Description 异常通知 用于拦截service层记录异常日志

* @date 2018年9月3日 下午5:43

*/

@AfterThrowing(pointcut = "serviceAspect()",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("user");

//获取请求ip

String ip = IpUtils.getIpAddr(request);

//获取用户请求方法的参数并序列化为JSON格式字符串

String params = "";

if (joinPoint.getArgs()!=null&&joinPoint.getArgs().length>0){

for (int i = 0; i < joinPoint.getArgs().length; i++) {

params+= JsonUtils.objectToJson(joinPoint.getArgs()[i])+";";

}

}

try{

/*========控制台输出=========*/

System.out.println("=====异常通知开始=====");

System.out.println("异常代码:" + e.getClass().getName());

System.out.println("异常信息:" + e.getMessage());

System.out.println("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));

System.out.println("方法描述:" + getServiceMethodDescription(joinPoint));

System.out.println("请求人:" + user.getUsername());

System.out.println("请求IP:" + ip);

System.out.println("请求参数:" + params);

/*==========数据库日志=========*/

Action action = new Action();

action.setActionDes(getServiceMethodDescription(joinPoint));

action.setActionType("1");

action.setUserId(user.getId());

action.setActionIp(ip);

action.setActionTime(new Date());

//保存到数据库

actionService.add(action);

}catch (Exception ex){

//记录本地异常日志

logger.error("==异常通知异常==");

logger.error("异常信息:{}", ex.getMessage());

}

}



/**

* @Description 获取注解中对方法的描述信息 用于service层注解

* @date 2018年9月3日 下午5:05

*/

public static String getServiceMethodDescription(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)){

Class[] clazzs = method.getParameterTypes();

if (clazzs.length==arguments.length){

description = method.getAnnotation(SystemServiceLog.class).description();

break;

}

}

}

return description;

}




/**

* @Description 获取注解中对方法的描述信息 用于Controller层注解

* @date 2018年9月3日 上午12:01

*/

public static 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)){

Class[] clazzs = method.getParameterTypes();

if (clazzs.length==arguments.length){

description = method.getAnnotation(SystemControllerLog.class).description();

break;

}

}

}

return description;

}

}

6、开始使用

1)@SystemControllerLog(description = "")

注解加在控制器中方法上面,括号里写上操作描述



2)用于监控service异常,可以不使用

@SystemServiceLog(description = "")

注解加在service层方法上面,括号里写上操作描述

(此处为AOP拦截Service记录异常信息。方法不需要加try-catch)

------------------------------------------------------------------------------------------------------


项目地址:https://gitee.com/lwydyby/wwmxd-log/

1. 在需要记录的方法上使用注解EnableGameleyLog

参数如下:

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.METHOD})

public @interface EnableGameleyLog {

/**

* 操作的中文说明 可以直接调用ModifyName

* @return

*/

String name() default "";

/**

* 获取编辑信息的解析类,目前为使用id获取,复杂的解析需要自己实现,默认不填写

* 则使用默认解析类

* @return

*/

Class parseclass() default DefaultContentParse.class;

/**

* 查询数据库所调用的class文件

* @return

*/

Class serviceclass() default IService.class;

/**

* 前台字段名称

*/

String[] feildName() default {"id"};

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

简单例子:

“`

@EnableGameleyLog(name = ModifyName.SAVE,serviceclass = DemoService.class)

public BaseResponse addDemo(@RequestBody Demo demo){

}

2.编写解析类,默认的解析类为使用id查询,自定义的解析类请继承ContentParser接口,并在注解中赋值

1

/**

* 基础解析类

* 单表编辑时可以直接使用id来查询

* 如果为多表复杂逻辑,请自行编写具体实现类

* @author lw

* @date 2018-03-02

*/

public class DefaultContentParse implements ContentParser {

@Override

public Object getResult(Map

3.默认的操作方式有:

```

public class ModifyName {

public final static String SAVE="新建";

public final static String UPDATE="编辑";

public final static String DELETE="删除";

}

1

2

3

4

5

6

7

4.如需记录操作字段中文请在entity中使用DataName注解

如:

@DataName(name="操作日期")

private String modifydate;