• springBoot AOP记录操作日志和异常日志


    springBoot AOP记录操作日志和异常日志

    1.创建日志表

    -- ----------------------------
    -- Table structure for sys_log
    -- ----------------------------
    DROP TABLE IF EXISTS "public"."sys_log";
    CREATE TABLE "public"."sys_log" (
      "id" varchar(64) COLLATE "pg_catalog"."default" NOT NULL,
      "thread" int4,
      "ip" varchar(30) COLLATE "pg_catalog"."default",
      "uri" varchar(100) COLLATE "pg_catalog"."default",
      "operate_module" varchar(100) COLLATE "pg_catalog"."default",
      "operate_type" varchar(50) COLLATE "pg_catalog"."default",
      "operate_method" varchar(100) COLLATE "pg_catalog"."default",
      "operate_desc" varchar(500) COLLATE "pg_catalog"."default",
      "request_state" int4,
      "request_param" varchar(500) COLLATE "pg_catalog"."default",
      "response_param" varchar(1000) COLLATE "pg_catalog"."default",
      "exception_name" varchar(255) COLLATE "pg_catalog"."default",
      "exception_message" text COLLATE "pg_catalog"."default",
      "create_time" timestamp(6),
      "user_id" varchar(50) COLLATE "pg_catalog"."default",
      "user_name" varchar(255) COLLATE "pg_catalog"."default",
      "session_time" int4
    )
    ;
    COMMENT ON COLUMN "public"."sys_log"."id" IS 'id';
    COMMENT ON COLUMN "public"."sys_log"."thread" IS '线程id';
    COMMENT ON COLUMN "public"."sys_log"."ip" IS 'ip';
    COMMENT ON COLUMN "public"."sys_log"."uri" IS '请求连接';
    COMMENT ON COLUMN "public"."sys_log"."operate_module" IS '功能模块';
    COMMENT ON COLUMN "public"."sys_log"."operate_type" IS '操作类型';
    COMMENT ON COLUMN "public"."sys_log"."operate_method" IS '操作方法';
    COMMENT ON COLUMN "public"."sys_log"."operate_desc" IS '操作描述';
    COMMENT ON COLUMN "public"."sys_log"."request_state" IS '请求状态(1正常 2异常)';
    COMMENT ON COLUMN "public"."sys_log"."request_param" IS '请求参数';
    COMMENT ON COLUMN "public"."sys_log"."response_param" IS '返回参数';
    COMMENT ON COLUMN "public"."sys_log"."exception_name" IS '异常名称';
    COMMENT ON COLUMN "public"."sys_log"."exception_message" IS '异常信息';
    COMMENT ON COLUMN "public"."sys_log"."create_time" IS '操作时间';
    COMMENT ON COLUMN "public"."sys_log"."user_id" IS '用户id';
    COMMENT ON COLUMN "public"."sys_log"."user_name" IS '用户名';
    COMMENT ON COLUMN "public"."sys_log"."session_time" IS '请求时长(秒)';
    
    -- ----------------------------
    -- Primary Key structure for table sys_log
    -- ----------------------------
    ALTER TABLE "public"."sys_log" ADD CONSTRAINT "sys_log_pkey" PRIMARY KEY ("id");
    

    2. 添加maven依赖

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

    3.创建操作日志注解

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface OperateLog {
    
        // 操作模块
        String operateModul() default "";
    
        // 操作类型
        String operateType() default "";
    
        // 操作说明
        String operateDesc() default "";
    }
    

    4.对应数据库的实体类

    @Data
    @TableName("sys_log")
    public class SysLog implements Serializable {
    
        private static final long serialVersionUID = 115492983341579610L;
    
        /** id **/
        @TableId(value = "id",type = IdType.ASSIGN_UUID)
        private String id;
    
        /** 线程id **/
        private Integer thread;
    
        /** ip **/
        private String ip;
    
        /** 请求连接 **/
        private String uri;
    
        /** 功能模块 **/
        private String operateModule;
    
        /** 操作类型 **/
        private String operateType;
    
        /** 操作方法 **/
        private String operateMethod;
    
        /** 操作描述 **/
        private String operateDesc;
    
        /** 请求状态(1正常 2异常) **/
        private Integer requestState;
    
        /** 请求参数 **/
        private String requestParam;
    
        /** 返回参数 **/
        private String responseParam;
    
        /** 异常名称 **/
        private String exceptionName;
    
        /** 异常信息 **/
        private String exceptionMessage;
    
        /** 操作时间 **/
        private Date createTime;
    
        /** 用户id **/
        private String userId;
    
        /** 用户名 **/
        private String userName;
    
        /** 请求时长(秒) **/
        private int sessionTime;
    }
    

    5.创建切面类来记录日志

    @Aspect
    @Component
    public class OperateLogAspect {
    
        @Autowired
        private SysLogMapper sysLogMapper;
    
        private static ThreadLocal<Long> startTime = new ThreadLocal<Long>();
    
        // 设置操作日志切入点 记录操作日志 在注解的位置切入代码
        @Pointcut("@annotation(com.gisquest.entity.OperateLog)")
        public void operatePointCut() {
        }
    
    
        /**
         * 设置操作异常切入点记录异常日志 扫描所有controller包下操作
         */
        @Pointcut("execution(* com.gisquest.controller..*.*(..))")
        public void operateExceptionPoinCut() {
        }
    
    
        /**
         * 前置通知
         * 获取开始的毫秒值
         */
        @Before("operatePointCut()||operateExceptionPoinCut()")
        public void doBefore() {
            startTime.set(System.currentTimeMillis());
        }
    
        /**
         * 返回通知
         * 拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行
         *
         * @param joinPoint 切入点
         * @param keys      返回结果
         */
        @AfterReturning(value = "operatePointCut()", returning = "keys")
        public void saveOperLog(JoinPoint joinPoint, Object keys) {
            saveLogInfo(joinPoint, keys, null);
        }
    
        /**
         * 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行
         *
         * @param joinPoint 切入点
         * @param e         异常信息
         */
        @AfterThrowing(pointcut = "operateExceptionPoinCut()", throwing = "e")
        public void saveExceptionLog(JoinPoint joinPoint, Throwable e) {
            saveLogInfo(joinPoint, null, e);
        }
    
    
        /**
         * 保存日志信息
         *
         * @param joinPoint 切点
         * @param keys      返回值
         * @param e         异常类
         */
        public void saveLogInfo(JoinPoint joinPoint, Object keys, Throwable e) {
            // 获取RequestAttributes
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            // 从获取RequestAttributes中获取HttpServletRequest的信息
            HttpServletRequest request = (HttpServletRequest) requestAttributes
                    .resolveReference(RequestAttributes.REFERENCE_REQUEST);
            SysLog sysLog = new SysLog();
            try {
                // 从切面织入点处通过反射机制获取织入点处的方法
                MethodSignature signature = (MethodSignature) joinPoint.getSignature();
                // 获取切入点所在的方法
                Method method = signature.getMethod();
                // 获取请求的类名
                String className = joinPoint.getTarget().getClass().getName();
                // 获取请求的方法名
                String methodName = method.getName();
                methodName = className + "." + methodName;
                sysLog.setOperateMethod(methodName); // 请求方法
                // 请求的参数
                Map<String, String> rtnMap = converMap(request.getParameterMap());
                // 将参数所在的数组转换成json
                String params = JSON.toJSONString(rtnMap);
    
                // 获取操作
                OperateLog opLog = method.getAnnotation(OperateLog.class);
                if (opLog != null) {
                    String operModul = opLog.operateModul();
                    String operType = opLog.operateType();
                    String operDesc = opLog.operateDesc();
                    sysLog.setOperateModule(operModul);
                    sysLog.setOperateType(operType);
                    sysLog.setOperateDesc(operDesc);
                }
    
                if (e != null) {
                    // 异常名称
                    sysLog.setExceptionName(e.getClass().getName());
                    // 异常信息
                    sysLog.setExceptionMessage(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()));
                }
    
                //获取线程id
                int threadId = (int) Thread.currentThread().getId();
                sysLog.setThread(threadId);
                sysLog.setRequestParam(params);
                sysLog.setResponseParam(JSON.toJSONString(keys));
                sysLog.setUserId(UserUtils.userId());    // 这边自己公司的工具类 
                sysLog.setUserName(UserUtils.nickname());// 你们可把用户信息放在Request中获取
                sysLog.setIp(getIpAddressa(request));
                sysLog.setUri(request.getRequestURI());
                sysLog.setCreateTime(new Date());
                sysLog.setRequestState(e == null ? 1 : 2);
                sysLog.setSessionTime((int) ((System.currentTimeMillis() - startTime.get()) / 1000));
                //插入数据到数据库
                sysLogMapper.insert(sysLog);
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
    
        /**
         * 转换request 请求参数
         *
         * @param paramMap request获取的参数数组
         */
        public Map<String, String> converMap(Map<String, String[]> paramMap) {
            Map<String, String> rtnMap = new HashMap<String, String>();
            for (String key : paramMap.keySet()) {
                rtnMap.put(key, paramMap.get(key)[0]);
            }
            return rtnMap;
        }
    
        /**
         * 转换异常信息为字符串
         *
         * @param exceptionName    异常名称
         * @param exceptionMessage 异常信息
         * @param elements         堆栈信息
         */
        public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
            StringBuffer strbuff = new StringBuffer();
            for (StackTraceElement stet : elements) {
                strbuff.append(stet + "
    ");
            }
            String message = exceptionName + ":" + exceptionMessage + "
    	" + strbuff.toString();
            return message;
        }
    
    
        /**
         * 获取IP
         *
         * @param request
         * @return
         */
        public static String getIpAddressa(HttpServletRequest request) {
            String Xip = request.getHeader("X-Real-IP");
            String XFor = request.getHeader("X-Forwarded-For");
    
            //多次反向代理后会有多个ip值,第一个ip才是真实ip
            if (StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)) {
                int index = XFor.indexOf(",");
                if (index != -1) {
                    return "0:0:0:0:0:0:0:1".equals(XFor.substring(0, index)) ? "127.0.0.1" : XFor.substring(0, index);
                } else {
                    return "0:0:0:0:0:0:0:1".equals(XFor) ? "127.0.0.1" : XFor;
                }
            }
            XFor = Xip;
            if (StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor))
                return "0:0:0:0:0:0:0:1".equals(XFor) ? "127.0.0.1" : XFor;
    
            if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor))
                XFor = request.getHeader("Proxy-Client-IP");
    
            if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor))
                XFor = request.getHeader("WL-Proxy-Client-IP");
    
            if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor))
                XFor = request.getHeader("HTTP_CLIENT_IP");
    
            if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor))
                XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
    
            if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor))
                XFor = request.getRemoteAddr();
    
            return "0:0:0:0:0:0:0:1".equals(XFor) ? "127.0.0.1" : XFor;
        }
    
    
    }
    

    6.在Controller中添加注解

    @OperateLog(operateModul = "模块名", operateType = "查询" ,operateDesc = "描述")
    @ApiOperation("通过名字获取详细信息")  //swagger注解 
    @GetMapping("selectByName/{name}")
    public Result selectByName(@PathVariable("name") String name) {
        return baseInfoService.selectByName(name);
    }
    
  • 相关阅读:
    各种数字证书区别
    微信支付前端对接流程
    ts笔记 流动类型
    支付宝支付前端对接流程
    ts笔记索引签名
    [翻译]Selenium API 命令和操作(JAVA)
    玩一玩yolo目标检测
    快速上手MyBatis
    Swift快速入门
    Windows远程桌面后不能粘贴问题处理
  • 原文地址:https://www.cnblogs.com/mumuda/p/15146361.html
Copyright © 2020-2023  润新知