Spring-Aop处理记录日志

AOP的几种通知类型:

1,前置通知(Before advice):在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行
	配置文件中使用 <aop:before>进行声明
	注解使用 @Before 进行声明

2,后置通知(After advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
	配置文件中使用<aop:after>进行声明
	注解使用 @After 进行声明

3,返回后通知(After return advice):在某连接点正常完成后执行的通知,不包括抛出异常的情况。
	配置文件中使用<after-returning>进行声明
	注解使用 @AfterReturning 进行声明

4,环绕通知(Around advice):包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。
  可以在方法的调用前后完成自定义的行为,也可以选择不执行。
	配置文件中使用<aop:around>进行声明
	注解使用 @Around 进行声明
	
5,抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。
	配置文件中使用<aop:after-throwing>进行声明
	注解使用 @AfterThrowing 进行声明

需要先引入相关jar包,
如果用Maven则在pom文件中加入下面配置,此时Maven会自动导入相关jar包

	<!-- 引入AOP所需要的jar包 -->
		<dependency>
		    <groupId>org.aspectj</groupId>
		    <artifactId>aspectjweaver</artifactId>
		    <version>1.7.2</version>
		</dependency>

Spring的applicationContext.xml 文件中的配置

这三个是aop的
xmlns:aop="http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:task="http://www.springframework.org/schema/task"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/aop 
           http://www.springframework.org/schema/aop/spring-aop-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/task
           http://www.springframework.org/schema/task/spring-task-3.0.xsd
           http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
           http://www.springframework.org/schema/util
           http://www.springframework.org/schema/util/spring-util-3.0.xsd">
   
	<!---注解配置开始  如果使用注解配置Aop则需要配置这两个参数 -->
	
	<!-- 激活组件扫描功能,在包cn.ysh.studio.spring.aop及其子包下面自动扫描通过注解配置的组件 -->
	<!--
	<context:component-scan base-package="cn.ysh.studio.spring.aop"/>
	-->
	<!-- 激活自动代理功能 -->
	<!--
	<aop:aspectj-autoproxy proxy-target-class="true"/>
	-->
	<!---注解配置结束 -->
	



	<aop:config>
			<!-- 声明一个切面,并注入切面Bean,相当于@Aspect -->
		  <aop:aspect id="myAop" ref="auditLogAop">
		  	 
		  	 <!--配置一个切点,相当于@Pointcut

			*  表示通配所有类型返回值或则没有返回值都可以
			com.unionpay.techjoin.common.service..*.*(..)
			表示com.unionpay.techjoin.common.service包下所以类  
			(..)表示所有参数类型
			-->
		  	 <aop:pointcut id="myAuditLog" expression="execution(* com.unionpay.techjoin.common.service..*.*(..))" />
		     
		     <!--配置环绕通知 相当于@Around-->
			<aop:around method="addAuditLog" pointcut-ref="myAuditLog"/>
		 </aop:aspect>
	</aop:config>

如果需要通知中获取Request对象,则需要在web.xml中加入如下配置

<listener>
		<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

日志实体类

package com.unionpay.techjoin.common.domain;

import java.io.Serializable;
import java.sql.Timestamp;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * 审计日志实体类
 * @author mszhou
 *
 */
@Entity
@Table(name = "tbl_tjmgm_audit_log")
public class AuditLog implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**主键id*/
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Integer id;
	
	/**类别 01表示产品 02表示解决方案 03表示API 04表示FAQ 05表示文档*/
	@Column(name = "target_type")
	private String targetType;
	
	/**关联id  */
	@Column(name = "target_id")
	private Integer targetId;
	
	/**该操作简单的简单描述 如 “admin修改产品”  */
	@Column(name = "operate_content")
	private String operateContent;
	
	/**操作类别 01表示新增 02表示修改 03表示删除*/
	@Column(name = "operate_type")
	private String operateType;
	
	/**操作人Id*/
	@Column(name = "operator_id")
	private String operatorId;
	
	/** 操作时间 */
	@Column(name = "operate_ts")
	private Timestamp operateTs;
	
	/**操作人的IP*/
	@Column(name = "operator_ip")
	private String operatorIp;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getTargetType() {
		return targetType;
	}

	public void setTargetType(String targetType) {
		this.targetType = targetType;
	}

	public Integer getTargetId() {
		return targetId;
	}

	public void setTargetId(Integer targetId) {
		this.targetId = targetId;
	}

	public String getOperateContent() {
		return operateContent;
	}

	public void setOperateContent(String operateContent) {
		this.operateContent = operateContent;
	}

	public String getOperateType() {
		return operateType;
	}

	public void setOperateType(String operateType) {
		this.operateType = operateType;
	}

	public String getOperatorId() {
		return operatorId;
	}

	public void setOperatorId(String operatorId) {
		this.operatorId = operatorId;
	}

	public Timestamp getOperateTs() {
		return operateTs;
	}

	public void setOperateTs(Timestamp operateTs) {
		this.operateTs = operateTs;
	}

	public String getOperatorIp() {
		return operatorIp;
	}

	public void setOperatorIp(String operatorIp) {
		this.operatorIp = operatorIp;
	}
	
}

