用SpringAOP获取用户操作日志入库

切service层中所有的方法,将有自定义注解的方法的操作日志入库,其中需要注意的几点:

  1. 注意aspectjweaver.jar包的版本,一般要1.6以上版本,否则会报错
  2. 注意是否使用了双重代理,spring.xml中不需要配置切面类的,否则会出现切两次的情况
  3. 注意返回的数据类型,如果是实体类需要获取实体类中每个属性的值,若该实体类中的某个属性也是实体类,需要再次循环获取该属性的实体类属性
  4. 用递归的方法获得参数及参数内容
package awb.aweb_soa.service.userOperationLog;

import java.io.IOException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.sql.rowset.serial.SerialBlob;

import org.apache.commons.lang.WordUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import cn.com.agree.aweb.asapi.ASAPI;
import edm.aweb_soa.aweb_soa.base.user.UserOperationLogDO;
import awb.aweb_soa.aservice.app.DefaultUser;
import awb.aweb_soa.global.annotation.UserOperationType;


@Service
@Aspect
public class UserOperationLogAspect {
	@Autowired
	UserOperationLog userOperationLog;
	/**
	 * 业务逻辑方法切入点,切所有service层的方法
	 */
	@Pointcut("execution(* awb.aweb_soa.service..*(..))")
	public void serviceCall() {

	}
	/**
	 * 用户登录
	 */
	@Pointcut("execution(* awb.aweb_soa.aservice.app.LoginController.signIn(..))")
	public void logInCall() {

	}
	/**
	 * 退出登出切入点
	 */
	@Pointcut("execution(* awb.aweb_soa.aservice.app.DefaultUser.logout(..))")
	public void logOutCall() {

	}

	/**
	 * 操作日志(后置通知)
	 * 
	 * @param joinPoint
	 * @param rtv
	 * @throws Throwable
	 */
	@AfterReturning(value = "serviceCall()", argNames = "rtv", returning = "rtv")
	public void doAfterReturning(JoinPoint joinPoint, Object rtv) throws Throwable {
		operationCall(joinPoint, rtv,"S");
	}
	/**
	 * 用户登录(后置通知)
	 * 
	 * @param joinPoint
	 * @param rtv
	 * @throws Throwable
	 */
	@AfterReturning(value = "logInCall()", argNames = "rtv", returning = "rtv")
	public void doLoginReturning(JoinPoint joinPoint, Object rtv) throws Throwable {
		operationCall(joinPoint, rtv,"S");
	}
	
	@Before(value = "logOutCall()")
	public void logoutCalls(JoinPoint joinPoint) throws Throwable {
		operationCall(joinPoint, null,"S");
	}
	/**
	 * 操作日志(异常通知)
	 * 
	 * @param joinPoint
	 * @param e
	 * @throws Throwable
	 */
	@AfterThrowing(value = "serviceCall()", throwing="e")
	public void doAfterThrowing(JoinPoint joinPoint, Object e) throws Throwable {
		operationCall(joinPoint, e,"F");
	}
	
