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<>();// 用于记录日志的Loggerpublic 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);}// 从请求属性中设置连接器IDString _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实例@AutowiredStringRedisTemplate stringRedisTemplate;// 注入ApiMessageLogServiceImpl实例@AutowiredApiMessageLogServiceImpl apiMessageLogService;/*** 在请求处理前执行的方法** @param request  HTTP请求对象* @param response HTTP响应对象* @param handler  处理请求的处理程序* @return 如果继续处理请求,则返回true;否则,返回false* @throws Exception 如果在处理过程中发生异常*/@Overridepublic 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对象*/@Beanpublic CorsFilter corsFilter() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", corsConfig());return new CorsFilter(source);}/*** 配置中电联拦截器的Bean** @return ZdlInterceptor对象*/@Beanpublic HandlerInterceptor getZdlInterceptor() {return new ZdlInterceptor();}/*** 配置拦截器*/@Overridepublic 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 {@Autowiredprivate 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();//将参数所在的数组转换成jsonString 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";}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

逻辑斯蒂回归-建模概率计算(鸢尾花)

导入的数据说明 因为气候不同&#xff0c;造就性不同&#xff0c;统计鸢尾花的关键特征数据&#xff1a;花萼长度、花萼宽度、花瓣长度&#xff0c;花瓣宽度 植物学家划分&#xff1a; setosa(中文名&#xff1a;山鸢尾) versicolor(中文名&#xff1a;杂色鸢尾) virginica(中…

小鹅通基于 TSE 云原生 API 网关的落地实践

导语 2023腾讯全球数字生态大会已于9月7-8日完美落幕&#xff0c;40专场活动展示了腾讯最新的前沿技术、核心产品、解决方案。 微服务与消息队列专场&#xff0c;我们邀请到了小鹅通的基础架构组负责人黄徐震为我们带来了《小鹅通基于 TSE 云原生网关的落地实践》的精彩演讲。…

鹦鹉目标检测数据集VOC+YOLO格式2000张

鹦鹉是一种非常受欢迎的鸟类&#xff0c;它们通常生活在热带和亚热带地区的森林和草原中。鹦鹉是一种非常聪明、有趣和亲密的动物&#xff0c;也是一种受到广泛关注和保护的物种。 鹦鹉的身体结构非常适应于它们的生活方式。它们的身体非常修长&#xff0c;有着漂亮的羽毛和强…

flutter开发windows应用的库

一、window_manager 这个插件允许 Flutter 桌面应用调整窗口的大小和位置 地址&#xff1a;https://github.com/leanflutter/window_manager二、win32 一个包&#xff0c;它使用FFI包装了一些最常见的Win32 API调用&#xff0c;使Dart代码可以访问这些调用&#xff0c;而不需…

腾讯云服务器上传文件 :Permission denied (os error 13) ,由于权限无法上传

根据网上的修改云服务器上传文件目录的权限&#xff0c;或是用root权限上传本地文件&#xff0c;均失败。 正解办法&#xff1a; ubuntu:/home/wwwroot# sudo passwd root Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully首先修…

【论文笔记】NeuRAD: Neural Rendering for Autonomous Driving

原文链接&#xff1a;https://arxiv.org/abs/2311.15260 1. 引言 神经辐射场&#xff08;NeRF&#xff09;应用在自动驾驶中&#xff0c;可以创建可编辑的场景数字克隆&#xff08;可自由编辑视角和场景物体&#xff09;&#xff0c;以进行仿真。但目前的方法或者需要大量的训…

图像处理—小波变换

小波变换 一维小波变换 因为存在 L 2 ( R ) V j 0 ⊕ W j 0 ⊕ W j 0 1 ⊕ ⋯ L^{2}(\boldsymbol{R})V_{j_{0}}\oplus W_{j_{0}}\oplus W_{j_{0}1}\oplus\cdots L2(R)Vj0​​⊕Wj0​​⊕Wj0​1​⊕⋯&#xff0c;所以存在 f ( x ) f(x) f(x)可以在子空间 V j 0 V_{j_0} Vj0…

springboot使用Validated实现参数校验

做为后端开发人员&#xff0c;一定有前端传的数据是可能会出错的警惕性&#xff0c;否则程序就可能会出错&#xff0c;比如常遇到的空指针异常&#xff0c;所以为了程序运行的健壮性&#xff0c;我们必须对每一个参数进行合法校验&#xff0c;就能避免很多不必要的错误&#xf…

【高效开发工具系列】eclipse部署web项目

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

