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、优化小程…

处理Java异常的10种最佳实践

在本文中&#xff0c;我们将看到处理Java异常的最佳实践。 用Java处理异常不是一件容易的事&#xff0c;因为新手很难理解&#xff0c;甚至专家级开发人员也可能浪费时间讨论应该抛出或处理哪些Java异常。 因此&#xff0c;最大的开发公司对如何使用它们有一套规则。 如果您是…

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) { …

PHP怎样表示几时几分,PHP将时间戳转换为刚刚、N分钟前、今天几点几分、昨天几点几分......

自定义函数&#xff1a;<?php date_default_timezone_set(PRC); // 设置时区&#xff0c;如果已经设置可以删除function timeFormat( $timestamp ) {$curTime time();$space $curTime - $timestamp;if($space < 60) { // 一分钟以内$string "刚刚";return …

古巴:为生产做准备

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

php重载,PHP 重载

PHP 重载一个类中的方法与另一个方法同名&#xff0c;但是参数不同&#xff0c;这种方法称之为重载方法。很遗憾因为 PHP 是弱类型的语言&#xff0c; 所以在方法的参数中本身就可以接收不同类型的数据&#xff0c;又因为 PHP 的方法可以接收不定个数的参数&#xff0c;所以在 …

平板安装python_在CentOS上安装Python3的三种方法

Centos7默认自带了Python2.7版本,但是因为项目需要使用Python3.x你可以按照此文的三个方法进行安装.注&#xff1a;本文示例安装版本为Python3.5&#xff0c;一、Python源代码编译安装安装必要工具 yum-utils &#xff0c;它的功能是管理repository及扩展包的工具 (主要是针对r…

hibernate脏数据_Hibernate脏检查的剖析

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

python查询sql_Python处理SQL语句(提供SQL查询平台使用)

在搞公司的SQL查询(MySQL)平台时&#xff0c;需要对用户查询SQL进行条数限制&#xff0c;默认是在配置文件中配置一个“limit 1000”这样的参数。最自然想到的就是对用户通过web传入的SQL做处理&#xff0c;默认加上limit参数。这样一来就有这么几个问题需要处理&#xff1a;1…

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

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

AWS Elasticsearch后模式

因此&#xff0c;碰巧我们在SaaS版本的LogSentinel上遇到了生产问题–我们的Elasticsearch停止了对新数据编制索引。 由于Elasticsearch只是辅助存储&#xff0c;因此没有数据丢失&#xff0c;但这给我们的客户带来了一些问题&#xff08;他们无法在其仪表板上看到实时数据&…

python设置word背景色_Python数据可视化:WordCloud入门

WordCloud是一种很好的展现数据的方式&#xff0c;网上也有不少小工具和在线网页。但是有些不支持中文&#xff0c;有些安装复杂&#xff0c;所以决定用Python实现。主要参考官网&#xff0c;通过官网的例子&#xff0c;讲一下WordCloud的制作。主要流程获取内容的路径如果是一…

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删除数组空元素的方法…