zoukankan      html  css  js  c++  java
  • jeecg系统日志管理

    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 '操作日志表';

    转自:https://blog.csdn.net/ma451152002/article/details/77234236

  • 相关阅读:
    easyui tree loader用法
    mysql字符集
    mysql 内连接 左连接 右连接 外连接
    mysql 聚集函数和分组
    mysql 大数据量求平均值
    C++ 纯虚方法
    Windows xcopy
    服务端数据库的操作如何不阻塞
    分布式系统业务服务器的设计
    mysql 查询执行的流程
  • 原文地址:https://www.cnblogs.com/ybal/p/10417124.html
Copyright © 2011-2022 走看看