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,结构如下图:
自定义日志注解
在项目中新增自定义注解,用于注解哪些接口需要记录操作日志,代码如下:
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); }}
切面类里面设计到几个工具类:
- ToolUtil=>getClientIp(获取客户端ip信息)
- 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自定义日志注解,用于数据库记录操作日志,你用过吗?...相关推荐
- 子类实现父类接口时注解为啥报错_Java中的注解使用:全面性的总结一下
前话: 今天,我们又来聊一下注解的使用,做一下详细的解析,也介绍了自定义注解,请耐心往下看哟! 注解的介绍: 在2005年,sun公司推出了jdk1.5,同时推出的注解功能吸引了很多人的目光,使用注解 ...
- slf4j注解log报错_这个注解一次搞定限流与熔断降级:@SentinelResource
在之前的<使用Sentinel实现接口限流>一文中,我们仅依靠引入Spring Cloud Alibaba对Sentinel的整合封装spring-cloud-starter-alibab ...
- 【实践】万字干货:如何优雅地记录操作日志?(附代码)
猜你喜欢 1.如何搭建一套个性化推荐系统? 2.从零开始搭建创业公司后台技术栈 3.某视频APP推荐详解(万字长文) 4.微博推荐算法实践与机器学习平台演进 5.腾讯PCG推荐系统应用实践 6.强化学 ...
- 美团的系统是如何记录操作日志?
来源:美团技术团队 操作日志几乎存在于每个系统中,而这些系统都有记录操作日志的一套 API.操作日志和系统日志不一样,操作日志必须要做到简单易懂.所以如何让操作日志不跟业务逻辑耦合,如何让操作日志的内 ...
- 记录操作日志(JAVA版某大厂基础实践)
1. 操作日志的使用场景 2. 实现方式 2.1 使用 Canal 监听数据库记录操作日志 2.2 通过日志文件的方式记录 2.3 通过 LogUtil 的方式记录日志 2.4 方法注解实现操作日志 ...
- 注解报错_Java中的注解使用:全面性的总结一下
前话: 今天,我们又来聊一下注解的使用,做一下详细的解析,也介绍了自定义注解,请耐心往下看哟! 注解的介绍: 在2005年,sun公司推出了jdk1.5,同时推出的注解功能吸引了很多人的目光,使用注解 ...
- Spring AOP 自定义注解记录操作日志
1.自定义注释 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface ...
- 安装MHA中清理Relay log报错
安装MHA中清理Relay log报错 [root@MHA3 ~]# /usr/bin/purge_relay_logs --user=root --password=123456 -disable ...
- 解决非controller使用@Autowired注解注入报错为java.lang.NullPointerException问题
解决非controller使用@Autowired注解注入报错为java.lang.NullPointerException问题 参考文章: (1)解决非controller使用@Autowired注 ...
最新文章
- VC++中Depends工具的使用和DLL函数的动态调用方式示例
- 从微信服务器获取用户信息,微信小程序Ⅴ [获取登陆用户信息,重点openID(详解)]...
- 2.数据湖DeltaLake之DDL操作
- esp32 coredump分析
- NameNode所需配置,NameNode内存配置计算,NameNode与block关系
- ICPC 2015 北京 Today Is a Rainy Day
- 推荐系统的冷启动与效果评估
- 从零开始做小程序(四)—— 自定义顶部导航栏
- 【数据结构】单链表的实现
- 家用带宽二级路由openwrt设置ipv6
- 编译出现错误,想知道为什么错误
- 红米无线连接服务器,电脑无线连接红米手机远程管理启动技巧
- Python爬虫突然提取不出信息了,返回的是空列表的解决办法
- [QTV] 实例演示 — 基于FPGA的AWS F1实例
- Docker 介绍、安装、基础搭建 --01
- 避坑指南:Zotero的文件管理与同步zotfile、webdav
- 震惊!点几下鼠标就能看到这个网站是不是用凡科搭建的?!
- quartz学习笔记7:trading
- 国内已经没有什么安全论坛值得留念了
- 计算机网络中的CATV,有线电视网络(catv)中的多媒体通信_视频通信