使用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();
    }
}

 

 

 

 

 

 

 

 

 

 



posted @ 2019-01-16 16:16  MRoot  阅读(1585)  评论(0编辑  收藏  举报