Spring Boot 使用AOP切面编程记录用户操作日志


前言:最近想做一个用户日志记录,几经寻找,发现都比较复杂,有的代码不详细,根本看不懂,我觉得这个方法比较简单,所以分享给大家
在Spring框架中使用AOP配合自定义注解监控用户操作。首先搭建一个基本的Spring Boot Web环境开启

1、pom.xml导入依赖

        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--引入druid依赖-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.14</version>
        </dependency>

        <!--Spring Boot Mybatis 依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.2.0</version>
        </dependency>

        <!-- MySQL 连接驱动依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.39</version>
        </dependency>
        
       <!-- 这里我使用lombok生成getting和setting等方法,如果没安装插件的,可以不需要加这个 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.20</version>
            <scope>provided</scope>
        </dependency>
        
        <!-- aop依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2、实体类(com.stodgy.bean)

这里我使用lombok插件快速生成的getting和setting,如果没装插件的要记得手动加上getting和setting方法

@Getter
@Setter
@ToString
@Data
//系统日志管理
public class SystemLog {
    /**
    * 主键,标识列,自动生成
    */
    private Integer logid;

    /**
    * 关联员工表主键
    */
    private String empname;

    /**
    * Ip地址
    */
    private String ipaddr;

    /**
    * 操作时间
    */
    private Date optime;

    /**
    * 操作的内容
    */
    private String params;

    /**
    * 信息
    */
    private String msg;
}

3、SystemLogDao Dao层(com.stodgy.dao)

@Repository
@Transactional
public interface SystemLogDao {
	
	//保存日志信息到数据库
    int insert(SystemLog systemLog);

}

4、新建对应dao层的mapper.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.stodgy.dao.SystemLogDao">

  <insert id="insert" keyColumn="logId" keyProperty="logid" parameterType="com.stodgy.bean.SystemLog" useGeneratedKeys="true">
    <!--@mbg.generated-->
    insert into systemLog (empName, ipAddr, optime,
      `params`, msg)
    values (#{empname,jdbcType=VARCHAR}, #{ipaddr,jdbcType=VARCHAR}, #{optime,jdbcType=TIMESTAMP},
      #{params,jdbcType=VARCHAR}, #{msg,jdbcType=VARCHAR})
  </insert>
</mapper>

5、Service (com.stodgy.service)

public interface SystemLogService {

   	int insert(SystemLog systemLog);
}

6、ServiceImpl (com.stodgy.service.impl)

@Service
public class SystemLogServiceImpl implements SystemLogService {

    @Resource
    private SystemLogDao sd;

    @Override
    public int insert(SystemLog systemLog) {
        return sd.insert(systemLog);
    }

}

前面这些基本只是一些准备工作,下面步入主题

7、Log (com.stodgy.annotation)

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
    String value() default "";
}

8、工具类 IPUtils 和 HttpContextUtils (com.stodgy.common)

IPUtils

public class IPUtils {
    /**
     * 获取IP地址
     *
     * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
     * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
     */
    public static String getIpAddr(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 "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }
}

HttpContextUtils

public class HttpContextUtils {
    public static HttpServletRequest getHttpServletRequest() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    }
}

9、LogAspect(com.stodgy.aspect)

@Aspect
@Component
public class LogAspect {

    @Autowired
    private SystemLogDao sd;

    @Pointcut("@annotation(com.ht.annotation.Log)")
    public void pointcut() { }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point) {
        Object result = null;
        long beginTime = System.currentTimeMillis();
        try {
            // 执行方法
            result = point.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        // 执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        // 保存日志
        saveLog(point, time);
        return result;
    }

    private void saveLog(ProceedingJoinPoint joinPoint, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        SystemLog systemLog = new SystemLog();
        Log logAnnotation = method.getAnnotation(Log.class);
        if (logAnnotation != null) {
            //获取注解@Log在controller上的描述
            systemLog.setMsg(logAnnotation.value());
        }

        // 获取request
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
        //获取session
        HttpSession session = request.getSession();
        // 设置IP地址
        systemLog.setIpaddr(IPUtils.getIpAddr(request));
       	//这里我是获取登录的用户,我已将登录的用户的信息放进了session
        //获取session的用户
        Emp emp = (Emp)session.getAttribute("emp");
        systemLog.setEmpname(emp.getEmpname());
        //设置登录时间
        systemLog.setOptime(new Date());
        //设置登录参数
        systemLog.setParams(emp.toString());

        // 保存系统日志
        sd.insert(systemLog);
    }
}

10、在需要监控的控制器上(com.stodgy.controller)

这里我已登录员工为例子
@Controller
@RequestMapping("/login")
public class LoginController {

    @Resource
    private LoginService ls;
    
    //在每个方法前加,当访问这个方法的时候,就会自动去保存你已经设置好的日志信息
    @Log("登录系统")
    //查询是否该员工账号
    @RequestMapping("/isnEmp")
    @ResponseBody
    public Map isnEmp(Emp emp, HttpSession session){
        Emp login = ls.login(emp);
        Map map = new HashMap();
        if (login!=null){
            session.setAttribute("emp",login);
            map.put("i",1);
        }
        return map;
    }

    //退出登录
    @RequestMapping("/out")
    public String out(HttpSession session){
        session.removeAttribute("emp");
        return "login";
    }
}

最后,一起看看效果吧

运行效果图

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值