大家好,我是程序员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,结构如下图:

自定义日志注解

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

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)); }}

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

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

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

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

  1. 子类实现父类接口时注解为啥报错_Java中的注解使用:全面性的总结一下

    前话: 今天,我们又来聊一下注解的使用,做一下详细的解析,也介绍了自定义注解,请耐心往下看哟! 注解的介绍: 在2005年,sun公司推出了jdk1.5,同时推出的注解功能吸引了很多人的目光,使用注解 ...

  2. slf4j注解log报错_这个注解一次搞定限流与熔断降级:@SentinelResource

    在之前的<使用Sentinel实现接口限流>一文中,我们仅依靠引入Spring Cloud Alibaba对Sentinel的整合封装spring-cloud-starter-alibab ...

  3. 【实践】万字干货:如何优雅地记录操作日志?(附代码)

    猜你喜欢 1.如何搭建一套个性化推荐系统? 2.从零开始搭建创业公司后台技术栈 3.某视频APP推荐详解(万字长文) 4.微博推荐算法实践与机器学习平台演进 5.腾讯PCG推荐系统应用实践 6.强化学 ...

  4. 美团的系统是如何记录操作日志?

    来源:美团技术团队 操作日志几乎存在于每个系统中,而这些系统都有记录操作日志的一套 API.操作日志和系统日志不一样,操作日志必须要做到简单易懂.所以如何让操作日志不跟业务逻辑耦合,如何让操作日志的内 ...

  5. 记录操作日志(JAVA版某大厂基础实践)

    1. 操作日志的使用场景 2. 实现方式 2.1 使用 Canal 监听数据库记录操作日志 2.2 通过日志文件的方式记录 2.3 通过 LogUtil 的方式记录日志 2.4 方法注解实现操作日志 ...

  6. 注解报错_Java中的注解使用:全面性的总结一下

    前话: 今天,我们又来聊一下注解的使用,做一下详细的解析,也介绍了自定义注解,请耐心往下看哟! 注解的介绍: 在2005年,sun公司推出了jdk1.5,同时推出的注解功能吸引了很多人的目光,使用注解 ...

  7. Spring AOP 自定义注解记录操作日志

    1.自定义注释 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface ...

  8. 安装MHA中清理Relay log报错

    安装MHA中清理Relay log报错 [root@MHA3 ~]#  /usr/bin/purge_relay_logs --user=root --password=123456 -disable ...

  9. 解决非controller使用@Autowired注解注入报错为java.lang.NullPointerException问题

    解决非controller使用@Autowired注解注入报错为java.lang.NullPointerException问题 参考文章: (1)解决非controller使用@Autowired注 ...

最新文章

  1. VC++中Depends工具的使用和DLL函数的动态调用方式示例
  2. 从微信服务器获取用户信息,微信小程序Ⅴ [获取登陆用户信息,重点openID(详解)]...
  3. 2.数据湖DeltaLake之DDL操作
  4. esp32 coredump分析
  5. NameNode所需配置,NameNode内存配置计算,NameNode与block关系
  6. ICPC 2015 北京 Today Is a Rainy Day
  7. 推荐系统的冷启动与效果评估
  8. 从零开始做小程序(四)—— 自定义顶部导航栏
  9. 【数据结构】单链表的实现
  10. 家用带宽二级路由openwrt设置ipv6
  11. 编译出现错误,想知道为什么错误
  12. 红米无线连接服务器,电脑无线连接红米手机远程管理启动技巧
  13. Python爬虫突然提取不出信息了,返回的是空列表的解决办法
  14. [QTV] 实例演示 — 基于FPGA的AWS F1实例
  15. Docker 介绍、安装、基础搭建 --01
  16. 避坑指南:Zotero的文件管理与同步zotfile、webdav
  17. 震惊!点几下鼠标就能看到这个网站是不是用凡科搭建的?!
  18. quartz学习笔记7:trading
  19. 国内已经没有什么安全论坛值得留念了
  20. 计算机网络中的CATV,有线电视网络(catv)中的多媒体通信_视频通信

热门文章

  1. 分布式系统开发注意点_分布式系统开发注意事项
  2. javap的用途不断发展:您的Java类文件中隐藏了什么?
  3. java jax-rs_在Java EE 6中将Bean验证与JAX-RS集成
  4. Neo4j:找到两个纬度/经度之间的中间点
  5. Java EE应用程序的单片到微服务重构
  6. Java Bootstrap:Dropwizard与Spring Boot
  7. 如何使用VisualVM监视服务器上的多个JVM
  8. 使用Spring Webservices构建SOAP Webservices代理模块
  9. 臭名昭著的Java错误和陷阱
  10. 带有自定义注释的Java注释教程