美文网首页我爱编程
利用spring切面编程特性 实现监控controller操作

利用spring切面编程特性 实现监控controller操作

作者: 人形大叔 | 来源:发表于2018-04-04 11:40 被阅读0次

    利用spring切面编程特性 实现监控controller操作,利用反射自动拿到方法参数以及返回值的名,类型以及值,记录持久化

    框架:JEECG JDK:1.8

    1. 首先第一步建立一个自定义annotation SystemLog

    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /***
     * 
     * 
     * Title: SystemLog<br/>
     * 
     * Description: 日志记录<br/>
     * 
     * @author 王维杰
     * 
     * @date 2018年4月2日
     */
    @Target({ ElementType.PARAMETER, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface SystemLog {
    
        /***
         * 
         * @Title: methodsDescription
         * @Description: 方法描述
         * @return String 返回类型
         * @throws
         */
        String methodsDescription() default "";
    }
    

    2. 书写拦截类 LogAopAction

    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.apache.log4j.Logger;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.Signature;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.CodeSignature;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.jeecgframework.core.util.ResourceUtil;
    import org.jeecgframework.core.util.aoplog.annotation.SystemLog;
    import org.jeecgframework.core.util.aoplog.entity.LogEntity;
    import org.jeecgframework.core.util.aoplog.service.AopLogServiceI;
    import org.jeecgframework.web.system.pojo.base.TSUser;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import com.alibaba.fastjson.JSON;
    
    /***
     * 
     * @ClassName: LogAopAction
     * @Description: aop日志工具类
     * @author 王维杰
     * @date 2018年4月3日  
     *
     */
    @Component
    @Aspect
    public class LogAopAction {
        private static final Logger logger = Logger.getLogger(LogAopAction.class);
        private long BEGIN_TIME;
        private long END_TIME;
        private LogEntity log = new LogEntity();
        @Autowired
        public AopLogServiceI logService;
    
        /**
         * Service层切点
         *
         * Ponintuct里面有spring的表达式,可以去百度   我写的意思是对所有带有类路径所指示的注解的方法生效
         */
        @Pointcut("@annotation(org.jeecgframework.core.util.aoplog.annotation.SystemLog)")
        public void logAspect() {
        }
    
        /**
         * 
         * @Title: around
         * @Description: 构造log实体
         * @param pjp
         * @return
         * @throws Throwable
         *             Object 返回类型   Around是对哪个切点生效
         * @throws
         */
        @Around("logAspect()")
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    
            TSUser user = ResourceUtil.getSessionUser();
            log.setUserId(user.getId().toString());
            // 当前用户姓名
            log.setLoginAccount(user.getUserName());
            // 设置参数列表
            log.setParamList(this.getparamList(pjp));
            // 方法描述
            log.setMethodsDescrip(this.getMethodsDescription(pjp));
            // 访问人ip
            log.setLoginIp(this.getIp(request));
            // 访问连接
            log.setActionUrl(request.getRequestURI());
    
            Object object = null;
            try {
                object = pjp.proceed();
                log.setDescription("执行成功");
                log.setState(1);
            } catch (Exception e) {
                log.setDescription("执行失败");
                log.setState(-1);
                e.printStackTrace();
            }
    
            return object;
        }
    
        /***
         * 
         * @Title: doBefore
         * @Description: 执行开始时间 void 返回类型
         * @throws
         */
        @Before("logAspect()")
        public void doBefore() {
            BEGIN_TIME = new Date().getTime();
        }
    
        /***
         * 
         * @Title: after
         * @Description: 执行结束时间 void 返回类型
         * @throws
         */
        @After("logAspect()")
        public void after() {
            END_TIME = new Date().getTime();
        }
    
        /***
         * 
         * 
         * Title: doAfter<br/>
         * 
         * Description: 逻辑执行完 保存数据库<br/>
         */
        @AfterReturning(value = "logAspect()", returning = "result")
        public void doAfter(JoinPoint joinPoint, Object result) {
            String methodName = joinPoint.getSignature().getName();
            // 设置方法名
            log.setMethods(methodName);
            // 返回值
            log.setResult(JSON.toJSONString(result));
            // 算出执行时间
            log.setActionTime(new Date(END_TIME - BEGIN_TIME));
            // 设置开始时间
            log.setGmtcreate(new Date(BEGIN_TIME));
    
            // 存入数据库
            try {
                logger.info(log);
                logService.save(log);
            } catch (Exception e) {
                logger.error("日志存入失败=====>" + e.getStackTrace());
            }
    
        }
        /*************工具方法开始****************
         * 
         * @Title: getparamList
         * @Description: 获取参数列表
         * @param pjp
         * @return String 返回类型
         * @throws
         */
        private String getparamList(ProceedingJoinPoint pjp) {
            Object[] paramValues = pjp.getArgs();
            String[] paramNames = ((CodeSignature) pjp.getSignature())
                    .getParameterNames();
    
            List<Map<String, Object>> map_list = new ArrayList<Map<String, Object>>();
    
            Map<String, Object> paramMap = null;
    
            for (int i = 0; i < paramNames.length; i++) {
                paramMap = new HashMap<String, Object>();
                paramMap.put("paramNames", paramNames[i]);
                if (paramValues[i] == null) {
                    paramMap.put("paramValues", "NULL");
                } else {
                    paramMap.put("paramValues", getFiledsInfo(paramValues[i]));
                }
                map_list.add(paramMap);
            }
            return JSON.toJSONString(map_list);
        }
    
        /***
         * 
         * @Title: getFieldValueByName
         * @Description: 根据属性名获取属性值
         * @param fieldName
         * @param o
         * @return Object 返回类型
         * @throws
         */
        private Object getFieldValueByName(String fieldName, Object o) {
            try {
                String firstLetter = fieldName.substring(0, 1).toUpperCase();
                String getter = "get" + firstLetter + fieldName.substring(1);
                Method method = o.getClass().getMethod(getter, new Class[] {});
                Object value = method.invoke(o, new Object[] {});
                return value;
            } catch (Exception e) {
                return e.getMessage();
            }
        }
    
        /***
         * 
         * @Title: getFiledsInfo
         * @Description: 获取属性类型(type),属性名(name),属性值(value)的map组成的list
         * @param o
         * @return List<Map<String,Object>> 返回类型
         * @throws
         */
        private List<Map<String, Object>> getFiledsInfo(Object o) {
            Field[] fields = o.getClass().getDeclaredFields();
            List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
            Map<String, Object> infoMap = null;
            for (int i = 0; i < fields.length; i++) {
                Object value = getFieldValueByName(fields[i].getName(), o);
                if (value != null) {
                    infoMap = new HashMap<String, Object>();
                    infoMap.put("type", fields[i].getType().toString());
                    infoMap.put("name", fields[i].getName());
                    infoMap.put("value", value);
                    list.add(infoMap);
                }
            }
            return list;
        }
    
        /***
         * 
         * 
         * Title: getIp<br/>
         * 
         * Description: 获得ip地址<br/>
         * 
         * @param request
         * @return
         */
        private String getIp(HttpServletRequest request) {
            if (request.getHeader("x-forwarded-for") == null) {
                return request.getRemoteAddr();
            }
            return request.getHeader("x-forwarded-for");
        }
    
        /**
         * 
         * @Title: getMethodsDescription
         * @Description: 获取方法描述
         * @param pjp
         * @return String 返回类型
         * @throws
         */
        private String getMethodsDescription(ProceedingJoinPoint pjp) {
            // 拦截的实体类
            Object target = pjp.getTarget();
    
            // 拦截的方法名
            String methodName = pjp.getSignature().getName();
            // 拦截的放参数类型
            Signature sig = pjp.getSignature();
            MethodSignature msig = null;
            if (!(sig instanceof MethodSignature)) {
                throw new IllegalArgumentException("该注解只能用于方法");
            }
            msig = (MethodSignature) sig;
            Class<?>[] parameterTypes = msig.getMethod().getParameterTypes();
    
            Method method = null;
            try {
                method = target.getClass().getMethod(methodName, parameterTypes);
            } catch (Exception e) {
                e.printStackTrace();
            }
            SystemLog systemlog = method.getAnnotation(SystemLog.class);
            return systemlog.methodsDescription();
        }
    
    }
    

    3. 给出log实体LogEntity 我这边是使用JEECG框架根据数据库表生成的实体 具体的get set方法就不再赘述

    
     
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue; 
    import javax.persistence.Id;
    import javax.persistence.Table;
    import org.hibernate.annotations.GenericGenerator;
    import org.jeecgframework.poi.excel.annotation.Excel;
    
    
    /**
     * 
    * @ClassName: LogEntity 
    * @Description: 
    * @author 王维杰
    * @date 2018年4月3日
    *
     */
    public class LogEntity{
        /** 日志id */
        private java.lang.String id;
        /** 操作用户id */
        private java.lang.String userId;
        /** 操作用户名 */
        private java.lang.String loginAccount;
        /** 操作人ip */
        private java.lang.String loginIp;
        /** 操作请求的链接 */
        private java.lang.String actionUrl;
        /** 方法描述 */
        private java.lang.String methodsDescrip;
        /** 方法名 */
        private java.lang.String methods;
        /** 返回值 */
        private java.lang.String result;
        /** actionTime */
        private java.util.Date actionTime;
        /** 本次执行描述 */
        private java.lang.String description;
        /** 本次执行时间 */
        private java.util.Date gmtcreate;
        /** 该操作状态,1表示成功,-1表示失败! */
        private java.lang.Integer state;
        /** 不为空的参数列表 */
        private java.lang.String paramList;
        /** 操作级别 */
        private java.lang.Integer operationLevel;
        /** 本条记录创建时间 */
        private java.util.Date careatTime;
    

    3. 修改配置文件spring-mvc.xml以及spring-mvc-hibernate.xmlJEECG框架知道日志系统的位置

    spring-mvc.xml文件,增加aop上下文 仔细看看有没漏下的

    <?xml version="1.0" encoding="UTF-8"?>  
    <beans xmlns="http://www.springframework.org/schema/beans"  
        xmlns:mvc="http://www.springframework.org/schema/mvc"   
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
        xmlns:p="http://www.springframework.org/schema/p"   
        xmlns:context="http://www.springframework.org/schema/context"  
        xmlns:aop="http://www.springframework.org/schema/aop"  
        xsi:schemaLocation="http://www.springframework.org/schema/beans  
          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
           http://www.springframework.org/schema/context  
            http://www.springframework.org/schema/context/spring-context-3.0.xsd  
             http://www.springframework.org/schema/mvc  
            http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd   
            http://www.springframework.org/schema/aop    
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd  ">  
    
        
        <!-- 启用切面注解 -->
        <aop:aspectj-autoproxy proxy-target-class="true" />
        <!-- 增加aop自动扫描并实例化bean -->
        <bean id="logAopAction" class="切面类全路径"></bean>
    

    如果需要持久化,打开spring-mvc-hibernate.xml文件,增加一个<value>持久层包路径</value>

    最后用法 直接在需要记录日志的方法名上 书写:

    @SystemLog(methodsDescription="方法描述")

    搞定

    相关文章

      网友评论

        本文标题:利用spring切面编程特性 实现监控controller操作

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