若依日志打印入参,返回参数,日志切面打印接口调用,出现一个接口多次调用的情况且,多次调用返回值为null,initBinder的原因。

使用若依Springboot项目,Controller均继承BaseController。
这里若依原日志切面不会打印接口请求参数,返回参数等信息,这里我做了修改。

修改后日志打印出现一个接口调用4次,5次的情况

15:08:58.342 [http-nio-8082-exec-4] INFO  c.s.f.a.LogAspect - [doBefore,103] -
=== 开始请求 ===
request-url:http://localhost:8082/xxx/xxx/xxx
request-desc:
request-method:POST
request-ip:
class-method:com.syt.api.controller.BaseController.initBinder
request-param:{"sign":["00001111111dddddddddddd"]}=== 返回值 ===
null
==== time cost ======= 开始请求 ===
request-url:http://localhost:8082/xxx/xxx/xxx
request-desc:
request-method:POST
request-ip:
class-method:com.syt.api.controller.BaseController.initBinder
request-param:{"sign":["00001111111dddddddddddd"]}=== 返回值 ===
null
==== time cost ====........

这里出现问题就是BaseController.initBinder方法重复调用了好几次,且返回值均为null。
BaseController.initBinder这个方法使用注解 @InitBinder
源代码为:

    /*** 将前台传递过来的日期格式的字符串,自动转化为Date类型*/@InitBinderpublic void initBinder(WebDataBinder binder){// Date 类型转换binder.registerCustomEditor(Date.class, new PropertyEditorSupport(){@Overridepublic void setAsText(String text){setValue(DateUtils.parseDate(text));}});}

@InitBinder从字面意思可以看出这个的作用是给Binder做初始化的,@InitBinder主要用在@Controller中标注于方法上(@RestController也算),表示初始化当前控制器的数据绑定器(或者属性绑定器),只对当前的Controller有效。@InitBinder标注的方法必须有一个参数WebDataBinder。所谓的属性编辑器可以理解就是帮助我们完成参数绑定,然后是在请求到达controller要执行方法前执行!
链接: 原文地址

为避免在日志重复显示接口调用,需要处理日志切面LogAspect.java,在@Before注解下的方法添加下面代码

    @Before("pointcut()")public void doBefore(JoinPoint joinPoint) throws Exception {*****Signature signature1 = joinPoint.getSignature();MethodSignature signature = (MethodSignature) signature1;//如果获取的方法名为initBinder,则直接returnif (signature.getMethod().getName().contains("initBinder")) {return;}******}

@AfterReturning注解的方法需要修改

    @AfterReturning(returning = "ret", pointcut = "pointcut()")public void doAfterReturning(Object ret) {if (!isDoReturning) {return;}//这里需要添加是否为空判断,不然会报错if (StringUtils.isNotNull(ret)) {log.info("\n=== 返回值 ===\n" + JSON.toJSONString(ret));log.info("\n==== time cost" + ((System.currentTimeMillis() - threadLocal.get())) + "ms" + " ====\n");}return;}

finish:修改后文件如下所示LogAspect.java

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;import com.alibaba.fastjson.JSON;
import io.swagger.annotations.ApiOperation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import com.syt.common.utils.StringUtils;/*** 操作日志记录处理* * @author syt*/
@Aspect
@Component
public class LogAspect
{private static final Logger log = LoggerFactory.getLogger(LogAspect.class);@Autowiredprivate Environment env;private static boolean isDoBefore = false;private static boolean isDoAfter = false;private static boolean isDoReturning = false;private static boolean isDoThrowing = false;/*** 保证每个线程都有一个单独的实例*/private ThreadLocal<Long> threadLocal = new ThreadLocal<>();private static String[] params;static {params = new String[]{"aspect.logger.spring-application-name", "aspect.logger.request-url", "aspect.logger.request-uri","aspect.logger.request-desc", "aspect.logger.session", "aspect.logger.cookie","aspect.logger.content-type", "aspect.logger.request-method", "aspect.logger.request-ip","aspect.logger.request-user-agent", "aspect.logger.class-method", "aspect.logger.request-param"};}@PostConstructpublic void init() {isDoBefore = env.getProperty("aspect.do-before") == null ? false : env.getProperty("aspect.do-before", Boolean.class);isDoAfter = env.getProperty("aspect.do-after") == null ? false : env.getProperty("aspect.do-after", Boolean.class);isDoReturning = env.getProperty("aspect.do-returning") == null ? false : env.getProperty("aspect.do-returning", Boolean.class);isDoThrowing = env.getProperty("aspect.do-throwing") == null ? false : env.getProperty("aspect.do-throwing", Boolean.class);}@Pointcut("execution(* com.syt.*.controller..*(..))")public void pointcut() {}@Before("pointcut()")public void doBefore(JoinPoint joinPoint) throws Exception {if (!isDoBefore) {return;}Signature signature1 = joinPoint.getSignature();MethodSignature signature = (MethodSignature) signature1;if (signature.getMethod().getName().contains("initBinder")) {return;}threadLocal.set(System.currentTimeMillis());ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();StringBuilder stringBuilder = new StringBuilder().append("\n=== 开始请求 ===\n");// 记录请求的内容this.logHandle(joinPoint, params, request, stringBuilder);log.info(stringBuilder.toString());return;}@After("pointcut()")public void doAfter(JoinPoint joinPoint) {if (!isDoAfter) {return;}log.info("\n==== doAfter ===\n" + joinPoint.toString());}/*** 返回值信息** @param ret*/@AfterReturning(returning = "ret", pointcut = "pointcut()")public void doAfterReturning(Object ret) {if (!isDoReturning) {return;}if (StringUtils.isNotNull(ret)) {log.info("\n=== 返回值 ===\n" + JSON.toJSONString(ret));log.info("\n==== time cost" + ((System.currentTimeMillis() - threadLocal.get())) + "ms" + " ====\n");}return;}@AfterThrowing(throwing = "ex",pointcut = "pointcut()")public void doThrowing(Throwable ex){if (!isDoThrowing) {return;}log.error("\n=== 异常 ===\n" + ex);}/*** 获取注解中对方法的描述信息 用于Controller层注解** @param joinPoint 切点* @return 方法描述* @throws Exception*/private String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {String targetName = joinPoint.getTarget().getClass().getName();String methodName = joinPoint.getSignature().getName();Object[] arguments = joinPoint.getArgs();Class targetClass = Class.forName(targetName);Method[] methods = targetClass.getMethods();String description = "";for (Method method : methods) {if (method.getName().equals(methodName)) {Class[] clazzs = method.getParameterTypes();if (clazzs.length == arguments.length) {Object temp = method.getAnnotation(ApiOperation.class);if (temp != null) {description = method.getAnnotation(ApiOperation.class).value();}break;}}}return description;}/*** 处理请求参数输出** @param joinPoint* @param requestParams* @param request* @param stringBuilder* @throws Exception*/public void logHandle(JoinPoint joinPoint, String[] requestParams, HttpServletRequest request, StringBuilder stringBuilder) throws Exception {Map<String, Object> paramMap = new HashMap<>(16);String contentType = request.getContentType();paramMap.put("session", request.getSession());paramMap.put("cookie", request.getCookies());paramMap.put("spring-application-name", env.getProperty("spring.application.name"));paramMap.put("request-url", request.getRequestURL());paramMap.put("request-uri", request.getRequestURI());paramMap.put("request-param", JSON.toJSONString(request.getParameterMap()));paramMap.put("request-desc", getControllerMethodDescription(joinPoint));paramMap.put("request-method", request.getMethod());paramMap.put("content-type", contentType);paramMap.put("class-method", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());paramMap.put("request-ip", request.getRemoteAddr());paramMap.put("request-user-agent", request.getHeader("User-Agent"));String reqParam = null;Object[] o = joinPoint.getArgs();if (contentType != null && contentType.contains("multipart/form-data")) {MultipartFile file = (MultipartFile) o[0];reqParam = file.getOriginalFilename();} else {if (o != null && o.length > 0) {reqParam = o[0].toString();}}paramMap.put("aspect.logger.request-param", reqParam);// 按配置输出for (String param : requestParams) {Boolean property = env.getProperty(param, Boolean.class);String p = param.replace("aspect.logger.", "");if (property != null && property && paramMap.containsKey(p)) {stringBuilder.append(p + ":" + paramMap.get(p) + "\n");}}}
}

配置文件applicaton-test.yml添加下面配置,这里aspect顶格

# 日志切面处理
aspect:logger:spring-application-name: falserequest-url: truerequest-uri: falseclass-method: truerequest-method: truerequest-param: truerequest-desc: truerequest-ip: truerequest-user-agent: falsecontent-type: falsesession: falsecookie: falsedo-before: truedo-after: falsedo-returning: truedo-throwing: true

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

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

相关文章

DevOps系列文章之 Git知识大全

常用命令 其他参数 --inital-branch 初始化的分支 --bare 创建一个裸仓库&#xff08;纯 Git 目录&#xff0c;没有工作目录&#xff09; --template 可以通过模板来创建预先建好的自定义 git 目录 常见 Git 配置 用户名配置 git config --global user.name "yourname&qu…

Oracle压缩数据

Oracle压缩数据的处理基于数据库块&#xff0c;其本质上是通过消除在数据库块中的重复数据来实现空间节约&#xff0c;具体方法如下&#xff1a;比较数据块中包含的所有字段或记录&#xff0c;其中重复的数据只在位于数据块开始部分的记号表&#xff08;Symbol Table&#xff0…

基于Springboot的汽车租赁系统

摘要 首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要包括软件架构模式、整体功能模块、数据库设计。…

信息熵和决策树

在预测分析领域&#xff0c;决策树是可应用于回归和分类任务的算法之一 决策树背后的想法是&#xff0c;根据数据集中的特征对当时响应变量的贡献方式&#xff0c;递归地构建一个颠倒的树状结构。 在每次迭代中&#xff0c;将以使得所得模型最小化成本函数的方式选择特征。 该结…

cmder 使用简介

文章目录 1. cmder 简介2. 下载地址3. 安装4. 配置环境变量5. 添加 cmder 到右键菜单6. 解决中文乱码问题 1. cmder 简介 cmder 是一个增强型命令行工具&#xff0c;不仅可以使用 windows 下的所有命令&#xff0c;更爽的是可以使用 linux的命令, shell 命令。 2. 下载地址 …

选择合适的图表,高效展现数据魅力

随着大数据时代的来临&#xff0c;数据的重要性愈发凸显&#xff0c;数据分析和可视化成为了决策和传递信息的重要手段。在数据可视化中&#xff0c;选择合适的图表是至关重要的一环&#xff0c;它能让数据更加生动、直观地呈现&#xff0c;为观众提供更有说服力的信息。本文将…

模型构建——使用逻辑回归构建模型,lightGBM进行特征筛选

1、模型构建流程 1.1 实验设计 新的模型要跟原有方案对比&#xff0c;而且是通过实验证明&#xff0c;特别注意模型和策略不能同时调整。一般实验设计包含以下流程&#xff1a; 问题&#xff1a;业务稳定后&#xff0c;可以去掉人工审核吗&#xff1f; 答&#xff1a;不可以…

React拆分窗格组件

React拆分窗格的两种方法 react-split-pane 使用第三方库react-split-pane的优点&#xff1a; 方便快捷&#xff1a;使用现有的第三方库可以快速实现拆分窗格功能&#xff0c;无需自己编写复杂的逻辑。 功能丰富&#xff1a;第三方库通常提供了许多可配置的选项和功能&…

c语言练手项目【编写天天酷跑游戏2.0】EASYX图形库的运用。代码开源,素材已打包

天天酷跑项目的开发 项目前言 项目是基于Windows&#xff0c;easyX图形库进行开发的&#xff0c; 开发环境&#xff1a;Visual Studio 2022 项目技术最低要求&#xff1a; 常量&#xff0c;变量&#xff0c;数组&#xff0c;循环&#xff0c;函数。 文章目录 天天酷跑项目的…

超详细-Vivado配置Sublime+Sublime实现Verilog语法实时检查

目录 一、前言 二、准备工作 三、Vivado配置Sublime 3.1 Vivado配置Sublime 3.2 环境变量添加 3.3 环境变量验证 3.4 Vivado设置 3.5 配置验证 3.6 解决Vivado配置失败问题 四、Sublime配置 4.1 Sublime安装Package Control 4.2 Sublime安装Verilog插件 4.3 安装语…

#pragma region用法

简介 #pragma region 是VS(Visio Studio)所特有的预处理语法&#xff08;其他IDE或者Cmake会报错&#xff09;&#xff0c;其可以用来收缩或者展开一段代码。 #pragma region MyRegion// ...Code content #pragma endregion 其中&#xff0c;MyRegion 即给这代码块所定义的名…

工业边缘网关HiWoo Box的4G/5G CPE功能:为现场无线设备提供网络

引言 随着工业物联网的快速发展&#xff0c;现场设备的无线连接需求越来越迫切。然而&#xff0c;在一些室外或者不方便布网的场景下&#xff0c;为现场的无线设备提供网络仍然是一个挑战。为了满足这一需求&#xff0c;工业边缘网关HiWoo Box引入了4G/5G CPE&#xff08;Cust…

【计算机网络】简易TCP网络小程序

文章目录 1. 简易TCP网络程序1.1 服务端1.1.1 服务端创建套接字1.1.2 服务端绑定1.1.3 服务端监听1.1.4 服务端获取连接1.1.5 服务端处理请求 1.2 客户端1.2.1 客户端创建套接字1.2.2 客户端连接服务器1.2.3 客户端发起请求 1.3 服务器测试1.4 单执行流服务器的弊端 2. 多进程版…

【Java】 服务器cpu过高如何排查和解决?

文章目录 前言一、常见能够引起CPU100%异常的情况都有哪些&#xff1f;二、服务器CPU使用率飙升异常&#xff0c;黄金4步排查法三、排查 CPU 故障的常用命令四、什么场景会造成 CPU 低而负载确很高呢&#xff1f;五、监控发现线上机器内存占用率居高不下&#xff0c;如何分析进…

网络性能测试诊断参考工具表

性能指标工具说明吞吐量&#xff08;BPS&#xff09;sar nethogs iftop分别可以查看网络接口、进程以及 IP 地址的网络吞吐量PPSsar /proc/net/dev查看网络接口的 PPS连接数netstat ss查看连接数延迟ping hping3通过 ICMP、TCP 等测试网络延迟连接跟踪数conntrack查看和管理连接…

django groupby踩坑

django groupby踩坑 前言坑 ~~参考~~ 前言 django的orm作为简单查询 使用简直是太爽了&#xff0c;所见即所得,但是groupby时候缺有一些坑点 坑 from django.db.models import Count from w.models import www # 在不加order by的时候 会默认按照id分组 print(TaskPort.obje…

webpack require.context

require.context((directory: String),(includeSubdirs: Boolean) /* 可选的&#xff0c;默认值是 true */,(filter: RegExp) /* 可选的&#xff0c;默认值是 /^\.\/.*$/&#xff0c;所有文件 */,(mode: String) /* 可选的&#xff0c; sync | eager | weak | lazy | lazy-onc…

RPA界面元素定位与操控技术详解-达观数据

RPA 入门介绍 什么是 RPA&#xff1f;RPA 是机器人流程自动化 Robotic Process Automation 的简写。在《智能RPA实战》中&#xff0c;我们这样定义&#xff1a;通过特定的、可模拟人类在计算机界面上进行操作的技术&#xff0c;按照规则自动执行相应的流程任务&#xff0c;代替…

【Ubuntu】完全卸载通过deb包安装的jenkins

要完全卸载通过Deb包安装的Jenkins&#xff0c;可以按照以下步骤操作&#xff1a; 停止Jenkins服务&#xff1a;首先&#xff0c;停止Jenkins服务&#xff0c;以确保它不再运行。 sudo systemctl stop jenkins禁用Jenkins服务&#xff1a;将Jenkins服务设置为在系统启动时不自动…

Linux QT通过NFS挂载到Linux开发板上

Linux QT通过NFS挂载到Linux开发板上 说明&#xff1a;这里使用的Linux开发板是正点原子的阿尔法开发板 创建NFS 环境 NFS简介 网络文件系统&#xff0c;英文 Network File System(NFS)&#xff0c;是由 SUN 公司研制的 UNIX 表示层协议 (presentation layer protocol)&…