springboot中使用aop记录操作和异常日志

一、创建日志记录表、异常日志表,表结构如下:

操作表:
springboot中使用aop记录操作和异常日志
异常表:
springboot中使用aop记录操作和异常日志
DDL:

CREATE TABLE `operlog` (
  `oper_id` varchar(64) NOT NULL COMMENT '主键',
  `oper_model` varchar(64) DEFAULT NULL COMMENT '功能模块',
  `oper_type` varchar(64) DEFAULT NULL COMMENT '操作类型',
  `oper_desc` varchar(500) DEFAULT NULL COMMENT '操作描述',
  `oper_requ_param` text COMMENT '请求参数',
  `oper_resp_param` text COMMENT '返回参数',
  `oper_user_id` varchar(64) DEFAULT NULL COMMENT '操作员id',
  `oper_user_name` varchar(64) DEFAULT NULL COMMENT '操作员名称',
  `oper_method` varchar(255) DEFAULT NULL COMMENT '操作方法',
  `oper_uri` varchar(255) DEFAULT NULL COMMENT '请求URI',
  `oper_ip` varchar(64) DEFAULT NULL COMMENT '请求id',
  `oper_create_time` datetime DEFAULT NULL COMMENT '操作时间',
  `oper_ver` varchar(64) DEFAULT NULL COMMENT '操作版本号',
  PRIMARY KEY (`oper_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

CREATE TABLE `errorlog` (
  `error_id` varchar(64) NOT NULL COMMENT '主键ID',
  `oper_user_id` varchar(64) DEFAULT NULL COMMENT '操作员ID',
  `oper_user_name` varchar(64) DEFAULT NULL COMMENT '操作员名称',
  `oper_method` varchar(255) DEFAULT NULL COMMENT '操作方法',
  `oper_uri` varchar(255) DEFAULT NULL COMMENT '请求URI',
  `oper_ip` varchar(64) DEFAULT NULL COMMENT '请求IP',
  `oper_ver` varchar(64) DEFAULT NULL COMMENT '操作版本',
  `oper_create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `error_requ_param` text COMMENT '请求参数',
  `error_name` varchar(255) DEFAULT NULL COMMENT '异常名称',
  `error_message` text COMMENT '异常信息',
  PRIMARY KEY (`error_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

二、添加Maven依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

创建操作日志注解类OperLog.java和操作类型类

//注解放置的目标位置,METHOD是可注解在方法级别上
@Target(ElementType.METHOD)
//注解在哪个阶段执行
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperLog {
    // 操作模块
    String operModul() default "";
    // 操作类型
    LogActionType operType() default LogActionType.SELECT;
    // 操作说明
    String operDesc() default "";
}
public enum LogActionType {
    /**
     * 增删改查
     */
    ADD("新增"),
    SELECT("查询"),
    UPDATE("更新"),
    DELETE("删除");
    private String value;

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

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

创建切面类记录操作日志

/**
 * 切片的实现
 * 监控controller的请求信息和响应信息
 *
 * @author sxyuser
 */
@Aspect
@Slf4j
@Component
public class WebLogAspect {
    /**
     * 操作版本号
     * <p>
     * 项目启动时从命令行传入,例如:java -jar xxx.war --version=201902
     * </p>
     */
//    @Value("${version}")
    private final String operVer = "1";

    @Resource
    private ErrorlogService errorlogService;

    @Resource
    private OperlogService operlogService;

    /**
     * 设置操作日志切入点 记录操作日志 在注解的位置切入代码
     */
    @Pointcut("@annotation(com.demo.shiyan2.utils.annotation.OperLog)")
    public void operLogPoinCut() {
    }

    /**
     * 设置操作异常切入点记录异常日志 扫描所有controller包下操作
     */
    @Pointcut("execution(* com.demo.shiyan2.controller..*.*(..))")
    public void operExceptionLogPoinCut() {
    }

    /**
     * 配置环绕通知,使用在方法logPointcut()上注册的切入点
     *
     * @param joinPoint join point for advice
     */
    @Before(value = "operLogPoinCut()")
    public void doBefore(JoinPoint joinPoint) {
        HttpServletRequest request = RequestHolder.getHttpServletRequest();
        if (request != null) {
                // 记录下请求内容
                log.info("URL : {}", request.getRequestURL().toString());
                log.info("HTTP_METHOD :{} ", request.getMethod());
                log.info("IP : {}", request.getRemoteAddr());
                log.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
                log.info("ARGS : " + JsonUtils.obiectToJson(joinPoint.getArgs()));
                Enumeration<String> enu = request.getParameterNames();
                while (enu.hasMoreElements()) {
                    String name = enu.nextElement();
                    log.info("name:{},value:{}", name, request.getParameter(name));
                }
        } else {
            log.error("ServletRequestAttributes为空!");
        }
    }

    /**
     * 正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行
     *
     * @param joinPoint 切入点
     * @param keys      返回结果
     */
    @AfterReturning(value = "operExceptionLogPoinCut()", returning = "keys")
    public void saveOperLog(JoinPoint joinPoint, Object keys) {
        HttpServletRequest request = RequestHolder.getHttpServletRequest();
        if (request != null) {
            Operlog operlog = new Operlog();
                // 主键ID
                operlog.setOperId(UUID.randomUUID().toString());

                // 从切面织入点处通过反射机制获取织入点处的方法
                MethodSignature signature = (MethodSignature) joinPoint.getSignature();
                // 获取切入点所在的方法
                Method method = signature.getMethod();
                // 获取操作
                OperLog opLog = method.getAnnotation(OperLog.class);
                if (opLog != null) {
                    String operModul = opLog.operModul();
                    String operType = JsonUtils.obiectToJson(opLog.operType());
                    String operDesc = opLog.operDesc();
                    // 操作模块
                    operlog.setOperModel(operModul);
                    // 操作类型
                    operlog.setOperType(operType);
                    // 操作描述
                    operlog.setOperDesc(operDesc);
                }
                // 获取请求的类名
                String className = joinPoint.getTarget().getClass().getName();
                // 获取请求的方法名
                String methodName = method.getName();
                methodName = className + "." + methodName;
                // 请求方法
                operlog.setOperMethod(methodName);
                // 将参数所在的数组转换成json
                String params = JsonUtils.obiectToJson(request.getParameterMap());
                // 请求参数
                operlog.setOperRequParam(params);
                // 返回结果
                operlog.setOperRespParam(JsonUtils.obiectToJson(keys));
//            operlog.setOperUserId(UserShiroUtil.getCurrentUserLoginName()); // 请求用户ID
//            operlog.setOperUserName(UserShiroUtil.getCurrentUserName()); // 请求用户名称
                // 请求IP
                operlog.setOperIp(request.getRemoteAddr());
                // 请求URI
                operlog.setOperUri(request.getRequestURI());
                // 创建时间
                operlog.setOperCreateTime(Instant.now());
                // 操作版本
                operlog.setOperVer(operVer);
                operlogService.save(operlog);
        } else {
            log.error("ServletRequestAttributes为空!");
        }
    }

    /**
     * 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行
     *
     * @param joinPoint 切入点
     * @param e         异常信息
     */
    @AfterThrowing(pointcut = "operLogPoinCut()", throwing = "e")
    public void saveExceptionLog(JoinPoint joinPoint, Throwable e) {
        try {
            HttpServletRequest request = RequestHolder.getHttpServletRequest();
            if (request != null) {
                Errorlog excepLog = new Errorlog();
                // 从切面织入点处通过反射机制获取织入点处的方法
                MethodSignature signature = (MethodSignature) joinPoint.getSignature();
                // 获取切入点所在的方法
                Method method = signature.getMethod();
                excepLog.setErrorId(UUID.randomUUID().toString());
                // 获取请求的类名
                String className = joinPoint.getTarget().getClass().getName();
                // 获取请求的方法名
                String methodName = method.getName();
                methodName = className + "." + methodName;
                // 将参数所在的数组转换成json
                String params = JsonUtils.obiectToJson(request.getParameterMap());
                excepLog.setErrorRequParam(params); // 请求参数
                excepLog.setOperMethod(methodName); // 请求方法名
                excepLog.setErrorName(e.getClass().getName()); // 异常名称
                excepLog.setErrorMessage(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()));
                // 异常信息
//            excepLog.setOperUserId(UserShiroUtil.getCurrentUserLoginName()); // 操作员ID
//            excepLog.setOperUserName(UserShiroUtil.getCurrentUserName()); // 操作员名称
                // 操作URI
                excepLog.setOperUri(request.getRequestURI());
                // 操作员IP
                excepLog.setOperIp(request.getRemoteAddr());
                // 操作版本号
                excepLog.setOperVer(operVer);
                // 发生异常时间
                excepLog.setOperCreateTime(Instant.now());
                errorlogService.save(excepLog);
            } else {
                log.error("ServletRequestAttributes为空!");
            }
        } catch (Exception e2) {
            e2.printStackTrace();
        }


    }

    /**
     * 转换异常信息为字符串
     *
     * @param exceptionName    异常名称
     * @param exceptionMessage 异常信息
     * @param elements         堆栈信息
     */
    public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
        StringBuilder strbuff = new StringBuilder();
        for (StackTraceElement stet : elements) {
            strbuff.append(stet).append("\n");
        }
        return exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString();
    }
}

RequestHolder类

/**
 * 获取 HttpServletRequest
 */
public class RequestHolder {

    public static HttpServletRequest getHttpServletRequest() {
        HttpServletRequest request=null;
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            request = attributes.getRequest();
        }
        return request;
    }
}

位于JsonUtils类中的obiectToJson方法

 public static String obiectToJson(Object object) {
        try {
            return objectMapper.writeValueAsString(object);
        } catch (Exception e) {
            return null;
        }
    }

在Controller层方法添加@OperLog注解

 @OperLog(operModul = "测试类",operType = LogActionType.ADD,operDesc = "测试方法")
    @GetMapping("/")
    public String test(HttpServletRequest request) {
        userService.test();
        return request.getRequestURI();
    }

操作日志、异常日志查询功能

springboot中使用aop记录操作和异常日志

上一篇:php简单工厂模式


下一篇:数据结构双链表C语言