Java教程:如何使用切面环绕方法对所有接口进行添加出入参日志保存功能

背景:

----在很多时候我们做开发时,往往只是提供一个对外接口来进行前后端调试,或第三方系统联调,并使用log进行日志打印,每当出现问题进行排查时,只需要查看服务器日志就可以定位到问题,从而解决问题,但当接口慢慢变多,公司开发部署方案越来越成熟时,分工明确,查看服务器日志却变得不那么随意,这个时候如果还和以前一样出现问题就打开服务器查看日志文件就会变得越来越困难,所以我们必须对重要日志信息进行数据库存储,出现问题直接在浏览器页面查看即可,非常方便,本章就来教大家如何使用切面的方式完成这一操作,方便快捷,使用简单,话不多说,教学开始~

第一步、首先我们需要创建一个注解接口:

/*** 接口日志记录注解** @author wfeil211@foxmail.com*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InterfaceLog {/*** 标题*/public String title() default "";}

第二步、创建接口日志保存实体类:

/*** 接口日志对象 interface_log** @author wfeil211@foxmail.com*/
@Data
public class InterfaceLog extends BaseEntity {private static final long serialVersionUID = 1L;/*** 主键*/private String id;/*** 接口说明*/private String title;/*** 接口入参*/private String requestParam;/*** 响应参数*/private String responseParam;/*** 方法名称*/private String methodName;/*** 请求方式*/private String requestWay;/*** 请求耗时(ms)*/private String handleTime;/*** 请求时间 yyyy-MM-dd HH:mm:ss*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date requestTime;/*** 错误信息*/private String errorInfo;/*** 错误码*/private String errorCode;/*** 用户ip*/private String userIp;/*** 服务器ip*/private String serverIp;/*** 接口状态(0正常 1异常)*/private String status;
}

第三步、创建我们的切面类,将第一步接口进行切入:

/*** 接口日志记录处理** @author wfeil211@foxmail.com*/
@Aspect
@Component
public class InterfaceLogAspect {private static final Logger log = LoggerFactory.getLogger(InterfaceLogAspect.class);// 接口日志@Autowiredprivate InterfaceLogService interfaceLogService;// 配置切入点@Pointcut("@annotation(com.feilin.InterfaceLog)")public void logPointCut() {}@Around("logPointCut()")public Object aroundBusAsMethod(ProceedingJoinPoint joinPoint) {// 获得注解InterfaceLog controllerLog = getAnnotationLog(joinPoint);if (controllerLog == null) {return null;}Object[] args = joinPoint.getArgs();long time;// 进入方法之前的时间StopWatch stopWatch = new StopWatch();stopWatch.start();InterfaceLog interfaceLog = new InterfaceLog();// 请求的地址String ip = IpUtils.getIpAddr(ServletUtils.getRequest());interfaceLog.setUserIp(ip);interfaceLog.setTitle(controllerLog.title());String hostAddress = "";try {hostAddress = InetAddress.getLocalHost().getHostAddress();} catch (UnknownHostException e) {e.printStackTrace();log.error("获取服务器ip异常,原因={}", e.toString());}interfaceLog.setServerIp(hostAddress);// 设置方法名称String methodName = joinPoint.getSignature().getName();interfaceLog.setMethodName(methodName);Object respObj = null;// 设置请求方式interfaceLog.setRequestWay(ServletUtils.getRequest().getMethod());try {respObj = joinPoint.proceed(args);} catch (Throwable e) {log.error("获取方法响应异常,原因:{}", e.toString());}stopWatch.stop();time = stopWatch.getTotalTimeMillis();// 请求时间与耗时interfaceLog.setHandleTime(String.valueOf(time));interfaceLog.setRequestTime(new Date());// 请求入参出参interfaceLog.setRequestParam(StringUtils.substring(argsArrayToString(args), 0, 2048));if (!ObjectUtils.isEmpty(respObj)) {interfaceLog.setResponseParam(StringUtils.substring(JSON.toJSONString(respObj), 0, 2048));JSONObject parse = (JSONObject) JSONObject.parse(interfaceLog.getResponseParam());String code = parse.getString("code");String msg = parse.getString("msg");if (!"0".equals(code)) {interfaceLog.setErrorCode(code);interfaceLog.setErrorInfo(msg);interfaceLog.setStatus("1");} else {interfaceLog.setStatus("0");}}try {interfaceLogService.insertInterfaceLog(interfaceLog);} catch (Throwable e) {log.error("接口日志保存失败,interfaceLog={},原因={}", interfaceLog.toString(), e.toString());}return respObj;}/*** 是否存在注解,如果存在就获取*/private InterfaceLog getAnnotationLog(JoinPoint joinPoint) {Signature signature = joinPoint.getSignature();MethodSignature methodSignature = (MethodSignature) signature;Method method = methodSignature.getMethod();if (method != null) {return method.getAnnotation(InterfaceLog.class);}return null;}/*** 参数拼装*/private String argsArrayToString(Object[] paramsArray) {String params = "";if (ArrayUtils.isNotEmpty(paramsArray) && paramsArray.length > 0 && !(paramsArray[0] instanceof BeanPropertyBindingResult)) {params = JSON.toJSON(paramsArray[0]).toString();} else {log.info("切面日志保存/打印,获取参数为空");}return params.trim();}/*** 判断是否需要过滤的对象。** @param o 对象信息。* @return 如果是需要过滤的对象,则返回true;否则返回false。*/@SuppressWarnings("rawtypes")public boolean isFilterObject(final Object o) {Class<?> clazz = o.getClass();if (clazz.isArray()) {return clazz.getComponentType().isAssignableFrom(MultipartFile.class);} else if (Collection.class.isAssignableFrom(clazz)) {Collection collection = (Collection) o;for (Iterator iter = collection.iterator(); iter.hasNext(); ) {return iter.next() instanceof MultipartFile;}} else if (Map.class.isAssignableFrom(clazz)) {Map map = (Map) o;for (Iterator iter = map.entrySet().iterator(); iter.hasNext(); ) {Map.Entry entry = (Map.Entry) iter.next();return entry.getValue() instanceof MultipartFile;}}return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;}
}

