SpringBoot和@Aspect实现自建Log日志功能

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: SpringBoot和@Aspect实现自建Log日志功能

主页:写程序的小王叔叔的博客欢迎来访👀

支持:点赞收藏关注


1、技术

JDK1.8+

SpringBoot2.0+   、@Aspect注解

MySql5.6+

2、代码干货

Log实体对象类.java

package*****.***.***.modules.sys.log.entity;
importjava.io.Serializable;
importjava.util.Date;
importjavax.persistence.Column;
importjavax.persistence.Entity;
importjavax.persistence.Id;
importjavax.persistence.Table;
importorg.springframework.stereotype.Component;
importio.swagger.annotations.ApiModelProperty;
@Entity@Table(name="sys_log")
@Component@org.hibernate.annotations.Table(comment="系统日志信息", appliesTo="sys_log")
publicclassSysLogimplementsSerializable{
privatestaticfinallongserialVersionUID=42L;
@Id@ApiModelProperty("主键")
@Column(name="id",nullable=false,columnDefinition="bigint(64)  comment '主键'")
privateLongid;// 主键Id@ApiModelProperty("日志编号")
@Column(name="log_id",columnDefinition="varchar(255)  comment '日志编号'" )
privateStringlogId;//日志编号@ApiModelProperty("请求链接")
@Column(name="url",columnDefinition="text  comment '请求链接'" )
privateStringurl;//请求链接@ApiModelProperty("请求方法")
@Column(name="method",columnDefinition="text  comment '请求方法'" )
privateStringmethod;//请求方法@ApiModelProperty("请求类名")
@Column(name="class_name",columnDefinition="text  comment '请求类名'" )
privateStringclassName;//请求方法@ApiModelProperty("请求方法名")
@Column(name="method_name",columnDefinition="text  comment '请求方法名'" )
privateStringmethodName;//请求方法@ApiModelProperty("请求参数")
@Column(name="params",columnDefinition="text  comment '请求参数'" )
privateStringparams;//请求参数@ApiModelProperty("日志类型:(1:系统日志2:业务日志)")
@Column(name="lot_type",columnDefinition="varchar(255)  comment '日志类型:(1:系统日志2:业务日志)'" )
privateStringlogType;//请求方法@ApiModelProperty("请求方式:(GET/POST)")
@Column(name="type",columnDefinition="varchar(255)  comment '请求方式(GET/POST)'" )
privateStringtype;//请求方法@ApiModelProperty("请求IP")
@Column(name="IP",columnDefinition="text  comment '请求IP'" )
privateStringip;//请求方法@ApiModelProperty("操作的数据库表")
@Column(name="log_table",columnDefinition="varchar(255)  comment '操作的数据库表'" )
privateStringtable;//操作的数据库表@ApiModelProperty("请求异常")
@Column(name="log_error",columnDefinition="text  comment '请求异常'" )
privateStringlogError;//请求异常@ApiModelProperty("运行时长")
@Column(name="time",columnDefinition="varchar(255) comment '运行时长'" )
privatelongtime;//@ApiModelProperty("备注")
@Column(name="log_comment",columnDefinition="text  comment '备注'" )
privateStringlogComment;//备注@ApiModelProperty("创建人")
@Column(name="create_by" )
privateStringcreateBy;//创建人@ApiModelProperty("创建时间")
@Column(name="create_time"  )
privateDatecreateTime;//创建时间//setter()/getter();}

3、基本的CRUD

package****.****.****.modules.sys.log.controller;
importjava.util.List;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.web.bind.annotation.CrossOrigin;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.ResponseBody;
importorg.springframework.web.bind.annotation.RestController;
import*****.modules.sys.log.entity.SysLog;
import*******.modules.sys.log.service.SysLogService;
importio.swagger.annotations.ApiOperation;
@CrossOrigin//跨域@RestController@RequestMapping("/SysLog")
publicclassSysLogController{
@AutowiredpublicSysLogServicesysLogService;
//  //添加AOP注解日志管理//  @SysLogAspectValue(//      describtion = "获取所有日志列表信息",//      logType = "1",//      type="POST",//      url="/SysLog/SelectAllSysLog",//      table="sys_log",//      params = "SysLog",//      method = "POST"//  )@ResponseBody@ApiOperation(value="获取所有日志列表信息", notes="/SysLog/SelectAllSysLog")
@GetMapping(value="/SelectAllSysLog")
publicList<SysLog>SelectAllSysLog(){
returnsysLogService.SelectAllSysLogList(page).getContent();
  }
}
package*******.*****.******modules.sys.log.service;
importorg.springframework.data.domain.Page;
import***.***.****t.modules.sys.log.entity.SysLog;
/**** 系统日志接口* @ClassName: SysLogService* @Description: TODO(描述)* @author author* @date 2019-12-03 10:55:22*/publicinterfaceSysLogService {
/**** 日志保存* @Title: save* @Description: TODO(描述)* @param sysLog* @author author* @date 2019-12-10 09:56:28*/voidsave(SysLogsysLog);
}
package***.****.****.modules.sys.log.service.impl;
importjava.util.ArrayList;
importjava.util.List;
importjavax.persistence.criteria.CriteriaBuilder;
importjavax.persistence.criteria.CriteriaQuery;
importjavax.persistence.criteria.Predicate;
importjavax.persistence.criteria.Root;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.data.domain.Page;
importorg.springframework.data.domain.PageRequest;
importorg.springframework.data.domain.Pageable;
importorg.springframework.data.domain.Sort;
importorg.springframework.data.jpa.domain.Specification;
importorg.springframework.stereotype.Service;
import***.***.***.***.****.modules.sys.log.entity.SysLog;
import***.*.*.*.*.*.*.*.modules.sys.log.repository.SysLogRepository;
import*.*.*.*.*.*.*.*.*.*.modules.sys.log.service.SysLogService;
/*** 系统日志实现类* @ClassName: SysLogServiceImpl* @Description: TODO(描述)* @author author* @date 2019-12-03 10:55:17*/@Service("SysLogService")
publicclassSysLogServiceImplimplementsSysLogService{
@AutowiredpublicSysLogRepositorysysLogRepository;
@OverridepublicPage<SysLog>SelectAllSysLogList(intpage) {
Sortsort=newSort(Sort.Direction.DESC, "createTime");//创建时间正序排列Pageablepageable=PageRequest.of(page, this.size, sort);
Page<SysLog>sysLog=sysLogRepository.findAll (newSpecification<SysLog>() {
@OverridepublicPredicatetoPredicate(Root<SysLog>root,
CriteriaQuery<?>query, CriteriaBuildercriteriaBuilder) {
List<Predicate>list=newArrayList<Predicate>();
//拼接 where条件-----------------//---------------------------Predicate[] p=newPredicate[list.size()];
returncriteriaBuilder.and(list.toArray(p));
      }
    }, pageable);
returnsysLog;
  }
@Overridepublicvoidsave(SysLogsysLog) {
sysLogRepository.save(sysLog);
  }
}
package*.*.*.*.*.*.*.modules.sys.log.repository;
importorg.springframework.data.jpa.domain.Specification;
importorg.springframework.data.jpa.repository.JpaRepository;
import*.*.*.*.*.*.*.*.modules.sys.log.entity.SysLog;
/*** 系统日志管理类* @ClassName: SysLogRepository* @Description: TODO(描述)* @author author* @date 2019-12-03 10:55:09*/publicinterfaceSysLogRepositoryextendsJpaRepository<SysLog, Long> {
}

已上就是基本的业务功能中的CRUD的功能,下面就是重点的log的AOP切面功能,,,

4、AOP切面功能动态获取log信息

1)、在每个需要用到的方法头上增加注释,附加案例【四中第一个截图】

