1. 程式人生 > >Spring Boot 使用AOP記錄操作日誌

Spring Boot 使用AOP記錄操作日誌

前言

在寫Aurora這個專案之前,我是通過攔截器去記錄使用者操作日誌,而這裡講解如何使用AOP配合自定義註解去實現使用者日誌記錄,使用攔截器的方式,下一章貼出

匯入依賴

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

部分配置檔案

spring:
  datasource:
    url
: jdbc:mysql://localhost:3306/log username: root password: 123456 jpa: hibernate: ddl-auto: update

自定義log註解

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

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

建立實體類

@Entity
@Data
@Table
(name = "syslog") public class SysLog implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String username; private String operation; private Integer time; private String method; private String params; private
String ip; /** * ip地址來源 */ private String location; @CreationTimestamp private Timestamp createTime; }

建立 repository

@Repository
public interface SysLogRepo extends JpaRepository<SysLog,Long>{
}

切面和切點

定義一個LogAspect類,使用@Aspect標註讓其成為一個切面,切點為使用@Log註解標註的方法,使用@Around環繞通知,部門工具程式碼,這裡就不貼出了,可以到原始碼中檢視

@Slf4j
@Aspect
@Component
public class LogAspect {

	@Autowired
	private SysLogRepo sysLogRepo;

	@Pointcut("@annotation(me.zhengjie.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;
    }

    public 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();
        String username = null;
        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(AddressUtils.getIpAddr(request));
        sysLog.setLocation(AddressUtils.getCityInfo(sysLog.getIp()));

        //模擬一個使用者名稱
        sysLog.setUsername("admin");
        sysLog.setTime((int) time);
        sysLogRepo.save(sysLog);
    }
}

專案結構如下

測試

編寫TestController


@RestController
public class TestController {

    @Autowired
    private SysLogRepo sysLogRepo;

    @Log("記錄測試")
    @GetMapping(value = "/test")
    public String test1(String test){

        return test;
    }

    @GetMapping(value = "/list")
    public ModelAndView list(Model model){

        List<SysLog> sysLogs = sysLogRepo.findAll();
        model.addAttribute("sysLogs",sysLogs);

        return new ModelAndView("/index");
    }
}

依次訪問:

專案原始碼

開源後臺管理系統

歡迎體驗Aurora