Использование принципа aop Spring для управления журналами на системном уровне.

Java Spring
Использование принципа aop Spring для управления журналами на системном уровне.

Эта статья участвовала в приказе о созыве Haowen, нажмите, чтобы просмотреть:Двойные заявки на внутреннюю и внешнюю стороны, призовой фонд в 20 000 юаней ждет вас, чтобы бросить вызов!

задний план

В предыдущей статье я дал краткое введение в ведение журнала. В ежедневной разработке мы обычно используем два типа журналов.Один из них — бизнес-журнал, который в основном используется для записи изменений определенных услуг или атрибутов в системе, таких как изменения статуса записи или изменения атрибутов объекта. в процессе бизнес-потока. Этот тип в основном используется для запроса бизнес-трассировки; другой — системный журнал, в котором в основном записывается информация о вызове метода, такая как имя метода, параметры и имя вызывающего, IP-адрес, время вызова и другие Информация. В сочетании с реальной ситуацией в проекте эта статья рассказывает, как использовать принцип aop Spring для реализации управления журналами на системном уровне.

основной код

1. Объявите класс аспекта системного журнала и передайте его контейнеру Spring для управления

код показывает, как показано ниже:

@Aspect
@Component
public class SysLogAspect {
	
    @Autowired
    private SysLogService sysLogService;

    @Pointcut("execution(* com.xx.xx.*.service.*.*(..))")
    public void logPointCut() { 

    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        // 执行方法
        Object result = point.proceed();
        // 执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        // 保存日志
        saveSysLog(point, time);
        return result;
    }

    private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {

        String userName = BaseController.getUsername();//BaseController为项目中的基类,主要存储用户登录后的一些基本信息,该类可有可无,根据自己的实际情况而定

        //判断是否SysLogService的调用操作,SysLogService本身不再记录日志
        if(joinPoint.getTarget() instanceof SysLogService) { //SysLogService,自己声明的系统日志接口
            return ;
        }

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        SysLog sysLog = new SysLog();

        // 请求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLog.setMethod(className + "." + methodName + "()");

        // 请求的参数
        Object[] args = joinPoint.getArgs();
        try{
            String params = JSONObject.toJSONString(args[0]);
            sysLog.setParams(params);
        } catch (Exception e){

        }

        // 获取request
        HttpServletRequest request = HttpUtils.getHttpServletRequest();
        // 设置IP地址
        sysLog.setIp(IPUtils.getIpAddr(request));

        // 用户名
        sysLog.setUserName(userName);

        // 执行时长(毫秒)
        sysLog.setTime(time);

        // 保存系统日志
        sysLogService.save(sysLog);
    }

}

2. Объявите класс инструмента ip

код показывает, как показано ниже:

public class IPUtils {
    
    private static Logger logger = LoggerFactory.getLogger(IPUtils.class);

    /**
     * 获取IP地址
     * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
     * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
     */
    public static String getIpAddr(HttpServletRequest request) {
    	String ip = null;
        try {
            ip = request.getHeader("x-forwarded-for");
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        } catch (Exception e) {
        	logger.error("IPUtils ERROR ", e);
        }
            
        return ip;
    }
	
}

3. Объявите класс инструмента HttpUtils

код показывает, как показано ниже:

public class HttpUtils {
	
    private static final Log log = LogFactory.getLog(HttpUtils.class);

    /**
     * 获取HttpServletRequest对象
     * @return
     */
    public static HttpServletRequest getHttpServletRequest() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    }
	
    /**
     * 输出信息到浏览器
     * @param response
     * @throws IOException
     */
    public static void print(HttpServletResponse response, int code, String msg) throws IOException {
        response.setContentType("application/json; charset=utf-8");
        HttpResult result = HttpResult.error(code, msg);
        String json = JSONObject.toJSONString(result);
        response.getWriter().print(json);
        response.getWriter().flush();
        response.getWriter().close();
    }
    
    public static String sendpost(String serverUrl, String data) {
        
        StringBuilder responseBuilder = null;
        BufferedReader reader = null;
        OutputStreamWriter wr = null;

        String re=null;
        try {
            URL url = new URL(serverUrl);
            URLConnection e = url.openConnection();
            e.setDoOutput(true);
            e.setConnectTimeout(5000);
            wr = new OutputStreamWriter(e.getOutputStream());
            wr.write(data);
            wr.flush();
            reader = new BufferedReader(new InputStreamReader(e.getInputStream()));
            responseBuilder = new StringBuilder();
            String line = null;

            while((line = reader.readLine()) != null) {
                responseBuilder.append(line).append("\n");
            }
            re=responseBuilder.toString();
            log.debug("http请求返回结果:"+re);
        } catch (IOException e1) {
            log.error("", e1);
        } finally {
            if(wr != null) {
                try {
                    wr.close();
                } catch (IOException e2) {
                    log.error("close error", e2);
                }
            }

            if(reader != null) {
                try {
                    reader.close();
                } catch (IOException e3) {
                    log.error("close error", e3);
                }
            }

        }

        return re;
    }
}

4. Результаты испытаний

微信图片_20210723001650.png

Примечания: Поскольку система часто используется, часть данных будет генерироваться при вызове каждого интерфейса, поэтому объем данных в таблице системного журнала будет очень большим.Необходимо регулярно создавать резервные копии данных и очищать некоторые старые данные, иначе данных в таблице будет становиться все больше и больше. Влияет на производительность.