package*.*.*.*.*.*.*.*.modules.sys.log.controller;
importjava.lang.annotation.Documented;
importjava.lang.annotation.ElementType;
importjava.lang.annotation.Retention;
importjava.lang.annotation.RetentionPolicy;
importjava.lang.annotation.Target;
/**** 系统日志管理表* @ClassName: SysLogController* @Description: TODO(描述)* @author author* @date 2019-12-03 10:54:52*/@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented//注释文档public@interfaceSysLogAspectValue {
Stringdescribtion() default"";//日志描述StringlogType() default"1";//日志种类-1:系统日志2:业务日志Stringtype()  default"GET";//请求方式:(GET/POST)Stringurl()  default"";//请求链接Stringtable()  default"";//操作的数据库表Stringparams()  default"";//请求参数Stringmethod()  default"";//请求方法}

制作切面内容

package*.*.*.*.*.*.*.modules.sys.log.controller;
importjava.lang.reflect.Method;
importjava.util.ArrayList;
importjava.util.Date;
importjava.util.List;
importjavax.servlet.http.HttpServletRequest;
importorg.aspectj.lang.JoinPoint;
importorg.aspectj.lang.ProceedingJoinPoint;
importorg.aspectj.lang.annotation.AfterThrowing;
importorg.aspectj.lang.annotation.Around;
importorg.aspectj.lang.annotation.Aspect;
importorg.aspectj.lang.annotation.Pointcut;
importorg.aspectj.lang.reflect.MethodSignature;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Component;
importorg.springframework.web.context.request.RequestContextHolder;
importorg.springframework.web.context.request.ServletRequestAttributes;
importcom.google.gson.Gson;
import*.*.*.*.*.*.common.utils.IdGenerate;
import*.*.*.*.*.*.modules.sys.log.entity.SysLog;
import*.*.*.*.*.*.modules.sys.log.service.SysLogService;
/****  系统日志切面* @ClassName: SysLogAspect* @Description: TODO(描述)* @author author* @date 2019-12-04 10:34:41*/@Aspect// 使用@Aspect注解声明一个切面@ComponentpublicclassSystemLogAspect{
privatefinalStringPOINT_CUT="@annotation(*.*.*.*.*.modules.sys.log.entity)";
privatestaticfinalorg.slf4j.Loggerlog=org.slf4j.LoggerFactory.getLogger(SystemLogAspect.class);
@AutowiredpublicSysLogServicesysLogService;
/*** 这里我们使用注解的形式* 当然,我们也可以通过切点表达式直接指定需要拦截的package,需要拦截的class 以及 method* 切点表达式:   execution(...)*/@Pointcut(POINT_CUT)
publicvoidPointCut() {}
/*** 环绕通知 @Around  , 当然也可以使用 @Before (前置通知)  @After (后置通知)* @param point* @return* @throws Throwable*///@Around(POINT_CUT)@Around("@annotation(SysLogAspectValue)")
publicObjectaround(ProceedingJoinPointpoint) throwsThrowable {
longbeginTime=System.currentTimeMillis();
Objectresult=point.proceed();
try {
//正常保存日志saveLog(point, System.currentTimeMillis() -beginTime);
        } catch (Exceptione) {
//异常保存日志//afterReturningMethod(point, e);        }
returnresult;
    }
/**** 捕获异常* * @Title: afterReturningMethod* @Description: TODO(描述)* @param joinPoint* @param e* @author author* @throws Throwable * @date 2019-12-10 01:40:37*/@AfterThrowing(throwing="exception",value="@annotation(SysLogAspectValue)",argNames="exception")
publicvoidafterReturningMethod(JoinPointjoinPoint, Exceptione) throwsThrowable{
if(e!=null){
SysLogsysLog=newSysLog();
longbeginTime=System.currentTimeMillis();
longtime=System.currentTimeMillis() -beginTime;
MethodSignaturesignature= (MethodSignature) joinPoint.getSignature();
Methodmethod=signature.getMethod();
// 接收到请求,记录请求内容ServletRequestAttributesattributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequestrequest=attributes.getRequest();
sysLog.setId(IdGenerate.longUUIDId());//主键sysLog.setLogId(sysLog.getId().toString());//日志编号sysLog.setTime(time);//时长sysLog.setIp(request.getRemoteAddr());//请求的IPsysLog.setCreateBy(sysLog.getIp());//请求人sysLog.setCreateTime( newDate() );//创建时间SysLogAspectValuesysLogAspectValue=method.getAnnotation(SysLogAspectValue.class);
if(sysLogAspectValue!=null){
//注解上的描述sysLog.setLogComment(sysLogAspectValue.describtion());//备注sysLog.setLogType(sysLogAspectValue.logType());//日志类型sysLog.setType(sysLogAspectValue.type());//请求类型sysLog.setUrl(sysLogAspectValue.url());//请求链接sysLog.setTable(sysLogAspectValue.table());//操作的数据表sysLog.setMethod(sysLogAspectValue.method());//操作请求方法            }
//请求的 类名、方法名sysLog.setClassName(joinPoint.getTarget().getClass().getName());//类名sysLog.setMethodName(signature.getName());//方法名//请求的参数Object[] args=joinPoint.getArgs();
List<String>list=newArrayList<String>();
for (Objecto : args) {
list.add(newGson().toJson(o));
            }
sysLog.setParams("Params:[ "+list.toString()+" ]:Aspectj @AfterThrowing");
sysLog.setLogError(joinPoint.getSignature().getName()+"[ message:"+e.getMessage() +"]:Aspectj @AfterThrowing");
System.out.println("=====异常保存日志成功==============================");
sysLogService.save(sysLog);
log.trace(POINT_CUT, sysLog);
System.out.println("=====异常保存日志  结束=========================");
        }
    }
/*** 正常保存日志* @param joinPoint* @param time* @throws Throwable */publicvoidsaveLog(ProceedingJoinPointjoinPoint, longtime) {
SysLogsysLog=newSysLog();
sysLog=this.addSysLog(joinPoint,sysLog , time );
//请求的参数Object[] args=joinPoint.getArgs();
List<String>list=newArrayList<String>();
for (Objecto : args) {
list.add(newGson().toJson(o));
        }
sysLog.setParams("Params:[ "+list.toString()+" ]:Aspectj @Around");
sysLog.setLogError( "[ message: 无 ]:Aspectj @Around");
System.out.println("=====正常保存日志成功==============================");
sysLogService.save(sysLog);
log.trace(POINT_CUT, sysLog);
System.out.println("=====正常保存日志  结束=========================");
    }
/*** 组装日志model* @Title: addSysLog* @Description: TODO(描述)* @param sysLog* @return* @author author* @date 2019-12-10 02:09:04*/publicSysLogaddSysLog(ProceedingJoinPointjoinPoint, SysLogsysLog , longtime) {
MethodSignaturesignature= (MethodSignature) joinPoint.getSignature();
Methodmethod=signature.getMethod();
// 接收到请求,记录请求内容ServletRequestAttributesattributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequestrequest=attributes.getRequest();
sysLog.setId(IdGenerate.longUUIDId());//主键sysLog.setLogId(sysLog.getId().toString());//日志编号sysLog.setTime(time);//时长sysLog.setIp(request.getRemoteAddr());//请求的IPsysLog.setCreateBy(sysLog.getIp());//请求人sysLog.setCreateTime( newDate() );//创建时间SysLogAspectValuesysLogAspectValue=method.getAnnotation(SysLogAspectValue.class);
if(sysLogAspectValue!=null){
//注解上的描述sysLog.setLogComment(sysLogAspectValue.describtion());//备注sysLog.setLogType(sysLogAspectValue.logType());//日志类型sysLog.setType(sysLogAspectValue.type());//请求类型sysLog.setUrl(sysLogAspectValue.url());//请求链接sysLog.setTable(sysLogAspectValue.table());//操作的数据表sysLog.setMethod(sysLogAspectValue.method());//操作请求方法        }
//请求的 类名、方法名sysLog.setClassName(joinPoint.getTarget().getClass().getName());//类名sysLog.setMethodName(signature.getName());//方法名returnsysLog;
    }
}

生成这个Log切面日志的用法:

image.png


转载声明:本文为博主原创文章,未经博主允许不得转载

⚠️注意 ~

💯本期内容就结束了,如果内容有误,麻烦大家评论区指出!

如有疑问❓可以在评论区💬或私信💬,尽我最大能力🏃‍♀️帮大家解决👨‍🏫!

如果我的文章有帮助到您,欢迎点赞+关注✔️鼓励博主🏃,您的鼓励是我分享的动力🏃🏃🏃~

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
2天前
|
消息中间件 缓存 Java
手写模拟Spring Boot启动过程功能
【11月更文挑战第19天】Spring Boot自推出以来,因其简化了Spring应用的初始搭建和开发过程,迅速成为Java企业级应用开发的首选框架之一。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,帮助读者深入理解其工作机制。
17 3
|
10天前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
110 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
2天前
|
Java 开发者 微服务
手写模拟Spring Boot自动配置功能
【11月更文挑战第19天】随着微服务架构的兴起,Spring Boot作为一种快速开发框架,因其简化了Spring应用的初始搭建和开发过程,受到了广大开发者的青睐。自动配置作为Spring Boot的核心特性之一,大大减少了手动配置的工作量,提高了开发效率。
13 0
|
30天前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
40 4
|
27天前
|
Java API 数据库
Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐
本文通过在线图书管理系统案例,详细介绍如何使用Spring Boot构建RESTful API。从项目基础环境搭建、实体类与数据访问层定义,到业务逻辑实现和控制器编写,逐步展示了Spring Boot的简洁配置和强大功能。最后,通过Postman测试API,并介绍了如何添加安全性和异常处理,确保API的稳定性和安全性。
34 0
|
16天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
94 62
|
12天前
|
前端开发 Java easyexcel
SpringBoot操作Excel实现单文件上传、多文件上传、下载、读取内容等功能
SpringBoot操作Excel实现单文件上传、多文件上传、下载、读取内容等功能
50 8
|
14天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
32 2
|
17天前
|
JSON Java API
springboot集成ElasticSearch使用completion实现补全功能
springboot集成ElasticSearch使用completion实现补全功能
22 1
|
21天前
|
存储 Java 数据管理
强大!用 @Audited 注解增强 Spring Boot 应用,打造健壮的数据审计功能
本文深入介绍了如何在Spring Boot应用中使用`@Audited`注解和`spring-data-envers`实现数据审计功能,涵盖从添加依赖、配置实体类到查询审计数据的具体步骤,助力开发人员构建更加透明、合规的应用系统。