java使用注解实现系统日志记录

 

不论在神魔类型的项目中,日志系统绝对是一个不可少的存在,那么,怎末用一个最简便的方式来实现日志在数据库中的存储呢??最近在项目中正好负责了日志模块的实现,就简单记录一下。

 我在这个项目中使用的是aop自定义注解的方式,大致步骤如下:

  1.第一步,首先需要先定义一个注解类,来实现部分方法介绍信息的传递和切入点的切入时机。

package com.cms.common.annotation;


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;

/**
 * 操作日志注解类
 * 请填上日志描述:desc
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
public @interface ControllerOptLog {
	/**
	 * 日志描述
	 * @return
	 */
	String desc() default "";
}

 

spring自定义注解,不多解释,其中属性desc是为切面传输必要参数的。

 

 

2.第二步,需要定义一个切面类,并在切面类中编写aop切入的前后通知等方法。

package com.cms.common.annotation;

import com.cms.common.utils.IPUtil;
import com.cms.common.utils.security.AccountShiroUtil;
import com.cms.common.utils.security.UserShiroUtil;
import com.cms.entity.company.Account;
import com.cms.entity.system.log.ErrorLog;
import com.cms.entity.system.log.OperateLog;
import com.cms.entity.system.users.Users;
import com.cms.service.system.log.ErrorLogService;
import com.cms.service.system.log.OptLogService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

@Aspect
@Component
@Order(1)// Order值越小优先被加载
public class OperateAspect {

	private final Log logger = LogFactory.getLog(OperateAspect.class);

	private Boolean recordOptLog = true;


	private OperateLog operateLog;


	@Autowired
	OptLogService operateLogService;

	@Autowired
	ErrorLogService errorLogService;

	@Before(value = "@annotation(com.cms.common.annotation.ControllerOptLog)")
	public void beforeAdvice(JoinPoint joinPoint) throws Throwable {
		Object[] args = joinPoint.getArgs();
		if (recordOptLog) {
			try {
				operateLog = new OperateLog();
				HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
						.getRequest();
				String ip = IPUtil.getIpAddr(request);
				MethodSignature signature = (MethodSignature) joinPoint.getSignature();
				Method method = signature.getMethod();
				Users currentUser= UserShiroUtil.getCurrentUser();
				ControllerOptLog controllerOptLog = method.getAnnotation(ControllerOptLog.class);
				String desc = controllerOptLog.desc();
				RequestMapping requestMappingAnnotation = joinPoint.getTarget().getClass().getAnnotation(RequestMapping.class);
				String url = request.getRequestURI();
				//添加记录内容
				operateLog.setIp(ip);
				operateLog.setUserName(currentUser.getName());
				operateLog.setParams(method.getParameters().toString());
				operateLog.setUserCode(currentUser.getCode());
				operateLog.setUrl(url);
				operateLog.setDesc(desc);
				operateLog.setBeginTime(new Date().toLocaleString());

			} catch (Throwable e) {
				logger.error("记录操作日志错误", e);
			}
		}
	}


	@AfterReturning(value = "@annotation(com.cms.common.annotation.ControllerOptLog)")
	public void afterAdvice(JoinPoint joinPoint) throws Throwable {
		if (recordOptLog) {
			try {
				operateLog.setEndTime(new Date().toLocaleString());
				operateLogService.log(operateLog);
			} catch (Throwable e) {
				logger.error("记录操作日志错误", e);
			}
		}
	}

	@AfterThrowing(value = "@annotation(com.cms.common.annotation.ControllerOptLog)",throwing = "e")
	public void erroeAdvice(JoinPoint joinPoint,Throwable e){

		Object[] args = joinPoint.getArgs();
		ErrorLog errorLog = new ErrorLog();
		if (recordOptLog) {
			HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
					.getRequest();
			String ip = IPUtil.getIpAddr(request);
			MethodSignature signature = (MethodSignature) joinPoint.getSignature();
			Method method = signature.getMethod();
			Users currentUser = UserShiroUtil.getCurrentUser();
			ControllerOptLog controllerOptLog = method.getAnnotation(ControllerOptLog.class);
			String desc = controllerOptLog.desc();
			RequestMapping requestMappingAnnotation = joinPoint.getTarget().getClass().getAnnotation(RequestMapping.class);
			String url = request.getRequestURI();

			errorLog.setUserCode(currentUser.getCode());
			errorLog.setUserName(currentUser.getName());
			errorLog.setParams(method.getParameters().toString());
			errorLog.setIp(ip);
			errorLog.setDesc(desc);
			errorLog.setContent(e.toString());
			errorLog.setUrl(url);
			errorLog.setCurrTime(new Date().toLocaleString());

			errorLogService.saveErrorAndOpt(errorLog);
		}
	}
}

需要注意的是,在这个切面类中所有的通知方法切入的位置都是指定为执行自定义注解时

value = "@annotation(com.cms.common.annotation.ControllerOptLog)"

在执行到切面方法 的时候可以通过 JoinPoint 对象获取一些请求上的参数,比如request,parms等等,同时因为使用的是自定义注解,所以可以通过

method.getAnnotation();

方法获取到标注注解的时候存入的操作介绍,最后把这些需要的参数封装到日志对象中,存入数据库或者指定位置中。

 

在需要切入的地方需要标上自己定义的注解,我的如下:

/**
	 * 跳转到发件箱
	 * @return
	 */
	@ControllerOptLog(desc = "发件箱跳转")
	@RequestMapping("tohairlist")
	public String tolist(Model model) {
		model.addAttribute("permitBtn", getPermitBtn(Const.RESOURCES_TYPE_BUTTON));
		model.addAttribute("tableBtn", getPermitBtn(Const.RESOURCES_TYPE_FUNCTION));
		return "/system/message/Hairbox/tolist";
	}

第一次记录日志,若有更好的方式可以评论下。

 

 

 

 

 

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值