el-select绑定值的坑

碰到一个问题&#xff0c;选择框的数据是后端传过来的&#xff0c;下拉框的数据也是后端传过来的&#xff0c;但是打开下拉框时&#xff0c;发现数据没有高亮。 最后发现&#xff0c;只要选择框v-model给的值和option的value绑定的值一致&#xff0c;就可以高亮。 大多数情况下…

机器学习——分类评价指标

【说明】文章内容来自《机器学习——基于sklearn》&#xff0c;用于学习记录。若有争议联系删除。 1、评价指标 对于模型的评价往往会使用损失函数和评价指标&#xff0c;两者的本质是一致的。一般情况下&#xff0c;损失函数应用于训练过程&#xff0c;而评价指标应用于测试过…

【Xcode】解决Unable to process request - PLA Update available

出现场景 IOS更新app时&#xff0c;使用Xcode上传新版本的包时&#xff0c;提示无法上传。 Unable to process request -PLA update available you currently dont have access to this membership resource. To resolve this issue ,agree to the latest program license a…

Flutter ExpansionPanelList 去除展开后的间隔距离,及属性

可展开列表中&#xff0c;展开后条目有一个间距&#xff0c;可以 使用materialGapSize: 0&#xff0c;来去掉 // child: ExpansionPanelList(//expandedHeaderPadding: EdgeInsets.zero,//头部顶部间隔// materialGapSize: 15,//展开后的间距// animationDuration: const …

实在智能成功完成近2亿元C轮融资,全面迎接2024年Agent智能体应用元年

在这个最冷的季节&#xff0c;杭州实在智能科技有限公司&#xff08;以下简称“实在智能”&#xff09;依然表现火爆&#xff0c;近日&#xff0c;实在智能成功完成C轮融资近2亿元人民币&#xff0c;由金泰富资本和安吉智慧谷共同领投、安吉两山国创跟投。 在此轮融资以前&…

61权限提升-RedisPostgre令牌窃取进程注入

主要讲解redis数据库和postgresql数据库&#xff0c;然后还要两个windows的提权方式令牌窃取和进程注入。 postgresql是基于两个cve的漏洞&#xff0c;redis的提权方式第一种是利用任务执行的反弹shell&#xff0c;第二个是写一个ssh-keygen的公钥使用私钥登录&#xff0c;这是…

[SWPUCTF 2021 新生赛]Do_you_know_http已

打开环境 它说用WLLM浏览器打开&#xff0c;使用BP抓包&#xff0c;发送到重发器 修改User-Agent 下一步&#xff0c;访问a.php 这儿他说添加一个本地地址&#xff0c;它给了一个183.224.40.160&#xff0c;我用了发现没用&#xff0c;然后重新添加一个地址&#xff1a;X-Forwa…

QListView的setResizeMode,setViewMode,setFlow

参考&#xff1a; qt的QListwiget设置横向的排列_qlistwidget 横排-CSDN博客 希望实现类似的效果&#xff1a; 感觉关键是搞清楚这三句&#xff1a; list.setViewMode(QListView::IconMode);list.setFlow(QListView::LeftToRight);list.setResizeMode(QListView::Adjust); …

mysql自增序列 关于mysql线程安全 独享内存 溢出 分析

1 MySQL锁概述 锁是计算机协调多个进程或线程并发访问某一资源的机制。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题&#xff0c;锁冲突也是影响数据库并发访问性能的一个重要因素。 相对其他数据库而言&#xff0c;MySQL的锁机制比较简单&#xff0c…

nginx 离线安装 https反向代理

这里写自定义目录标题 安装步骤1.安装nginx所需依赖1.1 安装gcc和gcc-c1.1.1下载依赖包1.1.2 上传依赖包1.1.3安装依赖 1.2 安装pcre1.2.1 下载pcre1.2.2 上传解压安装包1.2.3 编译安装 1.3 下载安装zlib1.3.1 下载zlib1.3.2 上传解压安装包1.3.3 编译安装 1.4 下载安装openssl…

STM32G4x FLASH 读写配置结构体(LL库下使用)

主要工作就是把HAL的超时用LL库延时替代&#xff0c;保留了中断擦写模式、轮询等待擦写&#xff0c;我已经验证了部分。 笔者用的芯片为STM32G473CBT6 128KB Flash&#xff0c;开环环境为CUBEMXMDK5.32&#xff0c;因为G4已经没有标准库了&#xff0c;笔者还是习惯使用标准库的…