# myLog **Repository Path**: xk857/my-log ## Basic Information - **Project Name**: myLog - **Description**: 使用SpringAOP和自定义注解实现统计接口耗时以及自定义方法名称,使用方法:在具体方法上@Log注解即可实现自定义日志打印。将日志打印到数据库,包括ip地址、方法名称、接口耗时等…… - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 1 - **Created**: 2020-12-03 - **Last Updated**: 2022-01-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 使用Spring AOP编写通用的日志模块 - 使用方法:代码下载后,先向数据库导入sql文件,之后直接运行即可 - 访问:http://localhost:8085/student 可以在控制台和数据库打印出常规日志 - 访问:http://localhost:8085/student/test 可以在控制台和数据库打印错误日志(该接口模拟了一个异常) - 注意:数据库有两张表,如果sql文件不兼容则使用下面的sql语句自行创建表 ## 更新说明 - 新增日志存储到数据库(包含了ip地址,操作系统,方法名,自定义方法描述信息等) - 完善 logback 配置信息 数据库效果: ![数据库效果](http://xk857.com/blog/2020/12image-20201204203858489.png) 放到前端效果: ![前端效果](http://xk857.com/blog/2020/12image-20201204204408456.png) 控制台打印效果: ![控制台打印效果](http://xk857.com/blog/2020/12image-20201204223555146.png) 解析: 当使用自定义注解@Log时,LogAspect执行环绕通知,统计接口耗时情况 ## 源码解析 ### 1.自定义注解 - 解析:声明一个注解,注解可用在方法上。 ```java /** * @author CV大魔王 * @date 2020-12-03 */ @Target(ElementType.METHOD) //声明该注解仅适用与方法 @Retention(RetentionPolicy.RUNTIME) //注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在; public @interface Log { String value() default ""; } ``` ### 2.编写AOP环绕通知 - 解析:当方法使用注解时,会调用到这里的环绕通知 - 注意:需要在启动类加上`@EnableAspectJAutoProxy`开启spring对aspect的支持 ```java @Component @Aspect public class LogAspect { /** * 防止线程冲突 */ ThreadLocal currentTime = new ThreadLocal<>(); /** * 配置切入点 */ @Pointcut("@annotation(com.xk857.annotation.Log)") public void logPointcut() { // 该方法无方法体,主要为了让同类中其他方法使用此切入点 } /** * 环绕通知 * @param joinPoint join point for advice */ @Around("logPointcut()") public Object beforeLog(JoinPoint joinPoint){ currentTime.set(System.currentTimeMillis());//暂存执行时间 Object proceed = null; try { proceed = ((ProceedingJoinPoint) joinPoint).proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); } System.out.println("执行方法:"+getDescription(joinPoint)+" 本次请求耗时:" + (System.currentTimeMillis() - currentTime.get()) + "ms"); currentTime.remove(); return proceed; } /** * 获取方法名 * @return 返回执行方法名,也就是@Log中的内容 */ public String getDescription(JoinPoint joinPoint){ MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); Log aopLog = method.getAnnotation(Log.class); return aopLog.value(); } } ``` ### 3.使用 - 解析:在方法上加入@Log()注解,方法调用时,环绕通知会自动执行 ```java /** * 学生信息控制层 * @author CV大魔王 * @date 2020-12-03 */ @RestController @RequestMapping("/student") public class StudentController { @Autowired private StudentService studentService; @Log("查询所有学生") @GetMapping public List findAll(){ return studentService.queryAll(); } } ``` ### 4.数据库 ```sql CREATE TABLE `student` ( `sid` int(11) NOT NULL COMMENT '学号', `realname` varchar(64) NOT NULL COMMENT '姓名', `gender` varchar(2) DEFAULT NULL COMMENT '性别', `profession` varchar(255) DEFAULT NULL COMMENT '专业', `birthday` date DEFAULT NULL COMMENT '出生日期', `create_time` datetime DEFAULT NULL COMMENT '入学时间', `polity` varchar(64) DEFAULT NULL COMMENT '政治面貌', `stay` varchar(32) DEFAULT NULL COMMENT '是否住宿', `pic` blob COMMENT '照片', PRIMARY KEY (`sid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='学生信息表'; ``` ```sql CREATE TABLE `sys_log` ( `log_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', `description` varchar(255) DEFAULT NULL, `log_type` varchar(255) DEFAULT NULL, `method` varchar(255) DEFAULT NULL, `request_ip` varchar(255) DEFAULT NULL, `time` bigint(20) DEFAULT NULL, `username` varchar(255) DEFAULT NULL, `os` varchar(255) DEFAULT NULL, `browser` varchar(255) DEFAULT NULL, `exception_detail` text, `create_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`log_id`) USING BTREE, KEY `log_create_time_index` (`create_time`) USING BTREE, KEY `inx_log_type` (`log_type`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=3879 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='系统日志'; ``` ### 5.异常日志打印 思维解析:定义全局异常处理器,使用springAOP增强环绕通知方法来处理