自定义注解AOP保存日志到数据库

Aop自定义注解实现日志记录

实现对Controller层切入点,在执行Controller方法时进行日志记录
需要引入的依赖

<!-- AOP相关包 -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.8.0</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.8.0</version>
		</dependency>

1、配置文件:
spring-mvc.xml 增加

<!-- 启动对@AspectJ注解的支持 -->
    <aop:aspectj-autoproxy/>
    <!-- 配置使Spring采用CGLIB代理 -->
    <aop:aspectj-autoproxy proxy-target-class="true" /> 
    <!-- 扫描切点类组件 -->
    <!-- 放置切面实现类的包路径 -->
    <context:component-scan base-package="doone.util.SystemLogAspect"/>
    <!-- 日志表的service的包路径 -->
    <context:component-scan base-package="doone.service.TlOperateLogService"/>
    <bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <property name="corePoolSize" value="5" />
        <property name="maxPoolSize" value="10" />
    </bean>

2、建立一个自定义注解

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;

//@Target说明了Annotation所修饰的对象范围  
//1.CONSTRUCTOR:用于描述构造器
//2.FIELD:用于描述域
//3.LOCAL_VARIABLE:用于描述局部变量
//4.METHOD:用于描述方法
//5.PACKAGE:用于描述包
//6.PARAMETER:用于描述参数
//7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
@Target({ElementType.PARAMETER, ElementType.METHOD}) 

//@Retention定义了该Annotation被保留的时间长短
//1.SOURCE:在源文件中有效(即源文件保留)
//2.CLASS:在class文件中有效(即class保留)
//3.RUNTIME:在运行时有效(即运行时保留)
@Retention(RetentionPolicy.RUNTIME) 

//@Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。
@Documented
public @interface MethodLog {

	/**
     * 该注解作用于方法上时需要备注信息
     */
    String remarks() default "";
    
    /**
     * 用于日志类型为1的会获取方法内的参数
     * @return
     */
    String type() default "";
    
    
    /**
     *   方法内参数长度
     * @return
     */
    int len() default 0;
	
}

3、书写日志记录的Service
4、定义切面类

import java.lang.reflect.Method;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
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.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.NamedThreadLocal;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.google.gson.Gson;

import doone.domain.TlOperateLogBean;
import doone.domain.User;
import doone.service.TlOperateLogService;
import net.sf.json.JSONObject;


@Aspect
@Component
public class SystemLogAspect {

