AOP实现日志记录功能

Posted xie-qi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
        }
    }
}

四、枚举还是实现单例模式的最佳方式

 

以上是关于AOP实现日志记录功能的主要内容,如果未能解决你的问题,请参考以下文章

Spring AOP 实现日志记录功能

我使用Spring AOP实现了用户操作日志功能

Spring Boot 中使用Spring Aop实现日志记录功能

我使用Spring AOP实现了用户操作日志功能

SpringAOP+注解实现简单的日志管理

JAVA之AOP