AOP實現日志記錄功能


場景:整個系統的DML操作需要記錄日志

記錄內容:1 操作人 2 操作時間 3 操作類型(登錄 新增 修改 刪除) 4 操作描述  5 詳細請求數據(varchar2()) 6 操作IP  ==>日志表

實現:

原來方式:在每個方法的里面編寫記錄日志代碼;

缺點:代碼重復 ,與原有邏輯耦合度高。

AOP: 將日志記錄功能提取到切面中。動態切入到需要日志記錄的方法上即可;

優點: 解耦合,代碼復用。

1) 先寫一個日志切面LogAspect.java;

// 日志切面
@Component//對象由spring管理
@Aspect// 切面注解
public class LogAspect {
    //定義切入點,切入到添加了LogData注解的方法上
    @Pointcut("@annotation(aop.LogData)")
    public void pointCut(){}
    /**
     *  記錄日志的切面方法
     *  在該方法中定義統一的日志記錄邏輯
     * @param joinPoint
     */
    @Before("pointCut()")
    public void log(JoinPoint joinPoint){
        System.out.println("進入日志Aspect");
    }
}

2)寫一個日志信息LogData.java;

// 自定義日志注解
@Target({ElementType.METHOD})//指定作用的目標對象(可以添加的位置)
@Retention(RetentionPolicy.RUNTIME)//指定在運行期間起作用
public @interface LogData {
    //定義注解中的屬性
    String description() default "";
    //日志類型
    int logType();
}

3)在控制層方法上寫上注解,加上描述信息,描述日志;

    @LogData(logType = 1,description = "學生信息修改")
    @RequestMapping("/update")
    public String update(Integer id,ModelMap modelMap){
        //查詢用戶信息,展示到頁面
        Student student=studentService.findById(id);
        modelMap.put("student",student);
        return "update.jsp";
    }

要想起作用,還要在springmvc.xml配置文件中配置AOP注解;

     <!--配置注解式AOP支持-->
     <aop:aspectj-autoproxy proxy-target-class="true"/>

二、自定義注解

枚舉:jdk1.5之后存在的一種數據類型。用來定義有限個對象。 enum

語法:

Public enum 類名{

對象定義;

類的成員定義

}

調用: 類名.對象名 獲取枚舉對象。

1)創建一個LogType.java文件來寫枚舉;

/**
 * 日志枚舉類型
 * 枚舉是一個特殊的類
 * class 可以創建n個對象
 * 枚舉類型的對象是固定的
 */
public enum LogType {

    //創建枚舉對象,對象的個數是有限的,對象與對象之間用逗號隔開
    LOGIN(1),DELETE(2),UPDATE(3),INSERT(4);
    //可以定義任意的方法和屬性,與普通類類似
    private final int type;

    //構造方法
    LogType(int type) {
        this.type = type;
    }

    public int getType() {
        return type;
    }

}

2)日志的注解也需要改變為枚舉類型的,在LogData.java文件中;

/**
 * 自定義注解
 */
@Target({ElementType.METHOD,ElementType.FIELD})//指定作用的目標對象(可以添加的位置)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogData {
    //定義注解中的屬性
    String description() default "";
    //日志類型 1、登錄  2、刪除  3、修改  4、插入
 LogType logType();
}

3)調用日志對象,在控制層中;

    @LogData(logType = LogType.DELETE,description = "學生信息刪除")
    @RequestMapping("/delete")
    public String delete(Integer id){
        studentService.delete(id);
        return "redirect:list";
    }
    @LogData(logType = LogType.UPDATE,description = "學生信息修改")
    @RequestMapping("/update2")
    public String update2(Integer id,ModelMap modelMap){
        Student student = studentService.selectById(id);
        modelMap.put("student",student);
        return "update.jsp";
    }
    @LogData(logType = LogType.INSERT,description = "學生信息新增")
    @RequestMapping("/insert")
    public String insert(Student student){
        studentService.insert(student);
        return "redirect:list";
    }

4)寫LogAspect.java文件;

@Component//對象由spring管理
@Aspect//切面注解
public class LogAspect {
    private static final Logger LOGGER = LogManager.getLogger(LogAspect.class);

    //定義切入點,切入到添加了LogData注解的方法上
    @Pointcut("@annotation(aop.LogData)")
    public void pointCut(){

    }

    /**
     * 記錄日志的切面方法
     * 在該方法中定義統一的日志記錄邏輯
     * @param joinPoint
     */
    @Before("pointCut()")
    public void log(JoinPoint joinPoint){
        System.out.println("進入日志Aspect");
        //獲取到方法簽名
        MethodSignature signature= (MethodSignature) joinPoint.getSignature();
        //獲取到連接點方法對象
        Method method=signature.getMethod();
        //獲取方法上面特定的注解
        LogData annotation=method.getAnnotation(LogData.class);
        LogType logType=annotation.logType();
        String description=annotation.description();
        LOGGER.info("獲取到注解內容:logType="+logType.getType()
                +",description:"+description);
        //aop中獲取request
        ServletRequestAttributes requestAttributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request=requestAttributes.getRequest();
        HttpSession session=request.getSession();
        //獲取操作人
        Student student= (Student) session.getAttribute("student");
        //獲取請求數據
        Map<String,String[]> parameterMap=request.getParameterMap();
        //將對象轉換成json字符串==>存儲到請求數據字段中
        //jackSon json字符串操作
        ObjectMapper objectMapper=new ObjectMapper();
        try {
            String s=objectMapper.writeValueAsString(parameterMap);
            LOGGER.info("請求數據:"+s);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        //todo 將日志信息保存到數據庫  LogController service mapper jsp
    }
}

三、枚舉

枚舉可用於switch語句中

public class T {

    public static void main(String[] args) {
        test(LogType.DELETE);
        //獲取到枚舉對象
        LogType logType = LogType.DELETE;
        //獲取到對象之后,與普通對象操作方式一樣
        int type = logType.getType();
    }

    /**
     * 枚舉類型在switch中的使用
     * @param logType
     */
    public static void test(LogType logType) {
        switch (logType){
            case LOGIN:
                System.out.println("登錄操作");break;
            case DELETE:
                System.out.println("刪除操作");break;
            case INSERT:
                System.out.println("插入操作");break;
            case UPDATE:
                System.out.println("修改操作");break;
        }
    }
}

四、枚舉還是實現單例模式的最佳方式

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM