记录用户操作日志

833 阅读1分钟

自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {

    /**
     * 功能描述
     *
     * @return {String}
     */
    String value() default "";


}

定义全局日志切面

@Slf4j
@Aspect
@Component
public class SysLogAspect {

    @Resource
    LogService logService;

    @Resource
    private HttpServletRequest request;

    @Value("${spring.application.name}")
    private String springApplicationName;

    /**
     * @Pointcut 定义一个切入点,指明 Advice(切面) 在什么情况下触发
     * @annotation 当执行的方法上拥有指定的注解时生效。
     */
    @Pointcut("@annotation(com.kb.spring.boot.starter.log.annotation.SysLog)")
    public void pointCut() {
    }

    /**
     * 环绕通知:前置+目标方法执行+后置通知
     *
     * @param point
     * @return
     */
    @SneakyThrows
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint point) {
        String strClassName = point.getTarget().getClass().getName();
        String strMethodName = point.getSignature().getName();
        Object result = point.proceed();
        Class<?> targetCls = point.getTarget().getClass();
        //获取方法签名(通过此签名获取目标方法信息)
        MethodSignature ms = (MethodSignature) point.getSignature();
        //获取目标方法上的注解指定的操作名称
        Method targetMethod = targetCls.getDeclaredMethod(ms.getName(), ms.getParameterTypes());
        SysLog annotation = targetMethod.getAnnotation(SysLog.class);
        try {
            saveLog(strClassName, strMethodName, annotation, point.getArgs(), result);
        } catch (Exception e) {
            log.error("日志记录失败 功能:{}", annotation.value());
        }
        return result;
    }

    /**
     * 异步收集日志
     *
     * @param strClassName  类名
     * @param strMethodName 方法名
     * @param annotation    操作名称
     * @param args          参数
     * @param result        返回值
     */
    private void saveLog(String strClassName, String strMethodName, SysLog annotation, Object[] args, Object result) {
        LogDTO logDTO = new LogDTO();
        logDTO.setClassName(strClassName);
        logDTO.setMethod(strMethodName);
        logDTO.setMethodInfo(annotation.value());
        logDTO.setApplication(springApplicationName);
        logDTO.setParams(convertArgs(args));
        logDTO.setResult(result == null ? null : result.toString());
        logDTO.setUrl(request.getRequestURI());
        logDTO.setIp(getRemoteAddrIp(request));
        logDTO.setOperationTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        //获取用户信息
        SysUserDTO sysUser = getUserId();
        if (sysUser != null) {
            logDTO.setOperatorId(sysUser.getId());
            logDTO.setOperatorPhone(sysUser.getPhone());
            logDTO.setOperatorName(sysUser.getNickname());
        }
        logService.saveLog(logDTO);
    }
}

日志服务

放入 redis 队列中

@Service
public class LogServiceImpl implements LogService {

    @Resource
    private RedisTemplate redisTemplate;

    @Override
    @Async
    public void saveLog(LogDTO logDTO) {
       String json = JSON.toJSONString(logDTO);
        redisTemplate.opsForList().rightPush(RedisKeyEnum.SYS_LOG_REDIS_KEY.toString(),json);
    }
}

操作日志处理 Job

@Component
@Slf4j
public class SysLogsJob{
    @Resource
    ArkRedisClient redisClient;

    @Resource
    SysLogsFeignClient sysLogsFeignClient;

    @XxlJob(value = "sysLogProcessHandler")
    public ReturnT<String> logTimingProcessing(String param) {
        log.info("操作日志处理开始!!!!");
        while (true) {
            Object o = redisClient.lpop(RedisKeyEnum.SYS_LOG_REDIS_KEY.toString());
            if (o == null) {
                break;
            }
            JSONObject jsonObject = (JSONObject) JSONObject.parse(o.toString());
            try {
                LogDTO logDTO = JSONObject.toJavaObject(jsonObject, LogDTO.class);
                SysLogsInsertReqVO sysLogsInsertReqVO = new SysLogsInsertReqVO();
                BeanUtils.copyProperties(logDTO, sysLogsInsertReqVO);
                sysLogsFeignClient.save(sysLogsInsertReqVO);
                log.info("操作日志处理中.......");
            } catch (Exception e) {
                redisClient.lpush(RedisKeyEnum.SYS_LOG_REDIS_KEY.toString(),jsonObject);
                log.info("记录保存失败 info:{}  e:{}", o,e);
            }

        }
        log.info("操作日志处理结束!!!!");
        return  ReturnT.SUCCESS;
    }
}