日志Dao类

package com.unionpay.techjoin.common.dao;

import java.io.Serializable;
import org.springframework.stereotype.Repository;
import com.unionpay.techjoin.common.domain.AuditLog;
/**
 * 审计日志Dao
 * @author mszhou
 */
@Repository
public class AuditLogDao  extends HibernateBaseDao<AuditLog,Serializable> {

}

日志业务类

package com.unionpay.techjoin.common.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.unionpay.techjoin.common.dao.AuditLogDao;
import com.unionpay.techjoin.common.domain.AuditLog;

@Service
@Transactional
public class AuditLogService {
	
	@Autowired
	private AuditLogDao auditLogDao;
	
	/**
	 * 新增
	 * @param auditLog
	 * @author mszhou
	 */
	public void add(AuditLog auditLog){
		auditLogDao.save(auditLog);
	}
	
}

切面类


package com.unionpay.techjoin.admin.controller;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
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.unionpay.common.authorization.user.UserDetail;
import com.unionpay.techjoin.admin.utils.UserInfoUtil;
import com.unionpay.techjoin.common.domain.AuditLog;
import com.unionpay.techjoin.common.service.AuditLogService;


@Component(value="auditLogAop")//实例化注解 
public class AuditLogAop {
	
	@Autowired
	private AuditLogService auditLogService;
	
