java 项目日记实现两种方式:拦截器方式实现日记与定义日记注解方式实现日记

        通常只要是java web项目基本都离不开项目日记,项目日记存在的意义很多,例如:安全审计,问题追踪都离不开项目日记。下面我们说一下项目日记实现最常用的两种方式 。

一 拉截器实现项目日记

   1 实现一个拦截器基类,用于事件项目的请求日记

     用拦截器实现记录日记代码

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.Duration;
import java.time.LocalDateTime;

/**
 * @author hua
 * @Description 自定义拦截器,用于记录处理Web请求的基本功能。
 */
public class BaseInterceptor extends HandlerInterceptorAdapter {

    // ThreadLocal 用于在每个线程中存储API消息日志
    ThreadLocal<ApiMessageLog> apiMessageLogThreadLocal = new ThreadLocal<>();

    // 用于记录日志的Logger
    public static final Logger logger = LoggerFactory.getLogger(BaseInterceptor.class);

    /**
     * 在请求完成后调用的方法,用于执行任何必要的清理或日志记录。
     *
     * @param request   HTTP请求对象。
     * @param response  HTTP响应对象。
     * @param handler   处理请求的处理程序(控制器方法)。
     * @param ex        在请求处理过程中发生的任何异常。
     * @throws Exception 如果在完成后处理过程中发生异常。
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

        // 获取当前线程的API消息日志
        ApiMessageLog apiMessageLog = apiMessageLogThreadLocal.get();

        // 检查API消息日志是否非空
        if (apiMessageLog != null) {

            // 计算请求所用时间
            long time = Duration.between(apiMessageLog.getCtime(), LocalDateTime.now()).getSeconds();
            apiMessageLog.setTimeLong((int) time);

            // 如果请求时间超过8秒,则记录错误日志
            if (time > 8) {
                logger.error("超时 > " + time + " > " + apiMessageLog.getApiName() + "\n" + apiMessageLog);
            }

            // 如果在请求处理过程中发生异常,将其设置为API消息日志的结果
            if (ex != null) {
                apiMessageLog.setResult(ex.getMessage());
            } else {
                // 如果没有异常,从请求属性中设置结果
                String result = (String) request.getAttribute("_REQ_RESULT");
                if (result != null) {
                    apiMessageLog.setResult(result);
                }

                // 从请求属性中设置API订单号
                String _REQ_ORDER_SN = (String) request.getAttribute("_REQ_ORDER_SN");
                if (_REQ_ORDER_SN != null) {
                    apiMessageLog.setApiOrderNo(_REQ_ORDER_SN);
                }

                // 从请求属性中设置连接器ID
                String _REQ_CONNECTOR_ID = (String) request.getAttribute("_REQ_CONNECTOR_ID");
                if (_REQ_ORDER_SN != null) {
                    apiMessageLog.setConnectorId(_REQ_CONNECTOR_ID);
                }
            }

            // 将API消息日志添加到内存队列,队列批量保存效率更高
            MemDataTable.API_MESSAGE_LOGS.offer(apiMessageLog);
        }
    }
}

继承上面写日记基类拦截器(如果项目简单且不用选择性记录,可以把以下代码合并成一个拦截器即可)。

import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;

/**
 * @author hua
 * @Description 统一处理中电联的拦截器
 */
@Component
public class ZdlInterceptor extends BaseInterceptor {

    // 注入StringRedisTemplate实例
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    // 注入ApiMessageLogServiceImpl实例
    @Autowired
    ApiMessageLogServiceImpl apiMessageLogService;

