• Jeecg中通过Spring_AOP+注解方式实现日志的管理


    转载;https://blog.csdn.net/ma451152002/article/details/77234236
    Jeecg中通过Spring_AOP+注解方式实现日志的管理
    
    一、设计思路
    
    通过spring的aop切面功能,拦截到请求的所有的符合切面表达式的方法,判断是否含有注解标志,生成日志对象,然后通过aop的后置通知进行日志的持久化。
    
    二、代码实现
    
        1、工程结构:
        
    
    2、pom.xml增加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> 
    
    
    
    3、定义我们的Log实体对象
    package aop;
     
    import java.util.Date;
     
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.persistence.Table;
     
    import org.hibernate.annotations.DynamicInsert;
    import org.hibernate.annotations.DynamicUpdate;
    import org.hibernate.annotations.GenericGenerator;
    import org.jeecgframework.core.common.entity.IdEntity;
     
    @Entity
    @Table(name="assess_log_test")
    @DynamicInsert(true)
    @DynamicUpdate(true)
    @SuppressWarnings("serial")
    public class Log  implements java.io.Serializable{
        /**
         * 日志id
         */
        private String 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;
     
        @Id
        @GeneratedValue(generator = "paymentableGenerator")
        @GenericGenerator(name="paymentableGenerator",strategy="uuid")
        @Column(name="id",nullable=false,length=32)
        public String getId() {
            return id;
        }
        @Column(name="login_account",length=32)
        public String getLoginAccount() {
            return loginAccount;
        }
        @Column(name="login_ip",length=32)
        public String getLoginIp() {
            return loginIp;
        }
        @Column(name="action_url",length=100)
        public String getActionUrl() {
            return actionUrl;
        }
        @Column(name="module",length=32)
        public String getModule() {
            return module;
        }
        @Column(name="method",length=32)
        public String getMethod() {
            return method;
        }
        @Column(name="action_time")
        public Long getActionTime() {
            return actionTime;
        }
        @Column(name="description",length=200)
        public String getDescription() {
            return description;
        }
        @Column(name="gmt_create")
        public Date getGmtCreate() {
            return gmtCreate;
        }
        @Column(name="state")
        public Short getState() {
            return state;
        }
     
        public void setId(String id) {
            this.id = id;
        }
     
        public void setLoginAccount(String loginAccount) {
            this.loginAccount = loginAccount;
        }
     
        public void setLoginIp(String loginIp) {
            this.loginIp = loginIp;
        }
     
        public void setActionUrl(String actionUrl) {
            this.actionUrl = actionUrl;
        }
     
        public void setModule(String module) {
            this.module = module;
        }
     
        public void setMethod(String method) {
            this.method = method;
        }
     
        public void setActionTime(Long actionTime) {
            this.actionTime = actionTime;
        }
     
        public void setDescription(String description) {
            this.description = description;
        }
     
        public void setGmtCreate(Date gmtCreate) {
            this.gmtCreate = gmtCreate;
        }
     
        public void setState(Short state) {
            this.state = state;
        }
     
        @Override
        public String toString() {
            return "Log [id=" + id + ", loginAccount=" + loginAccount
                    + ", loginIp=" + loginIp + ", actionUrl=" + actionUrl
                    + ", module=" + module + ", method=" + method + ", actionTime="
                    + actionTime + ", description=" + description + ", gmtCreate="
                    + gmtCreate + ", state=" + state + "]";
        }
        
        
     
    }
    
    4.定义注解对象
    package aop;
     
    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;
     
    /**
     * 日志记录
     *  
     *  @author mgj 
     *    @date 2017-8-11 上午10:53:19
     */
    @Target({ElementType.PARAMETER,ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface SystemLog {
        String module() default "";
        String methods() default "";
    }
    5.定义aop界面拦截方法
     package aop;
     
    import java.lang.reflect.Method;
    import java.util.Date;
    import javax.servlet.http.HttpServletRequest;
     
    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.MethodSignature;
    import org.jeecgframework.core.util.ResourceUtil;
    import org.jeecgframework.core.util.StringUtil;
    import org.jeecgframework.web.system.pojo.base.TSUser;
    import org.jeecgframework.web.system.service.SystemService;
    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 antlr.StringUtils;
     
    @Component
    @Aspect
    public class LogAopAction {
        private long BEGIN_TIME;
        private long END_TIME;
        private Log log = new Log();
        @Autowired
        private SystemService  systemService;
        
     
        //@Pointcut("execution(* vote.backmanage.teachermanage.controller.AssessTeacherInfoController.*(..))")
        //@Pointcut("execution(* vote.backmanage.teachermanage.controller.*.*(..))")
        //@Pointcut("execution(* vote.backmanage.teachermanage.controller..*.*(..))")
        @Pointcut("execution(* vote.backmanage.teachermanage.controller..*.*(..))")
        public  void controllerAspect(){}
        
        @Before("controllerAspect()")
        public  void doBefore(){
            BEGIN_TIME = new Date().getTime();
        }
        
        @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("存入到数据库");
                systemService.save(log);
                
            }else {
                System.out.println(log);
                System.out.println("不存到数据库里");
            }
        }
        @After("controllerAspect()")
        public  void after(){
            END_TIME = new Date().getTime();
        }
     
        @Around("controllerAspect()")
        public Object around(ProceedingJoinPoint pjp) throws Throwable{
            HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes())
                                            .getRequest();
            //获得当前用户
            TSUser user = ResourceUtil.getSessionUserName();
            String name = user.getRealName();
            log.setLoginAccount(name);
            
            //拦截的实体类
            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 (Exception e) {
                e.printStackTrace();
            }
            
            if (null != method) {
                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 (Exception e) {
                        log.setDescription("执行失败");
                        log.setState((short)-1);
                        e.printStackTrace();
                    }
                    
                }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
         *  @author mgj 
         *    @date 2017-8-11 下午2:19:51
         */
        private String getIp(HttpServletRequest request){
            if (request.getHeader("x-forwarded-for") == null) {
                return request.getRemoteAddr();
            }
            return request.getHeader("x-forwarded-for");
        }
        
    }
    
    
    6.增加aop自动扫描配置
    
    (1)打开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  ">
    2)增加aop自动扫描并实例化bean
     <aop:aspectj-autoproxy proxy-target-class="true" />
    <bean id="logAopAction" class="aop.LogAopAction"></bean>
    
    7.持久化Log实体的xml配置,使用自动扫描class的形式进行配置。打开spring-mvc-hibernate.xml文件,增加<value>aop.</value>
    <bean id="sessionFactory"
            class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <property name="entityInterceptor" ref="hiberAspect" />
            <property name="hibernateProperties">
                <props>
                    <!--<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop> -->
                    <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                    <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
                    <prop key="hibernate.show_sql">true</prop>
                    <prop key="hibernate.format_sql">false</prop>
                    <prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
                </props>
            </property>
            <!-- 注解方式配置 -->
            <property name="packagesToScan">
                <list>
                    <value>org.jeecgframework.web.system.pojo.*</value>
                    <value>org.jeecgframework.web.demo.entity.*</value>
                    <value>org.jeecgframework.web.test.entity.*</value>
                    <value>org.jeecgframework.web.cgform.entity.*</value>
                    <value>org.jeecgframework.web.cgreport.entity.*</value>
                    <value>aop.</value>
                </list>
            </property>
    </bean>
    
    8.使用注解方式,配置日志,在访问的controller方法上,增加@SystemLog(module="区教师库登录",methods="区教师库的assessTeacherInfo()方法")配置
        /**
         * 教师库管理列表 页面跳转
         * 
         * @return
         */
        @RequestMapping(params = "assessTeacherInfo")
        @SystemLog(module="区教师库登录",methods="区教师库的assessTeacherInfo()方法")
        public ModelAndView assessTeacherInfo(HttpServletRequest request) {        
            return new ModelAndView("vote/backmanage/teachermanage/assessTeacherInfoList");
        }
    
    9.效果
    
    
    
    三、注意事项
             1.增加aop自动扫描包时,必须写到spring-mvc.xml内,不可写到spring-mvc-aop.xml文件中。因为spring-mvc.xml会比spring-mvc-aop.xml文先执行。
             2.持久化Log实体,使用自动扫描class的形式进行配置时,规则如下
    (1)<value>aop.</value>,会解析为aop/*.class 或者 aop/xxx/*.class。即aop的包以及子包下的所有class。
                (2)<value>aop</value>,会解析为aop/*.class 。即aop的包下的所有class。
                (3)<value>aop.*</value>,会解析为 aop/xxx/*.class。即aop的子包下的所有class。
    
    四、思考
    1.需要深刻理解spring_mvc.xml文件的执行顺序。
    2.需要深刻理解使用自动扫描class的形式的配置规则。
    
    
    ---------------------------------------------------------------------------
    
    附录:
    
    Log实体创建的mysql脚本:
    
    drop table if exists assess_log_test;
     
    create table  assess_log_test (
        id varchar(32) not null COMMENT '主键id',
        login_account varchar(32) default null comment '当前操作人',
        login_ip varchar(32) default null comment '登录ip',
        action_url varchar(100) default null comment '请求url',
        module varchar(32) default null comment '执行模块',
        method varchar(32) default null comment '执行方法',
        action_time bigint default 0 comment '执行操作时间',
        description varchar(200)    default null comment '描述',
        gmt_create  datetime default null comment '执行时间',
        state smallint(6) default null comment '操作状态',
      primary key (id)
    )engine=innodb default charset=utf8  comment '操作日志表';
  • 相关阅读:
    java实现简单文件操作工具类
    (leetCode)Reverse Integer—颠倒整数
    (FLEX)AS3,for循环里面加监听,只能取到最后一个元素的取巧方法解决方法
    .net backend return json string , used by frontend
    Server Error in '/' Application. 访问Webservice报错。解决办法之一。
    Win7 64位ORACLE取数字乱码的解决
    WIN7-64位安装PLSQL-Developer步骤
    在Win7 64位操作系统下安装Oracle 10g
    HashMap 数据结构分析
    JAVA NIO原理剖析
  • 原文地址:https://www.cnblogs.com/Jeely/p/11310490.html
Copyright © 2020-2023  润新知