使用AOP监控用户操作并插入数据库
引入依赖
<!--spring切面aop依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
在application.properties添加配置
spring.aop.auto=true
1.创建自定义注解类
当然该注解类可以使用spring自带注解类:@Before,@After,@AfterRuturning ,@AfterThrowing ,@Around 。
只是这5种方式的作用不同:
(1)Before ---在所拦截方法执行前执行;
(2)After ---在所拦截方法执行后执行;
(3)AfterRuturning ---在所拦截方法返回值后,执行;
(4)AfterThrowing ---当所拦截方法抛出异常时,执行;
(5)Around ---最为复杂的切入方式,刚方式可以包括上述4个方式。
import java.lang.annotation.*; /**
* 自定义注解类
* @author MrRoot
* @date 2019-01-16
*/
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented //生成文档
public @interface MyLog {
String value() default "";
}
2.生成日志实体类
博主使用的是mybatisplus根据表信息生成的实体类,当然也可以使用普通实体类。
import com.baomidou.mybatisplus.enums.IdType;
import java.util.Date;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableField;
import com.baomidou.mybatisplus.enums.FieldFill;
import com.baomidou.mybatisplus.activerecord.Model;
import com.baomidou.mybatisplus.annotations.TableName;
import java.io.Serializable; /**
* <p>
* 日志表
* </p>
*
* @author MrRoot
* @since 2019-01-16
*/
@TableName("research_log")
public class Log extends Model<Log> { private static final long serialVersionUID = 1L; /**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 用户id
*/
@TableField("user_id")
private Long userId;
/**
* 操作时用户的ip地址
*/
private String ip;
/**
* 操作详情
*/
private String operation;
/**
* 创建时间
*/
@TableField(value = "gmt_create", fill = FieldFill.INSERT)
private Date gmtCreate;
/**
* 更新时间
*/
@TableField(value = "gmt_modified", fill = FieldFill.INSERT_UPDATE)
private Date gmtModified; public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public Long getUserId() {
return userId;
} public void setUserId(Long userId) {
this.userId = userId;
} public String getIp() {
return ip;
} public void setIp(String ip) {
this.ip = ip;
} public String getOperation() {
return operation;
} public void setOperation(String operation) {
this.operation = operation;
} public Date getGmtCreate() {
return gmtCreate;
} public void setGmtCreate(Date gmtCreate) {
this.gmtCreate = gmtCreate;
} public Date getGmtModified() {
return gmtModified;
} public void setGmtModified(Date gmtModified) {
this.gmtModified = gmtModified;
} @Override
protected Serializable pkVal() {
return this.id;
} @Override
public String toString() {
return "Log{" +
", id=" + id +
", userId=" + userId +
", ip=" + ip +
", operation=" + operation +
", gmtCreate=" + gmtCreate +
", gmtModified=" + gmtModified +
"}";
}
}
3.系统日志:处理切面类
其中最后的insert方法为mybatisplus封装好的插入方法,如果使用普通实体类则需要自己写插入数据库的方法。
IPUtils方法见附录
import com.alibaba.fastjson.JSON; import com.panshi.cecdc.research.entity.Log;
import com.panshi.cecdc.research.service.LogService;
import com.panshi.cecdc.research.util.IPUtils;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date; /**
* 系统日志:切面处理类
* @author MrRoot
* @date 2019-01-16
*/
@Aspect
@Component
public class SysLogAspect { @Autowired
private LogService logService; /**
* 定义切点 @Pointcut
* 在注解的位置切入代码
*/
@Pointcut("@annotation(com.panshi.cecdc.research.common.MyLog)")
public void logPointCut() {
} /**
* 切面 配置通知
* @param joinPoint
*/
@AfterReturning("logPointCut()")//这里可以选择日志插入的方式
public void saveSysLog(JoinPoint joinPoint) {
//保存日志
Log log = new Log(); //从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//获取切入点所在的方法
Method method = signature.getMethod(); //获取操作
MyLog myLog = method.getAnnotation(MyLog.class);
if (myLog != null) {
String value = myLog.value();
//保存获取的操作
log.setOperation(value);
} //获取请求的类名
//String className = joinPoint.getTarget().getClass().getName();
//获取请求的方法名
//String methodName = method.getName();
//sysLog.setMethod(className + "." + methodName); //请求的参数
//Object[] args = joinPoint.getArgs();
//将参数所在的数组转换成json
//String params = JSON.toJSONString(args);
//log.setParams(params); log.setGmtCreate(new Date());
//获取用户名
log.setUserId((Long)SecurityUtils.getSubject().getSession().getAttribute("userId"));
//获取用户ip地址
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
log.setIp(IPUtils.getIp(request));
//调用service保存SysLog实体类到数据库
logService.insert(log);
} }
4.在需要监控的controller方法上加上注解
@MyLog(value = "用户详情")//操作类型
@GetMapping("/detail")
public Result detail(@RequestParam("id") Long id){ return Result.createBySuccess(sysUserService.detail(id));
}
5.结果示例

