前言

1,在一些特定的场景我们往往需要看一下接口的入参,特别是跨系统的接口调用(下发,推送),这个时候的接口入参就很重要,我们保存入参入库,如果出问题就可以马上定位是上游还是下游的问题(方便扯皮)

2,还有一般需要在系统中看普通日志,还有特殊的异常(报错)日志,一般我们可以通过服务器去查看相应的位置,但是由于服务器是一直运行的,日志是一直在生成的,这个时候就不太方便。

3,保存入参,我们之间本地调试的时候就可以不用造数据,这个也是很方便的,只需改改就好。

这个时候就体现入参请求和相应结果的重要性

Aop基本概念

Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。

Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。

Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。

Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。

Target(目标对象):织入 Advice 的目标对象.。

Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程

自定义注解:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserAccess {
String desc() default "无信息";
}

对自定义注解进行aop切面

一般使用更加详细的日志切面

@Component
@Aspect
public class UserAccessAspect { // 这里就是对上面进行切面
@Pointcut(value = "@annotation(com.xncoding.aop.aspect.UserAccess)")
public void access() { } @Before("access()")
public void deBefore(JoinPoint joinPoint) throws Throwable {
System.out.println("second before");
} @Around("@annotation(userAccess)")
public Object around(ProceedingJoinPoint pjp, UserAccess userAccess) {
//获取注解里的值
System.out.println("second around:" + userAccess.desc());
try {
return pjp.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
return null;
}
}
}

日志切面

如果想保存到数据库或者进行更加详细的日志打印就可以使用下面的日志切面,

这里目前是打印,如果想保存到数据库,可以创建相应的实体,set进去,然后进行insert到数据库,如果使用mybatis-plus是很方便的,先创建表,然后用mybatis-plus 自动生成代码,再用相应的mapper.inster() 保存到数据库。

/**
* 日志切面
*/
@Aspect
@Component
public class LogAspect {
// 这个目前是对从 com.xncoding.aop.controller.* 下的都进行切入,如果想对上面的自定义注解进行切入,只需改成相对应的路径
// 例如:@Pointcut(value = "@annotation(com.xncoding.aop.aspect.UserAccess)")
@Pointcut("execution(public * com.xncoding.aop.controller.*.*(..))")
public void webLog(){} @Before("webLog()")
public void deBefore(JoinPoint joinPoint) throws Throwable {
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 记录下请求内容
System.out.println("URL : " + request.getRequestURL().toString());
System.out.println("HTTP_METHOD : " + request.getMethod());
System.out.println("IP : " + request.getRemoteAddr());
System.out.println("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
System.out.println("ARGS : " + Arrays.toString(joinPoint.getArgs()));
} @AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret) throws Throwable {
// 处理完请求,返回内容
System.out.println("方法的返回值 : " + ret);
} //后置异常通知
@AfterThrowing("webLog()")
public void throwss(JoinPoint jp){
System.out.println("方法异常时执行.....");
} //后置最终通知,final增强,不管是抛出异常或者正常退出都会执行
@After("webLog()")
public void after(JoinPoint jp){
System.out.println("方法最后执行.....");
} //环绕通知,环绕增强,相当于MethodInterceptor
@Around("webLog()")
public Object arround(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("方法环绕start.....");
try {
Object o = pjp.proceed();
System.out.println("方法环绕proceed,结果是 :" + o);
return o;
} catch (Throwable e) {
throw e;
}
}
}

测试controller

@RestController
@RequestMapping("aop")
public class UserController {
@GetMapping("/first")
public Object first() {
return "first controller";
} @GetMapping("/doError")
public Object error() {
return 1 / 0;
} @GetMapping("/second")
@UserAccess(desc = "second")
public Object second() {
return "second controller 666";
} @PostMapping("/user")
public void userPost(@RequestBody UserVo userVo){
System.out.println("我user进来了");
} }

user类

@Data
public class UserVo { @ApiModelProperty("姓名")
private String name; @ApiModelProperty("性别")
private Integer sex;
}

创建表SQL语句

