springboot 手写AOP切面日志

package com.hivekion.common.annotation;

import com.hivekion.common.enums.OperationTypeEnum;
import com.hivekion.common.enums.OperationUnitEnum;

import java.lang.annotation.*;

/**
 * @author admin
 */
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoLog {

      /**
       * 方法描述,可使用占位符获取参数:{{tel}}
       */
      String value() default "";

      /**
       * 日志等级:自己定,此处分为1-9
       */
      int level() default 0;

      /**
       * 操作类型(enum):主要是select,insert,update,delete,导入、导出
       */
      OperationTypeEnum operationType() default OperationTypeEnum.UNKNOWN;

      /**
       * 被操作的对象(此处使用enum):可以是任何对象,如表名(user),或者是工具(redis)
       */
      OperationUnitEnum operationUnit() default OperationUnitEnum.UNKNOWN;

      String module() default "";
}
package com.hivekion.common.enums;

/**
 * 操作类型
 * @author admin
 */
public enum OperationTypeEnum {
    /**
     * 操作类型
     */
    UNKNOWN("unknown"),
    DELETE("delete"),
    SELECT("select"),
    UPDATE("update"),
    CLEAN("clean"),
    DOWNLOAD("download"),
    LOGIN("login"),
    INSERT("insert");

    private String value;

    OperationTypeEnum(String s) {
        this.value = s;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}
package com.hivekion.common.enums;

/**
 * 被操作的单元
 * @author admin
 */
public enum OperationUnitEnum {
    /**
     * 操作单元
     */
      UNKNOWN("unknown"),
      USER("user"),
      EMPLOYEE("employee"),
      Redis("redis");

      private String value;

      OperationUnitEnum(String value) {
	    this.value = value;
      }

      public String getValue() {
	    return value;
      }

      public void setValue(String value) {
	    this.value = value;
      }
}
package com.hivekion.common.aspects;

import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.hivekion.common.annotation.AutoLog;
import com.hivekion.system.domain.SysOperationLog;
import com.hivekion.system.mapper.SysOperationLogMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * @author admin
 */
@Component
@Aspect
public class ControllerLogAspect {
    public static final Logger logger = LoggerFactory.getLogger(ControllerLogAspect.class);

    @Autowired
    SysOperationLogMapper mapper;

    @Pointcut("@annotation(com.hivekion.common.annotation.AutoLog)")
    public void operationLog() {
    }

    @Pointcut("execution(* com.hivekion.*.controller.*.*(..))")
    public void controllerThrowLog() {
    }

    @Around("operationLog()")
    public Object handleControllerMethod(ProceedingJoinPoint point) throws Throwable {
        // 执行时长
        Object result = null;
        // 开始时间
        long beginTime = System.currentTimeMillis();
        result = point.proceed();
        try {
            // 计算运行时间
            long time = System.currentTimeMillis() - beginTime;
            addOperationLog(point, result, time, 0);
        } catch (Exception ex) {
            logger.error("LogAspect 操作失败: " + ex.getMessage());
        }
        return result;
    }

    @AfterThrowing(value = "controllerThrowLog()", throwing = "e")
    public void handleControllerThrowMethod(JoinPoint point, Throwable e) {
        addOperationLog(point, e, 0, 1);
    }

    private void addOperationLog(JoinPoint point, Object res, long time, int status) {
        HttpServletRequest request =
                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                        .getRequest();
        MethodSignature signature = (MethodSignature) point.getSignature();
        SysOperationLog operationLog = new SysOperationLog();
        // 记录运行时间
        operationLog.setRunTime(time);
        String returnV = JSON.toJSONString(res);
        int length = returnV.length();
        // 记录返回结果
        operationLog.setReturnValue(returnV);
        operationLog.setMethod(signature.getDeclaringTypeName() + "." + signature.getName());
        operationLog.setRequestParams(getReqestParams(request, point));
        // 访问IP地址
        operationLog.setIp(ServletUtil.getClientIP(request));
        operationLog.setStatus(status);

        // 注解
        AutoLog annotation = signature.getMethod().getAnnotation(AutoLog.class);
        if (annotation != null) {
            operationLog.setLevel(annotation.level());
            operationLog.setTitle(annotation.value());
            // operationLog.setDescribe(getDetail(((MethodSignature)
            operationLog.setOperationType(annotation.operationType().getValue());
            // 被操作对象
            operationLog.setOperationUnit(annotation.operationUnit().getValue());
            // 操作模块
            operationLog.setModule(annotation.module());
        }
        // TODO 这里保存日志
        //System.out.println("记录日志:" + operationLog.toString());
        mapper.insert(operationLog);
    }

