slf4j注解log报错_SpringBoot自定义日志注解,用于数据库记录操作日志,你用过吗?...

大家好,我是程序员7歌!

今天我将为大家讲解如何通过自定义注解记录接口访问日志。一般的开发中,有两种方式可以记录日志信息,第一种:把接口日志信息保存到日志文件中,第二种:把接口操作日志保存到数据库中,这里我将为大家讲解第二种方式。

创建日志表

在数据库新增日志记录表,字段我们可以自定义,其中有几个必要字段,如下:

  • type:请求类型
  • title:操作记录(日志标题)
  • remote_addr:操作IP地址
  • username:操作人
  • request_uri:接口地址
  • http_method:接口类型
  • class_method:请求的接口方法
  • params:请求参数数据
  • session_id:用户session

以下就是数据库表结构:

DROP TABLE IF EXISTS `sys_log`;CREATE TABLE `sys_log` ( `id` bigint(50) NOT NULL AUTO_INCREMENT COMMENT '编号', `type` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT '请求类型', `title` varchar(255) COLLATE utf8_bin DEFAULT '' COMMENT '日志标题', `remote_addr` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '操作IP地址', `username` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '操作用户昵称', `request_uri` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '请求URI', `http_method` varchar(10) COLLATE utf8_bin DEFAULT NULL COMMENT '操作方式', `class_method` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '请求类型.方法', `params` text COLLATE utf8_bin COMMENT '操作提交的数据', `session_id` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT 'sessionId', `response` longtext COLLATE utf8_bin COMMENT '返回内容', `use_time` bigint(11) DEFAULT NULL COMMENT '方法执行时间', `browser` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '浏览器信息', `area` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '地区', `province` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '省', `city` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '市', `isp` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '网络服务提供商', `exception` text COLLATE utf8_bin COMMENT '异常信息', `create_by` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '创建者', `create_date` datetime DEFAULT NULL COMMENT '创建时间', `update_by` bigint(64) DEFAULT NULL, `update_date` datetime DEFAULT NULL, `remarks` varchar(255) COLLATE utf8_bin DEFAULT NULL, `del_flag` bit(1) DEFAULT NULL, PRIMARY KEY (`id`), KEY `sys_log_create_by` (`create_by`) USING BTREE, KEY `sys_log_request_uri` (`request_uri`) USING BTREE, KEY `sys_log_type` (`type`) USING BTREE, KEY `sys_log_create_date` (`create_date`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=150 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='系统日志';

使用自动生成代码工具生成SysLog类的信息:SysLog/SysLogController/SysLogService/SysLogServiceImpl/SysLogMapper/SysLogMapper.xml,结构如下图:

63aa318f3fe2b08c8404580d7bb4fa4f.png

自定义日志注解

在项目中新增自定义注解,用于注解哪些接口需要记录操作日志,代码如下:

package com.july.annotation;import java.lang.annotation.*;/** * 系统日志注解 * @author zqk * @since 2019/12/5 */@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface SysLog { String value() default "";}

在定义一个Aspect切面类,里面可以定义切入点和通知,核心代码如下:

package com.july.aspect;import com.alibaba.fastjson.JSONObject;import com.july.entity.SysLog;import com.july.service.SysLogService;import com.july.util.ToolUtil;import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;import org.springframework.web.context.request.RequestAttributes;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import org.springframework.web.multipart.MultipartFile;import javax.annotation.Resource;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import java.lang.reflect.Method;import java.util.Map;/** * 解析响应数据 * @author zqk * @since 2019/12/5 */@Aspect@Order(5)@Component@Slf4jpublic class WebLogAspect { @Resource private SysLogService sysLogService; private ThreadLocal startTime = new ThreadLocal<>(); private SysLog sysLog = null; @Pointcut("@annotation(com.july.annotation.SysLog)") public void webLog(){} @Before("webLog()") public void doBefore(JoinPoint joinPoint) { startTime.set(System.currentTimeMillis()); // 接收到请求,记录请求内容 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); HttpSession session = (HttpSession) attributes.resolveReference(RequestAttributes.REFERENCE_SESSION); sysLog = new SysLog(); sysLog.setClassMethod(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); sysLog.setHttpMethod(request.getMethod()); //获取传入目标方法的参数 Object[] args = joinPoint.getArgs(); for (int i = 0; i < args.length; i++) { Object o = args[i]; if(o instanceof ServletRequest || (o instanceof ServletResponse) || o instanceof MultipartFile){ args[i] = o.toString(); } } String str = JSONObject.toJSONString(args); sysLog.setParams(str.length()>5000? JSONObject.toJSONString("请求参数数据过长不与显示"):str); String ip = ToolUtil.getClientIp(request); if("0.0.0.0".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip) || "localhost".equals(ip) || "127.0.0.1".equals(ip)){ ip = "127.0.0.1"; } sysLog.setRemoteAddr(ip); sysLog.setRequestUri(request.getRequestURL().toString()); if(session != null){ sysLog.setSessionId(session.getId()); } MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); com.july.annotation.SysLog mylog = method.getAnnotation(com.july.annotation.SysLog.class); if(mylog != null){ //注解上的描述 log.info("注解信息 ===> " + mylog.value()); sysLog.setTitle(mylog.value()); } Map browserMap = ToolUtil.getOsAndBrowserInfo(request); sysLog.setBrowser(browserMap.get("os")+"-"+browserMap.get("browser")); if(!"127.0.0.1".equals(ip)){ Map map = ToolUtil.getAddressByIP(ToolUtil.getClientIp(request)); sysLog.setArea(map.get("area")); sysLog.setProvince(map.get("province")); sysLog.setCity(map.get("city")); sysLog.setIsp(map.get("isp")); } sysLog.setType(ToolUtil.isAjax(request)?"Ajax请求":"普通请求"); sysLog.setUsername("自定义用户"); } @Around("webLog()") public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { try { Object obj = proceedingJoinPoint.proceed(); return obj; } catch (Exception e) { e.printStackTrace(); sysLog.setException(e.getMessage()); throw e; } } @AfterReturning(returning = "ret", pointcut = "webLog()") public void doAfterReturning(Object ret) { sysLog.setUsername("自定义用户"); String retString = JSONObject.toJSONString(ret); sysLog.setResponse(retString.length()>5000? JSONObject.toJSONString("请求参数数据过长不与显示"):retString); sysLog.setUseTime(System.currentTimeMillis() - startTime.get()); sysLogService.save(sysLog); }}

切面类里面设计到几个工具类:

  1. ToolUtil=>getClientIp(获取客户端ip信息)
  2. ToolUtilgetAddressByIP:解析IP信息(调用第三方接口)

编程接口类

在项目里面新增测试接口类,在需要记录日志的接口上面添加注解@SysLog,如下代码:

package com.july.controller;import com.july.annotation.SysLog;import com.july.dto.UserLoginDto;import com.july.dto.UserRedisDto;import com.july.entity.Userinfo;import com.july.service.UserinfoService;import com.july.util.Result;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;/** * 前端控制器 * @author zqk * @since 2019/12/4 */@RestController@RequestMapping("/userinfo")public class UserinfoController { @Resource private UserinfoService userinfoService; /** * @description 用户登录 * @param userLoginDto * @return * @author zqk * @since 2019/12/4 */ @SysLog("登录") @PostMapping("/login") public Result login(@RequestBody UserLoginDto userLoginDto){ return Result.ok(userinfoService.userInfoLogin(userLoginDto)); }}

接下来我们启动项目,项目启动成功后,访问登录接口,如下图:

274d77a66c5546cd478264ee68b2c84e.png

等接口响应成功后,我们打开数据库去sys_log表里面查看记录信息,记录信息如下:

667b2ec3e46675d11ff17597980a3094.png

从数据库记录我们得知,接口调用的全部信息,这样以来也方便开发人员排查操作记录。对于上面的自定义注解记录操作日志,大家觉得怎么样啊?

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

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

相关文章

java applet audion_java applet audion

①希罗尤尔和他的飞翼敢达也有着不少拥趸&#xff0c;让我们期待这位美少年在《敢达决战》中的表现吧。②颜值时代&#xff0c;浏览器皮肤也不能输360浏览器耳目一新的设计&#xff0c;高清精美的壁纸&#xff0c;让你上网时更添一份好心情。软件使用1、支持游戏小号2、优化小程…

markdown 流程图_Markdown 进阶技能:用代码画流程图(编程零基础也适用)

这篇文章主要介绍流程图基础以写代码的方式画流程图相比于使用画图工具拖拽画图&#xff0c;用代码画图有什么好处&#xff1f;首先&#xff0c;这种方式非常轻便&#xff0c;无需安装复杂的画图应用。Typora 等多种 Markdown 编辑器自带有画图扩展&#xff08;这也是 Markdown…

java jtree_Java JTree

Java JTree1 Java JTree的介绍JTree类用于显示树结构数据或层次结构数据。JTree是一个复杂的组件。它的最顶部有一个“根节点”&#xff0c;它是树中所有节点的父节点。它继承了JComponent类。2 Java JTree的声明我们来看一下javax.swing.JTree类的声明。public class JTree ex…

akka和rabbitmq_Akka Notes –演员记录和测试

akka和rabbitmq在前两部分&#xff08; 一 &#xff0c; 二 &#xff09;中&#xff0c;我们简要讨论了Actor以及消息传递的工作方式。 在这一部分中&#xff0c;让我们看一下如何修复并记录我们的TeacherActor 。 回顾 这就是我们上一部分中的Actor的样子&#xff1a; class…

完数c++语言程序_C语言经典100题(19)

1上期答案揭晓首先给大家看看上一篇文章C语言经典100题(18)中第三部分编程题的答案&#xff1a;#includeint main(){ int s0,a,n,t; printf("请输入 a 和 n&#xff1a;\n"); scanf("%d%d",&a,&n); ta; while(n>0) { …

古巴:为生产做准备

“它可以在我的本地机器上运行&#xff01;” 如今&#xff0c;这听起来像模因&#xff0c;但仍然存在“开发环境与生产环境”的问题。 作为开发人员&#xff0c;您应始终牢记&#xff0c;您的应用程序有一天将在生产环境中开始运行。 在本文中&#xff0c;我们将讨论一些特定于…

hibernate脏数据_Hibernate脏检查的剖析

hibernate脏数据介绍 持久性上下文使实体状态转换入队 &#xff0c;该实体状态转换在刷新后转换为数据库语句。 对于托管实体&#xff0c;Hibernate可以代表我们自动检测传入的更改并安排SQL UPDATE。 这种机制称为自动脏检查 。 默认的脏检查策略 默认情况下&#xff0c;Hibe…

php组成,php接口有几部分组成?

程序接口&#xff0c;由一套陈述、功能、选项、其它表达程序结构的形式、以及程序师使用的程序或者程序语言提供的数据组成PHP接口(interface)的特点1、接口的方法必须是公开的。2、接口的方法默认是抽象的&#xff0c;所以不在方法名前面加abstract。3、接口可以定义常量&…

java 解析日期格式_日期/时间格式/解析,Java 8样式

java 解析日期格式自Java 几乎 开始以来&#xff0c;Java开发人员就通过java.util.Date类&#xff08;自JDK 1.0起&#xff09;和java.util.Calendar类&#xff08;自JDK 1.1起 &#xff09;来处理日期和时间。 在这段时间内&#xff0c;成千上万&#xff08;甚至数百万&#x…

php第三方登录代码,thinkPHP5项目中实现QQ第三方登录功能

本文实例讲述了thinkPHP5项目中实现QQ第三方登录功能。分享给大家供大家参考&#xff0c;具体如下&#xff1a;最近用thinkPHP 5框架做了一个婚纱店的项目&#xff0c;在开发过程中需要用到第三方登录&#xff0c;腾讯官方给的案例是几个文件相互包含实现的&#xff0c;放到tp5…

mac 显示隐藏文件_如何在Mac上显示隐藏文件?苹果mac显示隐藏文件夹方法

与任何操作系统一样&#xff0c;macOS会将重要文件隐藏起来&#xff0c;以防止意外删除它们并因此而损坏系统。但是&#xff0c;在某些情况下&#xff0c;您可能需要在Mac上显示隐藏文件&#xff0c;例如&#xff0c;浏览“ 库”文件夹并清除旧日志&#xff0c;缓存或其他垃圾文…

分布式虚拟跟踪

跟踪提供了对系统的可见性&#xff0c;使开发人员和操作人员可以在运行时观察应用程序。 当系统不断增长并与更多微服务进行交互时&#xff0c;跟踪变得非常有价值。 在这样的环境中&#xff0c;这些痕迹非常棒&#xff0c;可以定位导致性能下降的故障和瓶颈。 在这篇文章中&a…

php 删除数组的空元素,php删除数组空元素的方法_后端开发

php如何实现自动跳转_后端开发php实现自动跳转的方法&#xff1a;1、通过php内置函数“header”&#xff0c;将http响应头中的“Location”设置为要跳转的URL即可&#xff1b;2、可以在javascript代码中将“window.location.href”指向要跳转的URL即可。php删除数组空元素的方法…

map for循环_JavaScript 用 for 循环太 low?你是不是有什么误解

天要吐槽下&#xff0c;我时不时地看到有些文章说“循环语句不好&#xff0c;你应该用 filter&#xff0c;map 和 reduce ”——每次看到有文章鼓吹&#xff0c;所有需要循环的场景一律用这几个函数式方法&#xff0c;我都恨得牙痒痒。没错&#xff0c;这些函数式方法确实有它们…

简单工程验收单表格_中铁超大型工程项目-123个精细化管理手册配套表格附件,超全...

中铁超大型工程项目-123个精细化管理手册配套表格附件&#xff0c;超全&#xff01;什么是项目精细化&#xff1f;答&#xff1a;工程项目精细化管理是一个系统的管理体系&#xff0c;包含一系列管理制度和办法&#xff0c;除了《工程项目精细化管理办法》这个纲领性文件外&…

判断unsigned long long乘法溢出_信息安全课程17:缓冲区溢出2

在之前所讲述的内容中&#xff0c;都是我们在自己的程序中自行修改的&#xff1b;正常情况下&#xff0c;没有程序员会在自己的代码中这样写——那有没有办法攻击别人正常的程序呢&#xff1f;攻击者怎么样能够影响到不是自己的程序的返回地址呢&#xff1f;以及怎么样通过攻击…

java 保垒机telnet,开源堡垒机系统Teleport

一. teleport简介Teleport是一款简单易用的堡垒机系统&#xff0c;具有小巧、易用的特点&#xff0c;支持 RDP/SSH/SFTP/Telnet 协议的远程连接和审计管理。Teleport由两大部分构成&#xff1a;跳板核心服务WEB操作界面官网地址: https://tp4a.com/ 官网文档: https://docs.…

php背景图片随页面大小改变,css背景图根据屏幕大小自动缩放

css背景图根据屏幕大小自动缩放代码&#xff1a;html,body{margin:0px;padding:0px;}#background { position: fixed;top: 0;left: 0;width: 100%;height: 100%;overflow: hidden;background-color: #211f1f; display:none\8;}#background .bg-photo {position: absolute;top: …

forever不重启 node_运维监控Prometheus,部署安全的node_exporter监控主机

简介prometheus监控系统的时候&#xff0c;是使用pull的方式来获取监控数据&#xff0c;需要被监控端监听对应的端口&#xff0c;prometheus从这些端口服务中拉取对应的数据。node_exporter安全性讨论node_exporter是收集操作系统的指标的一个程序。例如CPU&#xff0c;内存&am…

netbeans ide_IDE:5个最喜欢的NetBeans功能

netbeans ide愉快的发展……。 NetBeans具有许多有趣的功能 &#xff0c;这些功能使开发非常容易&#xff0c;只需很少的步骤&#xff0c;并且可以在非常快速地将产品推向市场的过程中创造出非常高效的环境 。 将我的谈话仅限于五个功能非常困难&#xff0c;而此IDE具有大量有…