CREATE TABLE `sys_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`log_type` varchar(50) NOT NULL COMMENT '日志类型',
`create_user_code` varchar(64) NOT NULL COMMENT '创建用户编码',
`create_user_name` varchar(100) NOT NULL COMMENT '创建用户名称',
`create_date` datetime NOT NULL COMMENT '创建时间',
`request_uri` varchar(500) DEFAULT NULL COMMENT '请求URI',
`request_method` varchar(10) DEFAULT NULL COMMENT '请求方式',
`request_params` text COMMENT '请求参数',
`response_params` text COMMENT '响应参数',
`request_ip` varchar(20) NOT NULL COMMENT '请求IP',
`server_address` varchar(50) NOT NULL COMMENT '请求服务器地址',
`is_exception` char(1) DEFAULT NULL COMMENT '是否异常',
`exception_info` text COMMENT '异常信息',
`start_time` datetime NOT NULL COMMENT '开始时间',
`end_time` datetime NOT NULL COMMENT '结束时间',
`execute_time` int(11) DEFAULT NULL COMMENT '执行时间',
`user_agent` varchar(500) DEFAULT NULL COMMENT '用户代理',
`device_name` varchar(100) DEFAULT NULL COMMENT '操作系统',
`browser_name` varchar(100) DEFAULT NULL COMMENT '浏览器名称',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_sys_log_lt` (`log_type`) USING BTREE,
KEY `idx_sys_log_cub` (`create_user_code`) USING BTREE,
KEY `idx_sys_log_ie` (`is_exception`) USING BTREE,
KEY `idx_sys_log_cd` (`create_date`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1560559854462500867 DEFAULT CHARSET=utf8 COMMENT='系统日志表';

测试

请求参数:

debug图片

这里只是做打印,也可以在切面里面保存到数据库。

自定义注解,利用AOP实现日志保存(数据库),代码全贴,复制就能用的更多相关文章

  1. SpringBoot自定义注解、AOP打印日志

    前言 在SpringBoot中使用自定义注解.aop切面打印web请求日志.主要是想把controller的每个request请求日志收集起来,调用接口.执行时间.返回值这几个重要的信息存储到数据库里 ...

  2. 如何通过自定义注解实现AOP切点定义

    面向切面编程(Aspect Oriented Programming, AOP)是面向对象编程(Object Oriented Programming,OOP)的强大补充,通过横切面注入的方式引入其他 ...

  3. springboot aop 自定义注解方式实现完善日志记录(完整源码)

    版权声明:本文为博主原创文章,欢迎转载,转载请注明作者.原文超链接 一:功能简介 本文主要记录如何使用aop切面的方式来实现日志记录功能. 主要记录的信息有: 操作人,方法名,参数,运行时间,操作类型 ...

  4. Spring Boot 中使用自定义注解,AOP 切面打印出入参日志及Dubbo链路追踪透传traceId

    一.使用背景 开发排查系统问题用得最多的手段就是查看系统日志,在分布式环境中一般使用 ELK 来统一收集日志,但是在并发大时使用日志定位问题还是比较麻烦,由于大量的其他用户/其他线程的日志也一起输出穿 ...

  5. 如何优雅地在 Spring Boot 中使用自定义注解,AOP 切面统一打印出入参日志 | 修订版

    欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 资深架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...

  6. Spring Boot 自定义注解,AOP 切面统一打印出入参请求日志

    其实,小哈在之前就出过一篇关于如何使用 AOP 切面统一打印请求日志的文章,那为什么还要再出一篇呢?没东西写了? 哈哈,当然不是!原因是当时的实现方案还是存在缺陷的,原因如下: 不够灵活,由于是以所有 ...

  7. 手写SpringBoot自动配置及自定义注解搭配Aop,实现升级版@Value()功能

    背景 项目中为了统一管理项目的配置,比如接口地址,操作类别等信息,需要一个统一的配置管理中心,类似nacos. 我根据项目的需求写了一套分布式配置中心,测试无误后,改为单体应用并耦合到项目中.项目中使 ...

  8. Spring AOP基础概念及自定义注解式AOP初体验

    对AOP的理解开始是抽象的,看到切点的匹配方式其实与正则表达式性质大致一样就基本了解AOP是基本是个什么作用了.只是整个概念更抽象,需要具化理解.下图列表是AOP相关概念解释,可能也比较抽象^_^ 比 ...

  9. Spring 自定义注解,配置简单日志注解

    java在jdk1.5中引入了注解,spring框架也正好把java注解发挥得淋漓尽致. 下面会讲解Spring中自定义注解的简单流程,其中会涉及到spring框架中的AOP(面向切面编程)相关概念. ...

随机推荐

  1. 4. Docker自定义镜像

    下面制作镜像: 此时,验证一下: 以上验证都是成功的,到此就可以把刚才建立并经过刚才运行并验证的镜像包通过各种方式传递给其他人来部署使用了,并且环境肯定是可你统一的.

  2. VMware Workstation 虚拟机详细安装教程

    一.介绍篇 VMware Workstation 16 Pro是VMware(威睿公司)于2021年最新发布的一代虚拟机软件,软件的中文名是"VMware 工作站 16 专业版". ...

  3. Django——表单

    一.前言 看了下教程,以为表单很简单呢,结果搞了一两个钟才弄懂,哈哈哈,所以说不要小瞧每一件事. 先说明下HTTP请求: HTTP协议以"请求-回复"的方式工作.客户发送请求时,可 ...

  4. ABP框架之——数据访问基础架构(下)

    大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的一块垫脚石,我们一起精进. EF Core集成 EF Core是微软的ORM,可以使用它与主流的数据库提供商 ...

  5. 「快速学习系列」我熬夜整理了Vue3.x响应性API

    前言 Vue3.x正式版发布已经快半年了,相信大家也多多少少也用Vue3.x开发过项目.那么,我们今天就整理下Vue3.x中的响应性API.响应性APIreactive 作用: 创建一个响应式数据. ...

  6. Pisa-Proxy 之 SQL 解析实践

    SQL 语句解析是一个重要且复杂的技术,数据库流量相关的 SQL 审计.读写分离.分片等功能都依赖于 SQL 解析,而 Pisa-Proxy 作为 Database Mesh 理念的一个实践,对数据库 ...

  7. 手写一个虚拟DOM库,彻底让你理解diff算法

    所谓虚拟DOM就是用js对象来描述真实DOM,它相对于原生DOM更加轻量,因为真正的DOM对象附带有非常多的属性,另外配合虚拟DOM的diff算法,能以最少的操作来更新DOM,除此之外,也能让Vue和 ...

  8. Day04 HTML标记

    路径 ./ 同级目录 ./ 进入该目录名下 ../ 上一级目录 HTML标记 图片 <!-- 图片标记 src 图片的路径 width 设置图片宽度 height 设置图片高度 title 鼠标 ...

  9. C语言-数据结构-结构体

    一.结构体的定义 数组(Array)是一组具有相同类型的数据的集合.但在实际的编程过程中,我们往往还需要一组类型不同的数据,例如对于学生信息登记表,姓名为字符串,学号为整数,年龄为整数,所在的学习小组 ...

  10. 配置git的ssh

    Linux,Windows就在git bash here里面输 ① 初始化git账户 git config --global user.name "Eisen" git confi ...