第四步、在我们的请求接口上加上注解:

@InterfaceLog(title = "获取参数")
@PostMapping("/test")
public Map<String, String> test(@RequestBody Map<String, String> parms){return parms;
}

最后一步、使用PostMan进行测试,大功告成!

在这里插入图片描述

本次教程到这里就结束了,希望大家多多关注支持(首席摸鱼师 微信同号),持续跟踪最新文章吧~

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

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

相关文章

docker之简介与安装

环境配置问题 没有虚拟机&#xff0c;我们往往是打包代码发给对方&#xff0c;然后让对方安装相应的环境&#xff0c;比如node、数据库&#xff0c;要是配置不同&#xff0c;项目很有可能无法运行&#xff0c;还会报错&#xff0c;如果多个人想要运行这份代码&#xff0c;那还得…

【Redis】Redis中的布隆过滤器

【Redis】Redis中的布隆过滤器 前言 在实际开发中&#xff0c;会遇到很多要判断一个元素是否在某个集合中的业务场景&#xff0c;类似于垃圾邮件的识别&#xff0c;恶意IP地址的访问&#xff0c;缓存穿透等情况。类似于缓存穿透这种情况&#xff0c;有许多的解决方法&#xf…

【计算机设计大赛】国赛一等奖项目分享——基于多端融合的化工安全生产监管可视化系统

文章目录 一、计算机设计大赛国赛一等奖二、项目背景三、项目简介四、系统架构五、系统功能结构六、项目特色&#xff08;1&#xff09;多端融合&#xff08;2&#xff09;数据可视化&#xff08;3&#xff09;计算机视觉&#xff08;目标检测&#xff09; 七、系统界面设计&am…

PyQt5资源的加载和使用,即如何使用Pyrcc

1、打开QtDesigner&#xff0c;选择编辑资源 2、新建资源文件&#xff0c;随便找个地方保存 3、按照自己的喜好命名&#xff0c;然后添加资源 4、保存并退出 5、我们创建一个QLabel&#xff0c;在这里添加资源 6、我们保存界面文件&#xff0c;并编译为py文件&#xff0c;然后…

GPT系列总结

1.GPT1 无监督预训练有监督的子任务finetuning https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf 1.1 Unsupervised pre-training &#xff08;1&#xff09;基于一个transformer decoder&#xff0c;通过一个窗口的输入得…

Python高光谱遥感数据处理与高光谱遥感机器学习方法教程

详情点击链接&#xff1a;Python高光谱遥感数据处理与高光谱遥感机器学习方法教程 第一&#xff1a;高光谱基础 一&#xff1a;高光谱遥感基本 01)高光谱遥感 02)光的波长 03)光谱分辨率 04)高光谱遥感的历史和发展 二&#xff1a;高光谱传感器与数据获取 01)高光谱遥感…

FPGA_学习_17_IP核_ROM(无延迟-立即输出)

由于项目中关于厂商提供的温度-偏压曲线数据已经被同事放在ROM表了&#xff0c;我这边可用直接调用。 今天在仿真的时候&#xff0c;发现他的ROM表用的IP核是及时输出的&#xff0c;就是你地址给进去&#xff0c;对应地址的ROM数据就立马输出&#xff0c;没有延迟。 我打开他的…

pdf怎么合并在一起?这几个合并方法了解一下

pdf怎么合并在一起&#xff1f;在日常工作、学习和生活中&#xff0c;我们常常会遇到需要将多个PDF文件合并成一个文件的情况。比如&#xff0c;在学术论文写作中&#xff0c;我们可能需要将多篇论文合并成一个文件进行打印和提交。在工作中&#xff0c;我们可能需要将多个报告…

c语言——分别计算字符串中英文、空格、数字和其它符号的个数

//分别计算字符串中英文、空格、数字和其它符号的个数 #include<stdio.h> int main() {char c;int letters0,spaces0,digits0,others0;printf("输入字符&#xff1a;\n");while((cgetchar())!\n){if((c>a&&c<z)||(c>A&&c<Z))lette…

专业课只考2门,计算机学硕最低分290的江苏院校

南京工业大学 考研难度&#xff08;☆&#xff09; 内容&#xff1a;23考情概况&#xff08;拟录取和复试分析&#xff09;、专业目录、23复试详情、各专业考情分析。 正文1332字&#xff0c;预计阅读&#xff1a;3分钟。 2023考情概况 南京工业大学计算机相关各专业复试和…

docker学习

配置数据卷容器 1、创建启动c3数据卷容器&#xff0c;使用-v参数&#xff0c;设置数据卷 docker run -it --namec3 -v /volume centos:7 /bin/bash 2、创建启动c1 c2容器&#xff0c;使用--volumes-from 参数设置数据卷 docker run -it --namec1 --volumes-from c3 centos:7 /…

git 回滚相关问题

原本用as自带的git执行回滚任务&#xff0c; 但是提交之后发现并没有成功&#xff0c; 后面通过命令行的方式重新回滚并且提交上去&#xff0c;就可以了 说明as的git还是有点小瑕疵&#xff0c;还是命令行最稳妥 相关博文&#xff1a; git代码回滚操作_imkaifan的博客-CSDN博…