• 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;
            }
        }
    }

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

  • 相关阅读:
    算法练习-寻找和为定值的两个数
    算法练习-字符串全排列
    算法练习-最长回文子串
    判断一点是否在三角形的外接圆内
    用递归方法计算行列式的值
    算法练习-回文判断
    算法练习-字符串转换成整数(实现atoi函数)
    算法练习-字符串包含
    数据结构-队列
    结构体(或者联合体)变量的成员在内存里是如何分布的
  • 原文地址:https://www.cnblogs.com/xie-qi/p/13040543.html
Copyright © 2020-2023  润新知