    /**
     * 在请求处理前执行的方法
     *
     * @param request  HTTP请求对象
     * @param response HTTP响应对象
     * @param handler  处理请求的处理程序
     * @return 如果继续处理请求,则返回true;否则,返回false
     * @throws Exception 如果在处理过程中发生异常
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // 从请求中获取JSON字符串
        String reqJsonStr = IOUtils.toString(request.getInputStream(), "UTF-8");

        // 创建API消息日志实体并设置基本信息
        ApiMessageLog apiMessageLog = new ApiMessageLog();
        apiMessageLog.setApiName(request.getRequestURI());
        apiMessageLog.setMsg(reqJsonStr);
        apiMessageLog.setType("1");
        apiMessageLog.setCtime(LocalDateTime.now());

        // 尝试解析JSON字符串
        JSONObject json = null;

        try {
            json = JSONObject.parseObject(reqJsonStr);
        } catch (JSONException e) {
            // 如果JSON格式错误,返回错误信息并记录日志
            String r = "请求JSON格式错误!!!";
            response.getOutputStream().write(r.getBytes("utf-8"));
            apiMessageLog.setResult(r);
            MemDataTable.API_MESSAGE_LOGS.offer(apiMessageLog);
            return false;
        }

        // 从JSON中获取OperatorID并设置到API消息日志实体
        String operatorID = json.getString("OperatorID");
        apiMessageLog.setOperatorId(operatorID);

        // 将API消息日志的ID设置到请求属性中
        request.setAttribute("ApiMessageLogId", apiMessageLog.getId());

        // 将API消息日志存储到ThreadLocal中,以便后续处理
        apiMessageLogThreadLocal.set(apiMessageLog);
        return true;
    }
}

2 拦截器配置

这里可以选择性只记录哪些请求开头的日记。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author hua
 * @Description Web配置类,实现WebMvcConfigurer接口用于配置Web相关的功能。
 */
@Configuration
public class WebConfiguration implements WebMvcConfigurer {

    /**
     * 配置跨域访问规则
     *
     * @return CorsConfiguration对象
     */
    private CorsConfiguration corsConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        // 允许所有来源
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");

        return corsConfiguration;
    }

    /**
     * 配置CorsFilter,用于处理跨域请求
     *
     * @return CorsFilter对象
     */
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfig());
        return new CorsFilter(source);
    }

    /**
     * 配置中电联拦截器的Bean
     *
     * @return ZdlInterceptor对象
     */
    @Bean
    public HandlerInterceptor getZdlInterceptor() {
        return new ZdlInterceptor();
    }

    /**
     * 配置拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(getZdlInterceptor())
                // 设置不拦截的路径
                .excludePathPatterns("/public/**", "")
                // 设置拦截的路径
                .addPathPatterns("/api/zdl/**");
    }
}

3 实现效果

最终保存在数据库效果,可以根据业务情况记录,如记录访问ip,时间等。

 

 

二 注解方式实现项目日记

1 引入需用到jar包

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

  2 实现日记注解类

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 日记
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAnno {
    /**
     * 操作内容
     */
    String desc() default "";

    /**
     * 关键参数
     * @return
     */
    String key() default "";

}
import org.aspectj.lang.ProceedingJoinPoint;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.time.Duration;
import java.time.LocalDateTime;

@Aspect
@Component
public class LogAspect {

    @Autowired
    private ISysLogService sysLogService;

    /**
     * 定义切点
     */
    @Pointcut("@annotation(cn.enjoyiot.backend.config.aop.LogAnno)")
    public void initLogAnno() {
    }


