Spring Boot AOP記錄用戶操做日誌

在Spring框架中,使用AOP配合自定義註解能夠方便的實現用戶操做的監控。首先搭建一個基本的Spring Boot Web環境開啓Spring Boot,而後引入必要依賴:html

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

<!-- aop依賴 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<!-- oracle驅動 -->
<dependency>
   <groupId>com.oracle</groupId>
   <artifactId>ojdbc6</artifactId>
   <version>6.0</version>
</dependency>

<!-- druid數據源驅動 -->
<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>druid-spring-boot-starter</artifactId>
   <version>1.1.6</version>
</dependency>

自定義註解

定義一個方法級別的@Log註解,用於標註須要監控的方法:git

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

建立庫表和實體

在數據庫中建立一張sys_log表,用於保存用戶的操做日誌,數據庫採用oracle 11g:github

CREATE TABLE "SCOTT"."SYS_LOG" (
   "ID" NUMBER(20) NOT NULL ,
   "USERNAME" VARCHAR2(50 BYTE) NULL ,
   "OPERATION" VARCHAR2(50 BYTE) NULL ,
   "TIME" NUMBER(11) NULL ,
   "METHOD" VARCHAR2(200 BYTE) NULL ,
   "PARAMS" VARCHAR2(500 BYTE) NULL ,
   "IP" VARCHAR2(64 BYTE) NULL ,
   "CREATE_TIME" DATE NULL 
);

COMMENT ON COLUMN "SCOTT"."SYS_LOG"."USERNAME" IS '用戶名';
COMMENT ON COLUMN "SCOTT"."SYS_LOG"."OPERATION" IS '用戶操做';
COMMENT ON COLUMN "SCOTT"."SYS_LOG"."TIME" IS '響應時間';
COMMENT ON COLUMN "SCOTT"."SYS_LOG"."METHOD" IS '請求方法';
COMMENT ON COLUMN "SCOTT"."SYS_LOG"."PARAMS" IS '請求參數';
COMMENT ON COLUMN "SCOTT"."SYS_LOG"."IP" IS 'IP地址';
COMMENT ON COLUMN "SCOTT"."SYS_LOG"."CREATE_TIME" IS '建立時間';

CREATE SEQUENCE seq_sys_log START WITH 1 INCREMENT BY 1;

庫表對應的實體:web

public class SysLog implements Serializable{

    private static final long serialVersionUID = -6309732882044872298L;
    
    private Integer id;
    private String username;
    private String operation;
    private Integer time;
    private String method;
    private String params;
    private String ip;
    private Date createTime;
    // get,set略
}

保存日誌的方法

爲了方便,這裏直接使用Spring JdbcTemplate來操做數據庫。定義一個SysLogDao接口,包含一個保存操做日誌的抽象方法:spring

public interface SysLogDao {
    void saveSysLog(SysLog syslog);
}

其實現方法:sql

@Repository
public class SysLogDaoImp implements SysLogDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Override
    public void saveSysLog(SysLog syslog) {
        StringBuffer sql = new StringBuffer("insert into sys_log ");
        sql.append("(id,username,operation,time,method,params,ip,create_time) ");
        sql.append("values(seq_sys_log.nextval,:username,:operation,:time,:method,");
        sql.append(":params,:ip,:createTime)");
        
        NamedParameterJdbcTemplate npjt = new NamedParameterJdbcTemplate(this.jdbcTemplate.getDataSource());
        npjt.update(sql.toString(), new BeanPropertySqlParameterSource(syslog));
    }
}

切面和切點

定義一個LogAspect類,使用@Aspect標註讓其成爲一個切面,切點爲使用@Log註解標註的方法,使用@Around環繞通知:數據庫

@Aspect
@Component
public class LogAspect {

    @Autowired
    private SysLogDao sysLogDao;
    
    @Pointcut("@annotation(com.springboot.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();
        SysLog sysLog = new SysLog();
        Log logAnnotation = method.getAnnotation(Log.class);
        if (logAnnotation != null) {
            // 註解上的描述
            sysLog.setOperation(logAnnotation.value());
        }
        // 請求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLog.setMethod(className + "." + methodName + "()");
        // 請求的方法參數值
        Object[] args = joinPoint.getArgs();
        // 請求的方法參數名稱
        LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
        String[] paramNames = u.getParameterNames(method);
        if (args != null && paramNames != null) {
            String params = "";
            for (int i = 0; i < args.length; i++) {
                params += "  " + paramNames[i] + ": " + args[i];
            }
            sysLog.setParams(params);
        }
        // 獲取request
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
        // 設置IP地址
        sysLog.setIp(IPUtils.getIpAddr(request));
        // 模擬一個用戶名
        sysLog.setUsername("mrbird");
        sysLog.setTime((int) time);
        sysLog.setCreateTime(new Date());
        // 保存系統日誌
        sysLogDao.saveSysLog(sysLog);
    }
}

測試

TestController:springboot

@RestController
public class TestController {

    @Log("執行方法一")
    @GetMapping("/one")
    public void methodOne(String name) { }
    
    @Log("執行方法二")
    @GetMapping("/two")
    public void methodTwo() throws InterruptedException {
        Thread.sleep(2000);
    }
    
    @Log("執行方法三")
    @GetMapping("/three")
    public void methodThree(String name, String age) { }
}

最終項目目錄以下圖所示:oracle

QQ截圖20171208113619.png

啓動項目,分別訪問:app

查詢數據庫:

SQL> select * from sys_log order by id;

        ID USERNAME   OPERATION        TIME METHOD                         PARAMS                         IP         CREATE_TIME
---------- ---------- ---------- ---------- ------------------------------ ------------------------------ ---------- --------------
        11 mrbird     執行方法一          6 com.springboot.controller.Test  name: KangKang                127.0.0.1  08-12月-17
                                            Controller.methodOne()

        12 mrbird     執行方法二       2000 com.springboot.controller.Test                                127.0.0.1  08-12月-17
                                            Controller.methodTwo()

        13 mrbird     執行方法三          0 com.springboot.controller.Test  name: Mike age: 25            127.0.0.1  08-12月-17
                                            Controller.methodThree()

source code 本文由博客一文多發平臺 OpenWrite 發佈!

相關文章
相關標籤/搜索