HandlerInterceptor记录系统日志

作者: 编程界的小学生 | 来源:发表于2017-04-06 16:25 被阅读960次

    需求:
    记录系统日志,要求字段有:一级菜单名,二级菜单名,进行了什么操作

    实现方式:
    两个注解:

    package com.bshf.recipe.demo.syslog;
    
    import java.lang.annotation.*;
    
    
    /**
     * <p>用于记录系统操作日志的注解 -- 类注解 </p>
     * <p>在需要记录系统操作日志的Controller上添加该注解</p>
     *
     */
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface CategoryLog {
    
        /**
         * 一级菜单名
         */
        String menu1();
    
        /**
         * 二级菜单名
         */
        String menu2();
    
    }
    
    package com.bshf.recipe.demo.syslog;
    
    import java.lang.annotation.*;
    
    
    /**
     * <p>用于记录系统操作日志的注解 -- 方法注解</p>
     * <p>在需要记录系统操作日志的Controller中待记录系统操作日志的方法上添加该注解。</p>
     *
     */
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface DescLog {
    
        /**
         * 操作名称
         */
        String value();
    
    }
    

    注解处理器:

    package com.bshf.recipe.demo.syslog;
    
    
    import java.lang.reflect.Method;
    
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class SyslogInterceptor extends HandlerInterceptorAdapter {
    
        /**
         * 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
         */
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                ModelAndView modelAndView) throws Exception {
            
            if(! (handler instanceof HandlerMethod)) {
                return ;
            }
            
            HandlerMethod method = (HandlerMethod)handler;
            Class<? extends Object> controller = method.getBean().getClass();
            //获取类上的CategoryLog注解
            CategoryLog annotation = controller.getAnnotation(CategoryLog.class);
            //若类上没注解,则不记录日志
            if(null == annotation) {
                return ;
            }
            String menu1 = annotation.menu1();
            String menu2 = annotation.menu2();
            
            Method anyMethod = method.getMethod();
            //获取所有方法上的DescLog注解
            DescLog methodLog = anyMethod.getAnnotation(DescLog.class);
            
            if (null == methodLog) {
                return ;
            }
    
            String value = methodLog.value();
            
            //真正开始记录日志的代码。
    //      SysLog sysLog = new SysLog();
    //      sysLog.setXXX();
    //      sysLogService.save(sysLog);
            
        }
    }
    

    配置文件:

    <mvc:interceptors>
            <mvc:interceptor>
                <mvc:mapping path="/**"/>
                <bean class="com.bshf.recipe.demo.syslog.SyslogInterceptor" />
            </mvc:interceptor>
    </mvc:interceptors>
    

    Demo测试:

    package controller;
    
    import annotation.CategoryLog;
    import annotation.DescLog;
    
    /**
     * @author 15620646321@163.com
     * @date 2017年4月6日
     */
    @CategoryLog(firstMenu = "基本信息", secondMenu = "用户")
    @Controller
    @RequestMapping("/demo")
    public class DemoController {
    
        @DescLog("HelloWorld登陆了")
        @RequestMapping("/test")
        public void test() {
            System.out.println("HelloWorld!");
        }
    }
    

    程序运行流程:
    当调用test接口时,会首先会进入拦截器的preHandle方法,由于继承的HandlerInterceptorAdapter,而HandlerInterceptorAdapter 中的preHandle方法默认为true,所以进行test方法的业务逻辑,当走完逻辑(这时候只是走完了逻辑,页面并没有渲染数据),会调用postHandle方法进行记录日志,postHandle方法拿到注解上的值,就可以知道谁对某个模块操作了什么。当走完postHandle后,会调用HandlerInterceptorAdapter的afterCompletion(页面渲染完数据后会执行此方法)方法进行清理工作。

    问:为什么不在afterCompletion方法进行日志记录?
    答:因为如果我有多个拦截器或者就这一个,只要遇到preHandle方法返回false的,test主逻辑方法就不会在执行,就只会执行preHandle和afterCompletion方法,test主逻辑和postHandle方法都不会执行。这样就会产生我本来没有操作成功,return false了,但是还是给我记录了一条日志。而postHandle方法只要你程序抛出异常了或者preHandle返回false了,就不会执行,这样就不会记录系统日志。想要记录异常日志,可以配合logback+aop。

    如对HandlerInterceptor不懂的请看我的这篇文章:http://www.jianshu.com/p/1e8d088c2be9

    若有兴趣,欢迎来加入群,【Java初学者学习交流群】:458430385,此群有Java开发人员、UI设计人员和前端工程师。有问必答,共同探讨学习,一起进步!
    欢迎关注我的微信公众号【Java码农社区】,会定时推送各种干货:


    qrcode_for_gh_577b64e73701_258.jpg

    相关文章

      网友评论

        本文标题:HandlerInterceptor记录系统日志

        本文链接:https://www.haomeiwen.com/subject/jbsqattx.html