SpringAOP + 注解实现日志管理
时间:2022-07-27
本文章向大家介绍SpringAOP + 注解实现日志管理,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
SpringAOP + 注解实现日志管理
1. 什么是AOP
?
AOP
(Aspect Orient Programming),翻译过来就是面向切面编程,面向对象编程是将程序抽象成多个层次的对象,面向切面是将程序抽象成多个切面
2. 为什么要使用AOP
(场景说明)
在时间开发中,我们有很多模块中会使用到重复的代码,我们肯定不会通过复制的形式来复用代码.当然解决方式也是多种的,通常我们会将重复的代码抽离出来,提取成一个方法或者是一个抽象的类.然后在需要调用的地方,调用这个方法即可.但是随着我们的业务改变,加入改方法被删除不需要使用,我们需要对所有调用的地方进行单独的删除,这就增加了工作的难度,此时便有了AOP
.AOP
的原理是代理模式
3. 实际案例
使用AOP的方式,完成日志管理
1. 日志管理数据结构
CREATE TABLE `sys_log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`operation` varchar(50) DEFAULT NULL COMMENT '操作',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`method_name` varchar(100) DEFAULT NULL COMMENT '方法名',
`param_name` varchar(500) DEFAULT NULL COMMENT '参数',
`ip` varchar(100) DEFAULT NULL COMMENT 'ip地址',
`username` varchar(50) DEFAULT NULL COMMENT '用户名',
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
日志表对应的实体类,mapper
,service
,controller
可以通过mybatisplus
自动生成,这里就省略不写了.
2. 日志管理切入面(代码加强)
/**
* @ClassName LoginLogAspect
* @Description 操作日志切入面
* @Author xiongchao
* @Date 2020/9/27 10:22
**/
@Aspect
@Component
public class SysLogAspect {
@Autowired
private ISysLogService logService;
@Autowired
private ApplicationProperties properties;
@Autowired
private JwtTokenUtil util;
//定义切点 @Pointcut
//在注解的位置切入代码
@Pointcut("@annotation( com.adingxiong.cft.aop.Mylog)")
public void logPoinCut() {
}
//切面 配置通知
@AfterReturning("logPoinCut()")
public void savaLog(JoinPoint joinpoin){
SysLog sysLog = new SysLog();
//从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinpoin.getSignature();
//获取切入点所在的方法
Method method = signature.getMethod();
Mylog myLog = method.getAnnotation(Mylog.class);
if(myLog != null){
String value = myLog.value();
sysLog.setOperation(value);
}
//获取请求的类名
String className = joinpoin.getTarget().getClass().getName();
//获取请求的方法名
String methodName = method.getName();
sysLog.setMethodName(className + "." + methodName);
HttpServletRequest request=((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
String token = request.getHeader(properties.getTokenHeader());
String authToken = token.substring(properties.getTokenHead().length());
String username = util.getUserNameFromToken(authToken);
sysLog.setUsername(username);
String ip = IpUtils.getRealIp(request);
sysLog.setIp(ip);
//请求参数
Object args [] = joinpoin.getArgs();
String param = JSON.toJSONString(args);
sysLog.setParamName(param);
sysLog.setCreateTime(new Date());
logService.save(sysLog);
}
}
3. 获取IP
的工具类
/**
* @ClassName IpUtils
* @Description 获取用户的真实ip
* @Author xiongchao
* @Date 2020/9/27 10:08
**/
public class IpUtils {
public static String getRealIp(HttpServletRequest request) {
String ipAddress = request.getHeader("x-forwarded-for");
if(ipAddress == null || ipAddress.length() ==0 || "unknown".equals(ipAddress)){
ipAddress = request.getHeader("Proxy-Client-IP");
}
if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isEmpty(ipAddress) || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isEmpty(ipAddress) || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){
//根据网卡取本机配置的IP
InetAddress inet=null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
ipAddress= inet.getHostAddress();
}
}
//对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15
if(ipAddress.indexOf(",")>0){
ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));
}
}
return ipAddress;
}
}
4. 自定义注解(通过注解的方式调用切面方法)
/**
* @ClassName Mylog
* @Description TODO
* @Author xiongchao
* @Date 2020/9/27 10:29
**/
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented //生成文档
public @interface Mylog {
String value() default "";
}
5. 测试
在Service
层或者controller
层添加@MyLog(value="xxxxx")
注解完成调用
@Mylog(value = "获取当前用户信息")
@ApiOperation(value = "获取当前登录用户信息")
@GetMapping("/info")
public Result<Map<String,Object>> getUserInfo(Principal principal){
if(principal == null){
return Result.unauthorized(null);
}
String username = principal.getName();
TUser user = userService.getUserByUsername(username);
List<Role> list = roleService.getUserRole(user.getId());
Map<String,Object> res = new HashMap<>();
res.put("userInfo",user);
res.put("role",list);
return Result.success(res);
}
本文使用 mdnice 排版
Donate
- 不经意发现的dba_objects和dba_tables中的细节(r7笔记第56天)
- LeetCode——Longest Substring Without Repeating Characters
- Python time模块详解(时间戳↔元组形式↔格式化形式三者转化)
- Maven 核心原理解析(2)
- Linux C 编程——互斥锁mutex
- python两个 list 获取交集,并集,差集的方法.
- python——时间与时间戳之间的转换
- Maven 核心原理解析(3)
- String中的null,以及String s;等区别详解
- Shell编程——Shell中的数学运算
- 如何利用微信监管你的TF训练?
- python 安装spark_Spark环境搭建 (Python)
- MongoDB触发oom-killer的简单处理(一)(r7笔记第54天)
- int与integer的区别
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- ubuntu中python调用C/C++方法之动态链接库详解
- linux下cat命令连接文件并打印到标准输出设备上
- 详解Linux误删用户家目录的恢复方法
- Linux下sshd服务及服务管理命令详解
- 关于CentOS 7下sqlite3找不到的问题解决
- 宝塔Linux面板之好用免费的中文Linux VPS主机控制面板适合快速建站
- Linux中openssl/opensslv.h找不到问题的解决方法
- CentOS7 安装 PostgreSQL11的方法步骤
- Linux中FTP服务器的搭建教程
- ubuntu下编译安装opencv的方法
- CentOS7如何执行PHP定时任务详解
- linux中ssh免密通信的实现
- Linux 启动停止SpringBoot jar 程序部署Shell 脚本的方法
- linux下安装boost库的完整步骤记录
- Linux下使用killall命令终止进程的8大用法实例详解