	// 这段代码调用了org.slf4j.LoggerFactory line:280
	private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect.class);
	private static final ThreadLocal<Date> beginTimeThreadLocal = new NamedThreadLocal("ThreadLocal beginTime");
	private static final ThreadLocal<TlOperateLogBean> logThreadLocal = new NamedThreadLocal("ThreadLocal log");

	private static final ThreadLocal<User> currentUser = new NamedThreadLocal("ThreadLocal user");

	private long sid;    //日志主键id
	
	@Autowired
	private ThreadPoolTaskExecutor threadPoolTaskExecutor;
	
	@Autowired
	private TlOperateLogService logModelService;

	/**
	 * Controller层切点 注解拦截
	 */
	@Pointcut("@annotation(doone.util.MethodLog)")
	public void controllerAspect() {
		logger.info("====log记录---------------");
	}

	/**
	 * 用于拦截Controller层记录用户的操作的开始时间
	 *
	 * @param joinPoint 切点
	 * @throws InterruptedException
	 */
	@Before("controllerAspect()")
	public void doBefore(JoinPoint joinPoint) throws InterruptedException {
		logger.info("====前置通知---------------");
		Date beginTime = new Date();
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		beginTimeThreadLocal.set(beginTime);// 线程绑定变量(该数据只有当前请求的线程可见)
		if (logger.isDebugEnabled()) {// 这里日志级别为debug
			logger.debug("开始计时: {}  URI: {}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(beginTime),
					request.getRequestURI());
		}
		// 读取session中的用户
		HttpSession session = request.getSession();
		User user = (User) session.getAttribute("user");
		System.out.println(user);
		currentUser.set(user);
	}

	
	/**
     * 用于拦截Controller层记录用户的操作
     *
     * @param joinPoint 切点
     */
    @After("controllerAspect()")
	public void doAfter(JoinPoint joinPoint) throws Exception {
		logger.info("AOP日志,后置通知-------------------------");

		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		Map<String, Object> returnMap = new HashMap<>();
		User user = currentUser.get();
		TlOperateLogBean bean = new TlOperateLogBean();
		String title = "";
        String IP = SystemLogAspect.getIp();//请求的IP
        String requestUri = request.getRequestURI();//请求的Uri
        Object[] objects = joinPoint.getArgs();
        System.out.println("======objects" + objects);
        Map<String, Object> rMap = getControllerMethodDescription2(joinPoint);
        title = (String) rMap.get("title");
        String flag = (String) rMap.get("type");
        int len  = (int) rMap.get("len");
        int i = 0;
        if("1".equals(flag)) {
        	for(Object object : objects) {
        		if(len > 0) {
        			if(len > i) {
        				returnMap.put("arg" + i, object);
        			}
        		}
        		i ++;
        	}
        }
        
        // 拦截的放参数类型
        Signature sig = joinPoint.getSignature();
        // 拦截的方法参数
        Map<String, String[]> parameterMap = request.getParameterMap();
		Iterator entries = parameterMap.entrySet().iterator();
        Map.Entry entry;
        String name;
        String value = "";
        
        while(entries.hasNext()) {
        	entry = (Map.Entry) entries.next();
            name = (String) entry.getKey();
            Object valueObj = entry.getValue();
            if (null == valueObj) {
                value = "";
            } else if (valueObj instanceof String[]) {
                String[] values = (String[]) valueObj;
                for (String v : values) {
                    value = v + ",";
                }
                value = value.substring(0, value.length() - 1);
            } else {
                value = valueObj.toString();
            }
            returnMap.put(name, value);
        }
        
        JSONObject paramsJson = JSONObject.fromObject(new Gson().toJson(returnMap));
        
        
        
        bean.setOperateIp(IP);    //IP
        bean.setOperateUrl(requestUri);    //请求URL
        
        bean.setStatus("E");   //有效状态
        bean.setOperateName(title);
        bean.setOperateResult("0");
        bean.setInParam(paramsJson.toString());
		
		
		try {
		if (user != null) {
			logger.error("=======" + user.getLoginName());
			bean.setOperator(Long.valueOf(user.getId()));   //用户id
		} else {
			bean.setOperator((long)-1);   //用户id
		}
		} catch (Exception e) {
            e.printStackTrace();
        }
		sid = logModelService.insertTlOperateLog(bean);
		bean.setId(sid);
		logThreadLocal.set(bean);

	}
	
	
	
	/**
	 * 异常通知 记录操作报错日志
	 * 
	 * @param joinPoint
	 * @param e
	 */
	@AfterThrowing(pointcut = "controllerAspect()", throwing = "e")
	public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
		logger.info("AOP日志,方法出现异常----------------");
		TlOperateLogBean logModel = logThreadLocal.get();
		logModel.setOperateResult("error");
		logModel.setOutParam(e.toString());
		logModel.setUpdateTime(new Date());
		new UpdateLogThread(logModel, logModelService).start();
	}
	
	@AfterReturning(pointcut="controllerAspect()",returning="returnVal")
    public void afterReturn(JoinPoint joinPoint,Object returnVal){
        logger.info("AOP日志,方法正常执行");
        TlOperateLogBean bean = logThreadLocal.get();
        bean.setUpdateTime(new Date());
        bean.setOutParam(returnVal == null ? "" : returnVal.toString());
        new UpdateLogThread(bean, logModelService).start();
    }
	
	/**
	 * 获取注解中对方法的描述信息 用于Controller层注解
	 * 
	 * @param joinPoint 切点
	 * @return 方法描述
	 */

	public static Map<String, Object> getControllerMethodDescription2(JoinPoint joinPoint) {
		Map<String, Object> map = new HashMap<String,Object>();
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		Method method = signature.getMethod();
		MethodLog controllerLog = method.getAnnotation(MethodLog.class);
		String discription = controllerLog.remarks();
		map.put("title", discription);
		String type = controllerLog.type();
		map.put("type", type);
		int len = controllerLog.len();
		map.put("len", len);
		return map;
	}
	
	
	
	/**
     * 获取请求ip
     */
	public static String getIp() {
		InetAddress ia = null;
		String localip = null;
		try {
			ia = ia.getLocalHost();
			localip = ia.getHostAddress();
		} catch (Exception e) {
			// TODO: handle exception
		}
		
		return localip;
	}	
	
	/**
	 * 保存日志线程
	 *
	 * @author lin.r.x
	 *
	 */
	private class  SaveLogThread implements Runnable {
		private TlOperateLogBean logModel;
		private TlOperateLogService logModelService;

		public SaveLogThread(TlOperateLogBean logModel, TlOperateLogService logModelService) {
			this.logModel = logModel;
			this.logModelService = logModelService;
		}

		@Override
		public void run() {
			System.out.println("保存日志");
			 sid = logModelService.insertTlOperateLog(logModel);
		}
	}
	
	
	/**
	 * 日志更新线程
	 *
	 * @author lin.r.x
	 *
	 */
	private static class UpdateLogThread extends Thread {
		private TlOperateLogBean logModel;
		private TlOperateLogService logModelService;

		public UpdateLogThread(TlOperateLogBean logModel, TlOperateLogService logModelService) {
			super(UpdateLogThread.class.getSimpleName());
			this.logModel = logModel;
			this.logModelService = logModelService;
		}

		@Override
		public void run() {
			this.logModelService.updateTlOperateLogSensitive(logModel);
		}
	}
	

}

在Controller中引用

@MethodLog(remarks="数据导入-订单数据导入")
	@RequestMapping(value = "/orderInfoImport")
	@ResponseBody
	public Map<String,Object> orderInfoImport(HttpServletRequest request, HttpServletResponse response) {

参考文章:http://itindex.net/detail/50710-springaop-controller-service

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值