Spring Aop自定义注解方式实现记录用户操作日志功能(SSM)

目的
为了实现用户做的每一步操作都被后台记录下来。
思路
1,创建自定义注解。
2,在要记录的方法中加上自定义注解。
3,拦截浏览器发送的请求。
4,加载访问的类
5,获取这个方法的方法名,然后根据AOP拦截的请求进行判断是否是同一个。
6,判断这个拦截的方法有没有自定义的注解。
7,获取注解的值,然后写入数据库。
实现
创建数据库

DROP TABLE IF EXISTS `sys_log`;
CREATE TABLE `sys_log` (
  `id` int(64) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(64) DEFAULT NULL,
  `optIp` varchar(255) DEFAULT NULL COMMENT '操作IP',
  `operation` varchar(255) DEFAULT NULL COMMENT '操作',
  `content` varchar(255) DEFAULT NULL COMMENT '内容',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx` (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8mb4 COMMENT='日志管理';

自定义注解类

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OperationLogger {
    String modelName() default "";
    String option();
}

面向切面编程,aop拦截类

@Aspect
public class LogAspect {
    @Autowired
    private LogService logService;
    
    /**
     * 用户创建订单
     */
    @Pointcut("@annotation(com.zxzc.aspect.OperationLogger)")
    public void controllerAspect(){
        System.out.println("切入点》》》》");
    }

    @AfterReturning("controllerAspect()")
    public void doAfterReturn(JoinPoint joinPoint){
        System.out.println("==========后置通知=========");
        handleLog(joinPoint);
    }

    private void handleLog(JoinPoint joinPoint){
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            UserInfo user = (UserInfo) request.getSession().getAttribute("userInfo");
            //获取横切的方法名
            String methodName = joinPoint.getSignature().getName();
//            String methodName = signature.substring(
//                    signature.lastIndexOf(".")+1,signature.indexOf("("));
            //获取拦截的class
            String classType = joinPoint.getTarget().getClass().getName();
            //加载这个类
            Class<?> clazz = Class.forName(classType);
            //获取这个类上的方法名
            Method[] methods = clazz.getDeclaredMethods();
            System.out.println("methodName:"+methodName);
            /**
             * 循环判断,对所有方法进行循环遍历
             */
            for (Method method:methods){
                // 如果这个方法上面的注解是否含有自定义的注解
                // 并且方法名等于切点访问的方法名
                if (method.isAnnotationPresent(OperationLogger.class)
                        &&method.getName().equals(methodName)){
                    //获取method的注解
                    OperationLogger operationLogger = method.getAnnotation(OperationLogger.class);
                    //也可以用这种方式获取
                    /*Annotation[] annotations = method.getAnnotations();
                    for (Annotation annotation:annotations){
                        if (annotation instanceof OperationLogger){
                            OperationLogger operationLogger = (OperationLogger) annotation;
                        }
                    }*/
                    SysLog sysLog = new SysLog();
                    if (user!=null){
                        sysLog.setUserName(user.getUserName());
                        sysLog.setOptip(RequestIpUtil.getRemoteHost(request));
                    }else{
                        sysLog.setUserName("未登录用户");
                        sysLog.setOptip(RequestIpUtil.getRemoteHost(request));
                    }
                    sysLog.setCreateTime(new Date());
                    sysLog.setOperation(operationLogger.option());
                    sysLog.setContent(operationLogger.modelName());
                    logService.insertLog(sysLog);
                }
            }
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

LogService接口

public interface LogService {
    void insertLog(SysLog sysLog);
}

LogServiceImpl类

@Service("logService")
public class LogServiceImpl implements LogService {

    @Autowired
    private SysLogMapper sysLogMapper;

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void insertLog(SysLog sysLog) {
        sysLogMapper.insertSelective(sysLog);
    }
}

SysLogMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.zxzc.dao.SysLogMapper" >
  <resultMap id="BaseResultMap" type="com.zxzc.pojo.SysLog" >
    <constructor >
      <idArg column="id" jdbcType="INTEGER" javaType="java.lang.Integer" />
      <arg column="user_name" jdbcType="VARCHAR" javaType="java.lang.String" />
      <arg column="optIp" jdbcType="VARCHAR" javaType="java.lang.String" />
      <arg column="operation" jdbcType="VARCHAR" javaType="java.lang.String" />
      <arg column="content" jdbcType="VARCHAR" javaType="java.lang.String" />
      <arg column="create_time" jdbcType="TIMESTAMP" javaType="java.util.Date" />
    </constructor>
  </resultMap>
  <sql id="Base_Column_List" >
    id, user_name, optIp, operation, content, create_time
  </sql>
  
  <insert id="insertSelective" parameterType="com.zxzc.pojo.SysLog" >
    insert into sys_log
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        id,
      </if>
      <if test="userName != null" >
        user_name,
      </if>
      <if test="optip != null" >
        optIp,
      </if>
      <if test="operation != null" >
        operation,
      </if>
      <if test="content != null" >
        content,
      </if>
      <if test="createTime != null" >
        create_time,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        #{id,jdbcType=INTEGER},
      </if>
      <if test="userName != null" >
        #{userName,jdbcType=VARCHAR},
      </if>
      <if test="optip != null" >
        #{optip,jdbcType=VARCHAR},
      </if>
      <if test="operation != null" >
        #{operation,jdbcType=VARCHAR},
      </if>
      <if test="content != null" >
        #{content,jdbcType=VARCHAR},
      </if>
      <if test="createTime != null" >
        #{createTime,jdbcType=TIMESTAMP},
      </if>
    </trim>
  </insert>
</mapper>

springmvc.xml配置文件中加入

<aop:config proxy-target-class="true"></aop:config>
<aop:aspectj-autoproxy />
<bean id="logAspect" class="com.zxzc.aspect.LogAspect" />

记录获取Ip地址的Util类

public class RequestIpUtil {
    public static String getRemoteHost(javax.servlet.http.HttpServletRequest request){
        String ip = request.getHeader("x-forwarded-for");
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
            ip = request.getHeader("Proxy-Client-IP");
        }
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
            ip = request.getRemoteAddr();
        }
        return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip;
    }
}

然后在要拦截的方法上加上

@OperationLogger(modelName = "操作名称",option = "操作接口")

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值