附录:
IPUtils:
import org.apache.commons.lang3.StringUtils; import javax.servlet.http.HttpServletRequest; /**
* ip工具类
* @author MrRoot
* @date 2019-01-16
*/
public class IPUtils { private static final String UNKNOWN = "unKnown"; public static String getIp(HttpServletRequest request) { String ip = request.getHeader("X-Forwarded-For");
if(StringUtils.isNotEmpty(ip) && !UNKNOWN.equalsIgnoreCase(ip)){
//多次反向代理后会有多个ip值,第一个ip才是真实ip
int index = ip.indexOf(",");
if(index != -1){
return ip.substring(0,index);
}else{
return ip;
}
}
ip = request.getHeader("X-Real-IP");
if(StringUtils.isNotEmpty(ip) && !UNKNOWN.equalsIgnoreCase(ip)){
return ip;
}
return request.getRemoteAddr();
}
}
使用AOP监控用户操作并插入数据库的更多相关文章
- aop 记录用户操作(一)
转载: http://www.cnblogs.com/guokai870510826/p/5981015.html 使用标签来设置需要的记录 实例:@ISystemLog() @Controller ...
- Linux下监控用户操作轨迹
在实际工作当中,都会碰到误删除.误修改配置文件等事件.如果没有堡垒机,要在linux系统上查看到底谁对配置文件做了误操作,特别是遇到删库跑路的事件,当然可以通过history来查看历史命令记录,但如果 ...
- TinyFrame尾篇:整合Spring AOP实现用户认证
创建Manager用户验证表 这一篇主要讲解使用AOP对用户操作进行验证,如果通过验证,则继续执行,反之,则不能执行.其思想和上一篇完全一致. 由于需要用到用户认证,所以我们新建一个Manager实体 ...
- 微软企业库5.0 学习之路——第九步、使用PolicyInjection模块进行AOP—PART4——建立自定义Call Handler实现用户操作日志记录
在前面的Part3中, 我介绍Policy Injection模块中内置的Call Handler的使用方法,今天则继续介绍Call Handler——Custom Call Handler,通过建立 ...
- 我使用Spring AOP实现了用户操作日志功能
我使用Spring AOP实现了用户操作日志功能 今天答辩完了,复盘了一下系统,发现还是有一些东西值得拿出来和大家分享一下. 需求分析 系统需要对用户的操作进行记录,方便未来溯源 首先想到的就是在每个 ...
- MySQL数据库(6)_用户操作与权限管理、视图、存储过程、触发器、基本函数
用户操作与权限管理 MySQL用户操作 创建用户 方法一: CREATE USER语句创建 CREATE USER "用户名"@"IP地址" IDENTIFIE ...
- Spring AOP使用注解记录用户操作日志
最后一个方法:核心的日志记录方法 package com.migu.cm.aspect; import com.alibaba.fastjson.JSON; import com.migu.cm.do ...
- python scrapy 插入数据库的操作
需要安装这个 pymysql 写法还是很简单的 # -*- coding: utf-8 -*- # Define your item pipelines here # # Don't forget t ...
- Mysql 创建权限较小的用户(只对特定数据库有操作权限)
项目开发过程中,因为root的权限太大,可能对其他数据库造成修改.故创建一权限较小的用户,使其只能对特定的数据库操作,以保证数据安全. 主要语句如下: grant all on bos19.* to ...
随机推荐
- 树莓派 Learning 002 装机后的必要操作 --- 02 解决中文问题
树莓派 装机后的必要操作 - 解决中文问题 我的树莓派型号:Raspberry Pi 2 Model B V1.1 装机系统:NOOBS v1.9.2 每一块树莓派,装机后都应该执行的步骤 刚装机后, ...
- Learning Python 009 dict(字典)和 set
Python dict(字典)和 set dict (字典)是什么东西 dict全称dictionary.为什么这个数据结构取名叫dict.因为dict的实现原理和查字典是一样的.dict使用了键-值 ...
- 内核启动流程2-C语言部分的最后一个函数init_post()
最后分析最终调用用户空间init进程的函数init_post(). static noinline int init_post(void)这是一个非_init函数.强制让它为非内联函数,以防gcc让它 ...
- Prim算法:最小生成树---贪心算法的实现
算法图解: http://baike.baidu.com/link?url=hGNkWIOLRJ_LDWMJRECxCPKUw7pI3s8AH5kj-944RwgeBSa9hGpTaIz5aWYsl_ ...
- Java学习之多态(Polymorphism)
多态==晚绑定 不要把函数重载理解为多态. 因为多态是一种运行期的行为,不是编译期的行为. 多态:父类型的引用可以指向子类型的对象. 比如 Parent p = new Child(); 当使用多态方 ...
- ubuntu下apache2的cgi-bin中以root权限运行程序
一,安装apache2 sudo apt-get install apache2 二.配置cgi-bin sudo chmod 777 /var/www/html sudo vim /etc/apac ...
- 理解linux服务器mcelog如何工作
What are Machine Check Exceptions (or MCE)? A machine check exception is an error dedected by your s ...
- Python中读取,显示,保存图片的方法
一 opencv import cv2 as cv # load img = cv.imread(imagepath) # shape=(height, width, channel) h,w,c = ...
- Educational Codeforces Round 64 (Rated for Div. 2)D(并查集,图)
#include<bits/stdc++.h>using namespace std;int f[2][200007],s[2][200007];//并查集,相邻点int find_(in ...
- 洛谷P1311 选择客栈
P1311 选择客栈 题目描述 丽江河边有n 家很有特色的客栈,客栈按照其位置顺序从 1 到n 编号.每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0 ~ k-1 表示),且每家客栈都设有一 ...