	/**
	 * 获取用户操作日志详细信息
	 * 
	 * @param joinPoint
	 * @param rtv
	 * @param status
	 * @throws Throwable
	 */
	private void operationCall(JoinPoint joinPoint, Object rtv,String status)
			throws Throwable {
		//获取当前用户
		DefaultUser currentUser = (DefaultUser) ASAPI.authenticator().getCurrentUser();
		String userName = null;
		if (currentUser != null) {
			//获取用户名
			userName = currentUser.getUsername();
			//获取用户ip地址
			HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
					.getRequestAttributes()).getRequest();
			String userIp = getIpAddress(request);

			// 拼接操作内容的字符串
			StringBuffer rs = new StringBuffer();

			// 获取类名
			String className = joinPoint.getTarget().getClass()
					.getCanonicalName();
			rs.append("类名:" + className + "; 
"); // 获取方法名 String methodName = joinPoint.getSignature().getName(); rs.append("方法名:" + methodName + ";
"); // 获取类的所有方法 Method[] methods = joinPoint.getTarget().getClass() .getDeclaredMethods(); //创建变量用于存储注解返回的value值 String operationType = ""; for (Method method:methods) { String mName = method.getName(); // 当切的方法和类中的方法相同时 if (methodName.equals(mName)) { //获取方法的UserOperationType注解 UserOperationType userOperationType = method.getAnnotation(UserOperationType.class); //如果方法存在UserOperationType注解时 if (userOperationType!=null) { //获取注解的value值 operationType = userOperationType.value(); // 获取操作内容 Object[] args = joinPoint.getArgs(); int i = 1; if (args!=null&&args.length>0) { for (Object arg :args) { rs.append("[参数" + i + "======"); userOptionContent(arg, rs); rs.append("]
"); } } // 创建日志对象 UserOperationLogDO log = new UserOperationLogDO(); log.setLogId(ASAPI.randomizer().getRandomGUID()); log.setUserCode(userName); log.setUserIP(userIp); log.setOperationDesc(new SerialBlob(rs.toString().getBytes("UTF-8"))); log.setOperationType(operationType); log.setOperationTime(new Timestamp(System.currentTimeMillis())); log.setStatus(status); //日志对象入库 userOperationLog.insertLog(log); } } } } } /** * 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址; * * @param request * @return * @throws IOException */ public final static String getIpAddress(HttpServletRequest request) throws IOException { // 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址 String ip = request.getHeader("X-Forwarded-For"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } } else if (ip.length() > 15) { String[] ips = ip.split(","); for (int index = 0; index < ips.length; index++) { String strIp = (String) ips[index]; if (!("unknown".equalsIgnoreCase(strIp))) { ip = strIp; break; } } } return ip; } /** * 使用Java反射来获取被拦截方法(insert、update, delete)的参数值, 将参数值拼接为操作内容 */ @SuppressWarnings("unchecked") public StringBuffer userOptionContent(Object info, StringBuffer rs){ String className = null; // 获取参数对象类型 className = info.getClass().getName(); className = className.substring(className.lastIndexOf(".") + 1); rs.append("类型:"+className+","); //参数对象类型不是实体类或者集合时,直接显示参数值 if (className.equals("String")||className.equals("int")||className.equals("Date") ||className.equals("Timestamp")||className.equals("Integer") ||className.equals("B")||className.equals("Long")) { rs.append("值:(" + info + ")"); } //参数类型是ArrayList集合,迭代里面的对象,并且递归 if(className.equals("ArrayList")){ int i = 1; //将参数对象转换成List集合 List list = (List) info; for (Object obj: list) { rs.append("
 集合内容" + i + "————"); //递归 userOptionContent(obj, rs); rs.append("
"); i++; } //参数对象是实体类 }else{ // 获取对象的所有方法 Method[] methods = info.getClass().getDeclaredMethods(); //遍历对象中的所有方法是否是get方法 for (Method method : methods) { //获取方法名字 String methodName = method.getName(); if (methodName.indexOf("get") == -1 || methodName.equals("getPassword") || methodName.equals("getBytes")|| methodName.equals("getChars") || methodName.equals("getLong") || methodName.equals("getInteger") || methodName.equals("getTime") || methodName.equals("getCalendarDate") || methodName.equals("getDay") || methodName.equals("getMinutes") || methodName.equals("getHours")|| methodName.equals("getSeconds") || methodName.equals("getYear") || methodName.equals("getTimezoneOffset") || methodName.equals("getDate") || methodName.equals("getJulianCalendar") || methodName.equals("getMillisOf") || methodName.equals("getCalendarSystem") || methodName.equals("getMonth")|| methodName.equals("getTimeImpl") || methodName.equals("getNanos")) { continue; } rs.append("
 " + className + "——" + changeString(methodName) + ":"); Object rsValue = null; try { // 调用get方法,获取返回值 rsValue = method.invoke(info); userOptionContent(rsValue, rs); } catch (Exception e) { continue; } } } return rs; } //有get方法获得属性名 public String changeString(String name){ name = name.substring(3); name = WordUtils.uncapitalize(name);//首字符小写 return name; } }

 

你可能感兴趣的:(用SpringAOP获取用户操作日志入库)