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


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

⚠️注意 ~

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

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

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

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
|
2月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
410 2
|
8月前
|
XML 前端开发 Java
SpringBoot实现文件上传下载功能
本文介绍了如何使用SpringBoot实现文件上传与下载功能,涵盖配置和代码实现。包括Maven依赖配置(如`spring-boot-starter-web`和`spring-boot-starter-thymeleaf`)、前端HTML页面设计、WebConfig路径映射配置、YAML文件路径设置,以及核心的文件上传(通过`MultipartFile`处理)和下载(利用`ResponseEntity`返回文件流)功能的Java代码实现。文章由Colorful_WP撰写,内容详实,适合开发者学习参考。
772 0
|
5月前
|
缓存 前端开发 Java
SpringBoot 实现动态菜单功能完整指南
本文介绍了一个动态菜单系统的实现方案,涵盖数据库设计、SpringBoot后端实现、Vue前端展示及权限控制等内容,适用于中后台系统的权限管理。
479 1
|
7月前
|
监控 容灾 算法
阿里云 SLS 多云日志接入最佳实践:链路、成本与高可用性优化
本文探讨了如何高效、经济且可靠地将海外应用与基础设施日志统一采集至阿里云日志服务(SLS),解决全球化业务扩展中的关键挑战。重点介绍了高性能日志采集Agent(iLogtail/LoongCollector)在海外场景的应用,推荐使用LoongCollector以获得更优的稳定性和网络容错能力。同时分析了多种网络接入方案,包括公网直连、全球加速优化、阿里云内网及专线/CEN/VPN接入等,并提供了成本优化策略和多目标发送配置指导,帮助企业构建稳定、低成本、高可用的全球日志系统。
823 54
|
7月前
|
安全 Java API
Spring Boot 功能模块全解析:构建现代Java应用的技术图谱
Spring Boot不是一个单一的工具,而是一个由众多功能模块组成的生态系统。这些模块可以根据应用需求灵活组合,构建从简单的REST API到复杂的微服务系统,再到现代的AI驱动应用。
|
6月前
|
监控 安全 Java
Java 开发中基于 Spring Boot 3.2 框架集成 MQTT 5.0 协议实现消息推送与订阅功能的技术方案解析
本文介绍基于Spring Boot 3.2集成MQTT 5.0的消息推送与订阅技术方案,涵盖核心技术栈选型(Spring Boot、Eclipse Paho、HiveMQ)、项目搭建与配置、消息发布与订阅服务实现,以及在智能家居控制系统中的应用实例。同时,详细探讨了安全增强(TLS/SSL)、性能优化(异步处理与背压控制)、测试监控及生产环境部署方案,为构建高可用、高性能的消息通信系统提供全面指导。附资源下载链接:[https://pan.quark.cn/s/14fcf913bae6](https://pan.quark.cn/s/14fcf913bae6)。
1074 0
|
8月前
|
SQL 前端开发 Java
深入理解 Spring Boot 项目中的分页与排序功能
本文深入讲解了在Spring Boot项目中实现分页与排序功能的完整流程。通过实际案例,从Service层接口设计到Mapper层SQL动态生成,再到Controller层参数传递及前端页面交互,逐一剖析每个环节的核心逻辑与实现细节。重点包括分页计算、排序参数校验、动态SQL处理以及前后端联动,确保数据展示高效且安全。适合希望掌握分页排序实现原理的开发者参考学习。
530 4
|
8月前
|
存储 Java 定位技术
SpringBoot整合高德地图完成天气预报功能
本文介绍了如何在SpringBoot项目中整合高德地图API实现天气预报功能。从创建SpringBoot项目、配置依赖和申请高德地图API开始,详细讲解了实体类设计、服务层实现(调用高德地图API获取实时与预报天气数据)、控制器层接口开发以及定时任务的设置。通过示例代码,展示了如何获取并处理天气数据,最终提供实时天气与未来几天天气预报的接口。文章还提供了测试方法及运行步骤,帮助开发者快速上手并扩展功能。