zoukankan      html  css  js  c++  java
  • Spring MVC通过AOP切面编程 来拦截controller 实现日志的写入

    首选需要参考的是:【参考】http://www.cnblogs.com/guokai870510826/p/5977948.html

                   http://www.cnblogs.com/guokai870510826/p/5981015.html

    1:首先定义maven

      <!--配置aop切面编程需要引入的包-->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aop</artifactId>
          <version>4.1.7.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>aspectj</groupId>
          <artifactId>aspectjrt</artifactId>
          <version>1.5.3</version>
        </dependency>
        <dependency>
          <groupId>org.aspectj</groupId>
          <artifactId>aspectjweaver</artifactId>
          <version>1.8.4</version>
        </dependency>
        <dependency>
          <groupId>aopalliance</groupId>
          <artifactId>aopalliance</artifactId>
          <version>1.0</version>
        </dependency>
        <dependency>
          <groupId>cglib</groupId>
          <artifactId>cglib</artifactId>
          <version>3.2.4</version>
        </dependency>

    2:在拦截controller之前 需要自定义一个注解

    package com.cdms.aop;
    
    import java.lang.annotation.*;
    
    /**
     * Created by 草帽boy on 2017/2/21.
     */
    
    @Target({ElementType.PARAMETER, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface SystemLog {
        String module()  default "";
        String methods()  default "";
    }

    其目的是 如图:

    三:配置spring-web.xml

      <!--Aop切面编程的配置-->
        <aop:aspectj-autoproxy expose-proxy="true"></aop:aspectj-autoproxy>
        <bean id="logAopAction" class="com.cdms.aop.LogAopAction"></bean>

    四:aop的实现类中处理记录日志的逻辑

    package com.cdms.aop;
    
    import com.cdms.dto.User;
    import com.cdms.entity.Log;
    import com.cdms.util.SessionUtil;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.Signature;
    import org.aspectj.lang.annotation.*;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    import java.lang.reflect.Method;
    
    import javax.servlet.http.HttpServletRequest;
    import java.util.Date;
    
    /**
     * Created by 草帽boy on 2017/2/21.
     */
    @Aspect
    public class LogAopAction {
        //获取开始时间
        private long BEGIN_TIME ;
    
        //获取结束时间
        private long END_TIME;
    
        //定义本次log实体
        private Log log = new Log();
    
        @Pointcut("execution(* com.cdms.controller..*.*(..))")
        private void controllerAspect(){}
    
        /**
         * 方法开始执行
         */
        @Before("controllerAspect()")
        public void doBefore(){
            BEGIN_TIME = new Date().getTime();
            System.out.println("开始");
        }
    
        /**
         * 方法结束执行
         */
        @After("controllerAspect()")
        public void after(){
            END_TIME = new Date().getTime();
            System.out.println("结束");
        }
    
        /**
         * 方法结束执行后的操作
         */
        @AfterReturning("controllerAspect()")
        public void doAfter(){
    
            if(log.getState()==1||log.getState()==-1){
                log.setActionTime(END_TIME-BEGIN_TIME);
                log.setGmtCreate(new Date(BEGIN_TIME));
                System.out.println(log);
                System.out.println(">>>>>>>>>>存入到数据库");
            }else {
                System.out.println(log);
                System.out.println(">>>>>>>>不存入到数据库");
            }
        }
    
        /**
         * 方法有异常时的操作
         */
        @AfterThrowing("controllerAspect()")
        public void doAfterThrow(){
            System.out.println("例外通知-----------------------------------");
        }
    
    
        /**
         * 方法执行
         * @param pjp
         * @return
         * @throws Throwable
         */
        @Around("controllerAspect()")
        public Object around(ProceedingJoinPoint pjp) throws Throwable{
            //日志实体对象
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            //获取当前登陆用户信息
            User loginUser = SessionUtil.getLoginSession(request);
            if(loginUser==null){
                log.setLoginAccount("—— ——");
            }else{
                log.setLoginAccount(loginUser.getUserAuth().getIdentity());
            }
    
            // 拦截的实体类,就是当前正在执行的controller
            Object target = pjp.getTarget();
            // 拦截的方法名称。当前正在执行的方法
            String methodName = pjp.getSignature().getName();
            // 拦截的方法参数
            Object[] args = pjp.getArgs();
            // 拦截的放参数类型
            Signature sig = pjp.getSignature();
            MethodSignature msig = null;
            if (!(sig instanceof MethodSignature)) {
                throw new IllegalArgumentException("该注解只能用于方法");
            }
            msig = (MethodSignature) sig;
            Class[] parameterTypes = msig.getMethod().getParameterTypes();
    
            Object object = null;
    
            Method method = null;
            try {
                method = target.getClass().getMethod(methodName, parameterTypes);
            } catch (NoSuchMethodException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            } catch (SecurityException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
    
            if (null != method) {
                // 判断是否包含自定义的注解,说明一下这里的SystemLog就是我自己自定义的注解
                if (method.isAnnotationPresent(SystemLog.class)) {
                    SystemLog systemlog = method.getAnnotation(SystemLog.class);
                    log.setModule(systemlog.module());
                    log.setMethod(systemlog.methods());
                    log.setLoginIp(getIp(request));
                    log.setActionUrl(request.getRequestURI());
    
                    try {
                        object = pjp.proceed();
                        log.setDescription("执行成功");
                        log.setState((short) 1);
                    } catch (Throwable e) {
                        // TODO Auto-generated catch block
                        log.setDescription("执行失败");
                        log.setState((short)-1);
                    }
                } else {//没有包含注解
                    object = pjp.proceed();
                    log.setDescription("此操作不包含注解");
                    log.setState((short)0);
                }
            } else { //不需要拦截直接执行
                object = pjp.proceed();
                log.setDescription("不需要拦截直接执行");
                log.setState((short)0);
            }
            return object;
        }
    
        /**
         * 获取ip地址
         * @param request
         * @return
         */
        private String getIp(HttpServletRequest request){
            if (request.getHeader("x-forwarded-for") == null) {
                return request.getRemoteAddr();
            }
            return request.getHeader("x-forwarded-for");
        }
    }

     其中我的Log实体类如下图所示

    /**
         * 日志id
         */
        private Integer id;
    
        /**
         * 当前操作人id
         */
        private String loginAccount;
    
        /**
         * 当前操作人ip
         */
        private String loginIp;
    
        /**
         * 操作请求的链接
         */
        private String actionUrl;
    
        /**
         * 执行的模块
         */
        private String module;
    
        /**
         * 执行的方法
         */
        private String method;
    
        /**
         * 执行操作时间
         */
        private Long actionTime;
    
        /**
         * 描述
         */
        private String description;
    
        /**
         * 执行的时间
         */
        private Date gmtCreate;
    
        /**
         * 该操作状态,1表示成功,-1表示失败!
         */
        private Short state;

    四:我们在看一下 controller中的注解怎么写

        /**
         * 登陆消息验证
         * @param userAuth 用户登陆信息
         * @param request http协议请求
         * @return 一个带参数的json数据
         */
        @RequestMapping(value = "/toLogin",method = RequestMethod.POST,
                produces = {"application/json;charset=UTF-8"})
        @ResponseBody
        @SystemLog(methods = "用户管理",module = "用户登陆")
        public JSONObject toLogin(UserAuth userAuth, HttpServletRequest request){
            JSONObject loginJson = userService.userLogin(userAuth);
            //表示登陆成功
            if(loginJson.get("key").equals("success")){
                //放入到session中
                SessionUtil.setLoginSession(request,loginJson.get("data"));
                return JSONOperation.successMessage("登陆成功!");
            }
            return loginJson;
        }

    在控制台的打印结果是:

    开始
    结束
    Log{id=null, loginAccount='919132691@qq.com', loginIp='127.0.0.1', actionUrl='/user/toLogin', module='用户登陆', method='用户管理', actionTime=0, description='执行成功', gmtCreate=Tue Feb 21 18:56:15 CST 2017, state=1}
    >>>>>>>>>>存入到数据库
  • 相关阅读:
    《面向模式的软件体系结构1模式系统》读书笔记(7) 通信
    《面向模式的软件体系结构2用于并发和网络化对象模式》读书笔记(5) 截取器
    Enum variable is used in switch sentencejava Anny
    How to create a dynamic range source(转) Anny
    Managing Range Names in Excel 2010(转) Anny
    Mixed Content Handling Issue on IE7/8 Anny
    How to resolve "skip non existing resourceDirectory" when using "mvn test" Anny
    Install chinese input method in Ubuntu12.04 Anny
    IDL(International Date Line) Anny
    Web Accessibility508(转) Anny
  • 原文地址:https://www.cnblogs.com/luffyu/p/6425694.html
Copyright © 2011-2022 走看看