    private String getReqestParams(HttpServletRequest request, JoinPoint joinPoint) {
        String httpMethod = request.getMethod();
        String params = "";

        if (RequestMethod.POST.toString().equalsIgnoreCase(httpMethod) || RequestMethod.PUT.toString().equalsIgnoreCase(httpMethod)
                || RequestMethod.PATCH.toString().equalsIgnoreCase(httpMethod)) {
            Object[] paramsArray = joinPoint.getArgs();
            Object[] arguments = new Object[paramsArray.length];
            for (int i = 0; i < paramsArray.length; i++) {
                if (paramsArray[i] instanceof ServletRequest
                        || paramsArray[i] instanceof ServletResponse
                        || paramsArray[i] instanceof MultipartFile
                        || paramsArray[i] instanceof MultipartFile[]) {

                    continue;
                }
                arguments[i] = paramsArray[i];
            }
            // update-begin-author:taoyan date:20200724 for:日志数据太长的直接过滤掉
            PropertyFilter profilter =
                    new PropertyFilter() {
                        @Override
                        public boolean apply(Object o, String name, Object value) {
                            if (value != null && value.toString().length() > HttpStatus.INTERNAL_SERVER_ERROR.value()) {
                                return false;
                            }
                            return true;
                        }
                    };
            params = JSONObject.toJSONString(arguments, profilter);
            // update-end-author:taoyan date:20200724 for:日志数据太长的直接过滤掉
        } else {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            // 请求的方法参数值
            Object[] args = joinPoint.getArgs();
            // 请求的方法参数名称
            LocalVariableTableParameterNameDiscoverer u =
                    new LocalVariableTableParameterNameDiscoverer();
            String[] paramNames = u.getParameterNames(method);
            if (args != null && paramNames != null) {
                for (int i = 0; i < args.length; i++) {
                    params += "  " + paramNames[i] + ": " + args[i];
                }
            }
        }
        return params;
    }
}
package com.hivekion.system.domain;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnComment;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnType;
import com.gitee.sunchenbin.mybatis.actable.annotation.TableComment;
import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant;
import com.hivekion.common.entity.BaseEntity;
import lombok.Data;

/**
 * @author admin
 */
@Data
@TableName("base_sys_operation_log")
@TableComment("操作日志表")
public class SysOperationLog extends BaseEntity {
      @TableField
      @ColumnType(value = MySqlTypeConstant.INT, length = 8)
      @ColumnComment("日志等级")
      private Integer level;

      @TableField
      @ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
      @ColumnComment("被操作的对象")
      private String operationUnit;

      @TableField
      @ColumnType(value = MySqlTypeConstant.VARCHAR, length = 250)
      @ColumnComment("方法名")
      private String method;

      @TableField
      @ColumnType(value = MySqlTypeConstant.VARCHAR, length = 5000)
      @ColumnComment("参数")
      private String args;

      @TableField
      @ColumnType(value = MySqlTypeConstant.VARCHAR, length = 250)
      @ColumnComment("日志描述")
      private String title;

      @TableField
      @ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
      @ColumnComment("操作类型")
      private String operationType;

      @TableField
      @ColumnType(value = MySqlTypeConstant.BIGINT, length = 8)
      @ColumnComment("方法运行时间")
      private Long runTime;

      @TableField
      @ColumnType(value = MySqlTypeConstant.LONGTEXT)
      @ColumnComment("方法返回值")
      private String returnValue;

      @TableField
      @ColumnType(value = MySqlTypeConstant.VARCHAR, length = 5000)
      @ColumnComment("请求的参数")
      private String requestParams;

      @TableField
      @ColumnType(value = MySqlTypeConstant.VARCHAR, length = 5000)
      @ColumnComment("操作模块")
      private String module;

      @TableField
      @ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
      @ColumnComment("IP地址")
      private String ip;

      @TableField
      @ColumnType(value = MySqlTypeConstant.INT, length = 8)
      @ColumnComment("结果状态")
      private Integer status;
}
package com.hivekion.system.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hivekion.system.domain.SysOperationLog;
import org.apache.ibatis.annotations.Mapper;

/**
 * @author admin
 */
@Mapper
public interface SysOperationLogMapper extends BaseMapper<SysOperationLog> {

      /**
       * 清空日志
       */
      void cleanOperationLog();
}
 @PostMapping("/checkDeptNameUnique")
    @ApiOperation("部门名称是否存在")
    @AutoLog(value = "部门名称是否存在", operationType = OperationTypeEnum.SELECT, module = "系统管理/部门管理")
    public boolean checkDeptNameUnique(String deptName, String deptId) {
        return deptService.checkDeptNameUnique(deptName, deptId);
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值