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

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




猜你喜欢

转载自blog.csdn.net/ma451152002/article/details/77234236