    @Around(value = "initLogAnno()")
    public Object saveSysLog(ProceedingJoinPoint joinPoint) {


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

        //获取切入点所在的方法
        Method method = signature.getMethod();
        LogAnno operation = method.getAnnotation(LogAnno.class);

        if (operation != null) {
            String value = operation.desc();
            sysLog.setOperation(value);//保存获取的操作
        }

        //获取请求的类名
        String className = joinPoint.getTarget().getClass().getName();
        //获取请求的方法名
        String methodName = method.getName();
        sysLog.setMethod(className + "." + methodName);
        //请求的参数
        Object[] args = joinPoint.getArgs();
        //将参数所在的数组转换成json
        String params = "";
        try {
            if (args.length > 0) {
                for (Object p : args) {
                    if(checkLogParam(p)){
                        params = params + JSONObject.toJSONString(p) + " ";
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        sysLog.setParams(params);

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        sysLog.setIp(IpUtil.getRealIP(request));
        sysLog.setUri(request.getRequestURI());
        SysUser sysUser = SessionUtil.getSysUser();
        if (sysUser != null) {
            sysLog.setUserId(sysUser.getId());
            sysLog.setUsername(sysUser.getUsername());
            sysLog.setAccount(sysUser.getAccount());
        }
        LocalDateTime begin = LocalDateTime.now();

        /*执行目标方法*/
        try {
            Object result = joinPoint.proceed();
            return result;
        } catch (Throwable e) {
            e.printStackTrace();
            sysLog.setExceptionMessage(e.getMessage());
            return RespUtil.respErr(e.getMessage());
        } finally {
            LocalDateTime end = LocalDateTime.now();
            long sec = Duration.between(begin, end).getSeconds();
            sysLog.setCreateTime(end);
            sysLog.setTime(sec);
            sysLogService.save(sysLog);

        }


    }

    private boolean checkLogParam(Object p) {

        if(p==null){
            return false;
        }
        if(StringUtils.isEmpty(p)){
            return false;
        }
        if(p instanceof HttpServletRequest){
           return false;
        }else if(p instanceof HttpServletResponse){
            return false;
        }else if(p instanceof InputStreamSource){
            return false;
        }
        return true;
    }


}

 3 注解使用

    @PostMapping(value = "/couponList")
    @LogAnno(desc="账户列表")
    @PreAuthorize("hasPermission(filterObject,'accountList')")
    public String accountList(@RequestBody PageParam param) {
       return "test";
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/262858.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在做题中学习(37):复写零

1089. 复写零 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a;双指针法 1.因为是就地修改不能用新数组&#xff0c;但可以试试看看结果是什么&#xff08;结尾数是4&#xff09; &#xff08;cur遍历数组&#xff09;&#xff08;当cur&#xff01;0时替换一个 当c…

FFmpeg windows安装与使用

FFmpeg下载&#xff1a; 1、进入ffmpeg官网&#xff0c;点击“Download”。官网地址&#xff1a;FFmpeg 2、选择对应环境的编译工具&#xff0c;如下载windows环境下的ffmpeg编译工具 3、点击下载编译好的ffmpeg工具 FFmpeg使用&#xff1a; 1、将ffmpeg编译的bin文件复制出来…

【大模型】1、LoRA | 大模型高效微调技术

文章目录 一、背景1.1 什么是秩1.2 为什么要用低秩 二、方法三、效果 论文&#xff1a;LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS 代码&#xff1a;https://github.com/microsoft/LoRA 出处&#xff1a;微软 一、背景 1.1 什么是秩 矩阵的秩是指其行&#xff0…

Tomcat转SpringBoot、tomcat升级到springboot、springmvc改造springboot

Tomcat转SpringBoot、tomcat升级到springboot、springmvc改造springboot 起因&#xff1a;我接手tomcat-springmvc-hibernate项目&#xff0c;使用tomcat时问题不大。自从信创开始&#xff0c;部分市场使用国产中间件&#xff0c;例如第一次听说的宝兰德、东方通&#xff0c;还…

算法模板之栈图文详解

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;算法模板、数据结构 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. ⛳️模拟栈1.1 &#x1f514;用数组模拟实现栈1.1.1 &#x1f47b;栈的定义1.1.…

R语言贝叶斯网络模型、INLA下的贝叶斯回归、R语言现代贝叶斯统计学方法、R语言混合效应(多水平/层次/嵌套)模型

目录 ㈠ 基于R语言的贝叶斯网络模型的实践技术应用 ㈡ R语言贝叶斯方法在生态环境领域中的高阶技术应用 ㈢ 基于R语言贝叶斯进阶:INLA下的贝叶斯回归、生存分析、随机游走、广义可加模型、极端数据的贝叶斯分析 ㈣ 基于R语言的现代贝叶斯统计学方法&#xff08;贝叶斯参数估…

如何把透明OLED显示屏介绍给用户人群

透明OLED显示屏是一种新型的显示技术&#xff0c;它具有透明度高、色彩鲜艳、对比度高、响应速度快等优点。下面是一些介绍透明OLED显示屏的要点&#xff1a; 透明度&#xff1a;透明OLED显示屏的最大特点是其透明度&#xff0c;它可以让光线透过显示屏&#xff0c;使得屏幕背后…

TG5032CGN TCXO / VC-TCXO(超高稳定10pin端子型)

TG5032CGN 晶振是EPSON推出的一款额定频率10MHz至40MHz的石英晶体振荡器&#xff0c;该型号采用互补金属氧化物半导体技术&#xff0c;输出波形稳定可靠。外形尺寸为5.0 3.2 1.45mm具有小尺寸,高稳定性。该款晶体振荡器&#xff0c;可以在G&#xff1a;-40C至 85C的温度内稳定…

共建还是对抗?BTC 铭文风波中开发者、矿工与社区的平衡艺术

近期&#xff0c;比特币铭文正加速进入一场争议与危机的漩涡。12 月 6 日&#xff0c;比特币核心开发人员 Luke Dashjr 在 X 表示&#xff0c;铭文&#xff08;Inscriptions&#xff09;正在利用比特币核心客户端 Bitcoin Core 的一个漏洞向区块链发送垃圾信息&#xff0c;Bitc…

在灾难推文分析场景上比较用 LoRA 微调 Roberta、Llama 2 和 Mistral 的过程及表现

引言 自然语言处理 (NLP) 领域的进展日新月异&#xff0c;你方唱罢我登场。因此&#xff0c;在实际场景中&#xff0c;针对特定的任务&#xff0c;我们经常需要对不同的语言模型进行比较&#xff0c;以寻找最适合的模型。本文主要比较 3 个模型: RoBERTa、Mistral-7B 及 Llama-…

基于javaWeb的長安智慧医疗管理系统设计与实现论文

長安智慧医疗管理系统 摘 要&#xff1a;如今社会上各行各业&#xff0c;都在用属于自己专用的软件来进行工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。互联网的发展&#xff0c;离不开一些新的技术&#xff0c;而新技术的产生往往是为了解决…

Shell 脚本应用(三)

使用 for 循环语句 for语句的结构 使用for循环语句时&#xff0c;需要指定一个变量及可能的取值列表&#xff0c;针对每个不同的取值重复执行相同 的命令序列&#xff0c;直到变量值用完退出循环。在这里&#xff0c;“取值列表”称为for语句的执行条件&#xff0c;其中包括多…

makefile例子

1、目录结构 2、文件 2.1、 test.h extern void test(void); 2.2 、test.c #include <stdio.h>void test(void) {printf("Hello world!\n"); }2.3 、main.c #include "test.h"int main(void) {test();return 0; }2.4、makefile TEST_DIR : $(s…

ai学习笔记-入门

目录 一、人工智能是什么&#xff1f;可以做什么&#xff1f; 人工智能(Artificial Intelligence): 人工智能的技术发展路线&#xff1a; 产业发展驱动因素&#xff1a;数据、算力、算法 二、人工智能这个工具的使用原理入门 神经网络⭕数学基础 1.神经网络的生物表示 …

SpringMVC:执行原理详解、配置文件和注解开发实现 SpringMVC

文章目录 SpringMVC - 01一、概述二、SpringMVC 执行原理三、使用配置文件实现 SpringMVC四、使用注解开发实现 SpringMVC1. 步骤2. 实现 五、总结注意&#xff1a; SpringMVC - 01 一、概述 SpringMVC 官方文档&#xff1a;点此进入 有关 MVC 架构模式的内容见之前的笔记&a…

小红书kos和kop有什么区别,营销玩法有哪些

相信熟悉媒介传播的朋友&#xff0c;对于kol和koc都不陌生。但随着平台的发展和市场的进步&#xff0c;又出现了kos和kop。那么小红书kos和kop有什么区别&#xff0c;营销玩法有哪些&#xff1f; 一、什么是kos和kop KOS&#xff0c;全称叫做Key Opinion Sales&#xff0c;意思…

安装 PyCharm 2021.1 保姆级教程

作者&#xff1a;billy 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 前言 目前能下载到的最新版本是 PyCharm 2021.1。 请注意对应 Python 的版本&#xff1a; Python 2: 2.7Python 3: >3.6, <3.11…

APEX后台弱密码增强改造出现的问题及解决方法

为了加强APEX后台密码的安全性和可靠性&#xff0c;对其进行弱密码改造&#xff0c;通过改写登录函数&#xff0c;判断密码可靠性&#xff0c;在密码不符合条件&#xff08;密码长度必须大于8位小于16位&#xff0c;其包含数字、大小写字母与特殊符号&#xff09;时跳转到密码修…

网络基础篇【网线的制作,OSI七层模型,集线器和交换机的介绍,路由器的介绍与设置】

目录 一、网线制作 1.1 工具介绍 1.1.1网线 1.1.2 网线钳 1.1.3 水晶头 1.1.4 网线测试仪 二、OSI七层模型 2.1 简介 2.2 OSI模型层次介绍 2.2.1 结构图 2.2.2 数据传输过程 2.3 相关网站 二、集线器 2.1 介绍 2.2 适用场景 三、交换机 3.1 介绍 3.2 适用场景…

Linux(二)常用命令

文章目录 一、文件管理命令1.1 chmod1.2 chown1.3 cat1.4 cp1.5 find1.6 head1.7 tail1.8 less1.9 more1.10 mv1.11 rm1.12 touch1.13 vim1.14 >和>>1.15 scp1.16 ln1.17 怎么用命令查看日志 二、文档管理命令2.1 grep2.2 wc2.3 echo 三、磁盘管理命令3.1 cd3.2 df3.3…