	/*
	 *(环绕通知)  -日志切点
	 * 参数 JoinPoint joinPoint
	 * ProceedingJoinPoint是JoinPoint的子类,在环绕通知中用到
	 * 其它通知则直接用JoinPoint类型参数
	 * 
	 * 环绕通知也可以这样写
	 * ((ProceedingJoinPoint) joinPoint).proceed();
	 */
	@SuppressWarnings("finally")
	public Object addAuditLog(ProceedingJoinPoint pjp) throws Throwable{
		
		Object obj=pjp.proceed();//执行方法
		//========生成日志开姿============
		try{
			//得到Request对象
			HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
			if(request!=null){
				//pjp.getTarget().getClass().getName()得到请求的Service类全名(包名.类名)
				//调用方法getTargetType得到类型01表示产品 02表示解决方案 03表示API 04表示FAQ 05表示文档
				String targetType =getTargetType(pjp.getTarget().getClass().getName());
				
				//pjp.getSignature().getName()得到请求的方法名
				//调用getOperateType方法得到操作类型 01表示新增 02表示修改 03表示删除
				String operateType=getOperateType(pjp.getSignature().getName());//方法 
				
				if(targetType!=null&&!"".equals(targetType)&&operateType!=null&&!"".equals(operateType)){
					
					//获取当前用户,这里调用了UserInfoUtil工具类
					UserDetail user= UserInfoUtil.getUserInfo(request);
					AuditLog auditLog=new AuditLog();//创建审计日志对象
					auditLog.setTargetType(targetType);//设置请求类别
					
					//设置关联Id,这里调用了下面getpArgs方法得到id
					auditLog.setTargetId(getpArgs(pjp,operateType));
					
					//设置简单操作描述,这里调用了下面getOperateContent方法获得							
			  auditLog.setOperateContent(getOperateContent(user.getUserId(),targetType,operateType));
					
					auditLog.setOperateType(operateType);//设置操作类别
					auditLog.setOperatorId(user.getUserId());//设置操作人id
					auditLog.setOperateTs(new Timestamp(new Date().getTime()));//设置操作时间
					
					//获取请求ip
					String ip = request.getRemoteAddr();
					auditLog.setOperatorIp(ip);//设置操作人ip
					auditLogService.add(auditLog);//保存审计日志
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			return obj;
		}
		//=======生成日志结束==========
		
	}
	
	/**
	 * 转换请求类型 01表示产品 02表示解决方案 03表示API 04表示FAQ 05表示文档
	 * @param className
	 * @return
	 */
	private String getTargetType(String className){
		String returnType=null;
		if(className!=null){
			String name=className.substring(className.lastIndexOf(".")+1);
			if(name!=null){
				if("ProductService".equals(name)){//01 产品
					returnType="01";
				}else if("SolutionService".equals(name)){//02 解决方案
					returnType="02";
				}else if("APIInfoService".equals(name)){//03 API
					returnType="03";
				}else if("FaqService".equals(name)){//04 FAQ
					returnType="04";			
				}else if("FileInfoService".equals(name)){//05 文档
					returnType="05";		
				}
			}
		}
		return returnType;
	}
	
	/**
	 * 转换操作类别  01表示新增 02表示修改 03表示删除
	 * @param methodName
	 * @return
	 */
	private String getOperateType(String methodName){
		String returnType=null;
		if(methodName!=null){
			if(methodName.startsWith("add")||methodName.startsWith("save")){//01 新增
				returnType="01";
			}else if(methodName.startsWith("upd")||methodName.startsWith("modify")){//02 修改
				returnType="02";
			}else if(methodName.startsWith("del")){//03 删除
				returnType="03";
			}
		}
		return returnType;
	}
	
	/**
	 * 获取所有请求参敿
	 * @param pjp
	 * @return
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 */
	private Integer getpArgs(ProceedingJoinPoint pjp,String operateType) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException{
		Integer id=0;
		Object[] objs=pjp.getArgs();//得到所有参数
		if(objs==null||objs.length<=0){
			return id;
		}
		//判断如果是删除,则直接取参数中的第一个参数表示id,
		//否则通过反射判断对象中是否有getId方法,
		//如果有则通过反射调用该方法得到对应的id
		//例如 是新增产品,则得到的是产品id
		if("03".equals(operateType)){//是删除
			Object obj = objs[0];//获取第一个参数
        	if(obj!=null){//判断不为空
       			 String strNum=obj.toString();//转String
       			 
       			 if(strNum!=null&&!"".equals(strNum)){
	       			//将id转换成Integer类型
       				id=new Integer(strNum);
       			 }
   		 	}
		}else{//不是删除,是增加或修改
			for (Object info : objs) {//遍历参数对象  
	          
	           //获取该参数对象的所有方法 
	           Method[] methods = info.getClass().getDeclaredMethods(); 
	            //遍历所有方法
	            for (Method method : methods){
	                //得到方法名称
	                String methodName = method.getName();  
	                //判断是否为getId方法
	                if (methodName!=null&&methodName.endsWith("getId")) {
		                //调用该方法
	                	Object obj = method.invoke(info);
	                	//返回值不能空
	                	if(obj!=null){
			                //转String
		           			 String strNum=obj.toString();
		           			 if(strNum!=null&&!"".equals(strNum)){
		           			    //将id转换成Integer类型
		           				id=new Integer(strNum);
		           			 }
	           		 	}
	                }  
	            }   
	        } 
		}
		
		return id;//返回id
	}
	
	/**
	 * 转换简单的操作描述
	 * @param targetType
	 * @param operateType
	 * @return
	 */
	private String getOperateContent(String userName,String targetType,String operateType){
		String result=userName;
		if("01".equals(operateType)){//01 新增
			result+="新增";
		}else if("02".equals(operateType)){//02 修改
			result+="修改";
		}else if("03".equals(operateType)){//03 删除
			result+="删除";
		}
		
		if("01".equals(targetType)){
			result+="产品";
		}else if("02".equals(targetType)){//02
			result+="解决方案";
		}else if("03".equals(targetType)){//03 
			result+="API";
		}else if("04".equals(targetType)){//04 
			result+="FAQ";			
		}else if("05".equals(targetType)){//05
			result+="文档";	
		}
		return result;
	}

}

注解方式配置切面类

package com.unionpay.techjoin.admin.controller;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
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.unionpay.common.authorization.user.UserDetail;
import com.unionpay.techjoin.admin.utils.UserInfoUtil;
import com.unionpay.techjoin.common.domain.AuditLog;
import com.unionpay.techjoin.common.service.AuditLogService;
import org.aspectj.lang.annotation.Aspect


@Component(value="auditLogAop")//实例化注解 
@Aspect//声明这是一个切面Bean
public class AuditLogAop {
	
	@Autowired
	private AuditLogService auditLogService;
	
	//配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点
	//aspect 该方法名自己取的
	@Pointcut("execution(* com.unionpay.techjoin.common.service..*.*(..))")
	public void aspect(){	}
	
	/*
	 * (环绕通知)  -日志切点
	 * 参数 JoinPoint joinPoint
	 * ProceedingJoinPoint是JoinPoint的子类,在环绕通知中用到
	 * 其它通知则直接用JoinPoint类型参数
	 * 
	 * 环绕通知也可以这样写
	 * ((ProceedingJoinPoint) joinPoint).proceed();
	 */
	@SuppressWarnings("finally")
	@Around("aspect()")//配置环绕通知,使用在方法aspect()上注册的切入点
	public Object addAuditLog(ProceedingJoinPoint pjp) throws Throwable{
		
		Object obj=pjp.proceed();//执行方法
		//========生成日志开姿============
		try{
			//得到Request对象
			HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
			if(request!=null){
				//pjp.getTarget().getClass().getName()得到请求的Service类全名(包名.类名)
				//调用方法getTargetType得到类型01表示产品 02表示解决方案 03表示API 04表示FAQ 05表示文档
				String targetType =getTargetType(pjp.getTarget().getClass().getName());
				
				//pjp.getSignature().getName()得到请求的方法名
				//调用getOperateType方法得到操作类型 01表示新增 02表示修改 03表示删除
				String operateType=getOperateType(pjp.getSignature().getName());//方法 
				
				if(targetType!=null&&!"".equals(targetType)&&operateType!=null&&!"".equals(operateType)){
					
					//获取当前用户,这里调用了UserInfoUtil工具类
					UserDetail user= UserInfoUtil.getUserInfo(request);
					AuditLog auditLog=new AuditLog();//创建审计日志对象
					auditLog.setTargetType(targetType);//设置请求类别
					
					//设置关联Id,这里调用了下面getpArgs方法得到id
					auditLog.setTargetId(getpArgs(pjp,operateType));
					
					//设置简单操作描述,这里调用了下面getOperateContent方法获得							
			  auditLog.setOperateContent(getOperateContent(user.getUserId(),targetType,operateType));
					
					auditLog.setOperateType(operateType);//设置操作类别
					auditLog.setOperatorId(user.getUserId());//设置操作人id
					auditLog.setOperateTs(new Timestamp(new Date().getTime()));//设置操作时间
					
					//获取请求ip
					String ip = request.getRemoteAddr();
					auditLog.setOperatorIp(ip);//设置操作人ip
					auditLogService.add(auditLog);//保存审计日志
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			return obj;
		}
		//=======生成日志结束==========
		
	}
	
	/**
	 * 转换请求类型 01表示产品 02表示解决方案 03表示API 04表示FAQ 05表示文档
	 * @param className
	 * @return
	 */
	private String getTargetType(String className){
		String returnType=null;
		if(className!=null){
			String name=className.substring(className.lastIndexOf(".")+1);
			if(name!=null){
				if("ProductService".equals(name)){//01 产品
					returnType="01";
				}else if("SolutionService".equals(name)){//02 解决方案
					returnType="02";
				}else if("APIInfoService".equals(name)){//03 API
					returnType="03";
				}else if("FaqService".equals(name)){//04 FAQ
					returnType="04";			
				}else if("FileInfoService".equals(name)){//05 文档
					returnType="05";		
				}
			}
		}
		return returnType;
	}
	
	/**
	 * 转换操作类别   01表示新增 02表示修改 03表示删除
	 * @param methodName
	 * @return
	 */
	private String getOperateType(String methodName){
		String returnType=null;
		if(methodName!=null){
			if(methodName.startsWith("add")||methodName.startsWith("save")){//01 新增
				returnType="01";
			}else if(methodName.startsWith("upd")||methodName.startsWith("modify")){//02 修改
				returnType="02";
			}else if(methodName.startsWith("del")){//03 删除
				returnType="03";
			}
		}
		return returnType;
	}
	
	/**
	 * 获取所有请求参敿
	 * @param pjp
	 * @return
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 */
	private Integer getpArgs(ProceedingJoinPoint pjp,String operateType) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException{
		Integer id=0;
		Object[] objs=pjp.getArgs();//得到所有参数
		if(objs==null||objs.length<=0){
			return id;
		}
		//判断如果是删除,则直接取参数中的第一个参数表示id,
		//否则通过反射判断对象中是否有getId方法,
		//如果有则通过反射调用该方法得到对应的id
		//例如 是新增产品,则得到的是产品id
		if("03".equals(operateType)){//是删除
			Object obj = objs[0];//获取第一个参数
        	if(obj!=null){//判断不为空
       			 String strNum=obj.toString();//转String
       			 
       			 if(strNum!=null&&!"".equals(strNum)){
	       			//将id转换成Integer类型
       				id=new Integer(strNum);
       			 }
   		 	}
		}else{//不是删除,是增加或修改
			for (Object info : objs) {//遍历参数对象  
	          
	           //获取该参数对象的所有方法 
	           Method[] methods = info.getClass().getDeclaredMethods(); 
	            //遍历所有方法
	            for (Method method : methods){
	                //得到方法名称
	                String methodName = method.getName();  
	                //判断是否为getId方法
	                if (methodName!=null&&methodName.endsWith("getId")) {
		                //调用该方法
	                	Object obj = method.invoke(info);
	                	//返回值不能空
	                	if(obj!=null){
			                //转String
		           			 String strNum=obj.toString();
		           			 if(strNum!=null&&!"".equals(strNum)){
		           			    //将id转换成Integer类型
		           				id=new Integer(strNum);
		           			 }
	           		 	}
	                }  
	            }   
	        } 
		}
		
		return id;//返回id
	}
	
	/**
	 * 转换简单的操作描述
	 * @param targetType
	 * @param operateType
	 * @return
	 */
	private String getOperateContent(String userName,String targetType,String operateType){
		String result=userName;
		if("01".equals(operateType)){//01 新增
			result+="新增";
		}else if("02".equals(operateType)){//02 修改
			result+="修改";
		}else if("03".equals(operateType)){//03 删除
			result+="删除";
		}
		
		if("01".equals(targetType)){
			result+="产品";
		}else if("02".equals(targetType)){//02
			result+="解决方案";
		}else if("03".equals(targetType)){//03 
			result+="API";
		}else if("04".equals(targetType)){//04 
			result+="FAQ";			
		}else if("05".equals(targetType)){//05
			result+="文档";	
		}
		return result;
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值