Spring使用 AOP 实现 日志功能

一个简单版本。
在写Aop 实现日志功能时,如果你对AOP 一些内置属性不清楚的,可结合此博客:https://www.cnblogs.com/liuruowang/p/5711563.html

代码环境 SSM :

1.首先 写一个 日志类 Logtable

@Entity
@Table(name = "logtable")
@Setter
@Getter
public class Logtable {
	private Integer id;
	/**     类名  **/
	private String operateClassName;
	/**     方法名 **/
	private String operateMethodName;
	/**     操作类型    **/
	private String operateType;
	/**     操作s说明    **/
	private String operateExplain;

	private String operateUser;

	private String operateDate;

	private String operateResult;

	private String remark;

}

2.自定义注解。为了获取注释

@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {

	/** 操作类型 **/
	 String operateType();
	/** 操作解释 **/
	 String operateExplain();
}

参数解释:

/**
 * @author Cc
 *
 *  @Target({ElementType.PARAMETER, ElementType.METHOD})
 *  作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
 *
 *   取值(ElementType)有:
 *
 *     1.CONSTRUCTOR:用于描述构造器
 *     2.FIELD:用于描述域
 *     3.LOCAL_VARIABLE:用于描述局部变量
 *     4.METHOD:用于描述方法
 *     5.PACKAGE:用于描述包
 *     6.PARAMETER:用于描述参数
 *     7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
 *
 * @Retention(RetentionPolicy.RUNTIME)  解释:@Retention()  定义了该Annotation(注释)被保留的时间长短
 * 取值(RetentionPoicy)有:
 *
 *     1.SOURCE:在源文件中有效(即源文件保留)
 *     2.CLASS:在class文件中有效(即class保留)
 *     3.RUNTIME:在运行时有效(即运行时保留)
 *
 *
 * 自定义注解: @interface  自定义注解
 *
 *  定义注解格式:
 *   public @interface 注解名 {定义体}
 *
 *   注解参数的可支持数据类型:
 *
 *     1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
 *     2.String类型
 *     3.Class类型
 *     4.enum类型
 *     5.Annotation类型
 *     6.以上所有类型的数组
 *
 *   Annotation(注释)类型里面的参数该怎么设定:
 *   第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;   
 *   第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;  
 *   第三,如果只有一个参数成员,最好把参数名称设为"value",后加小括号.例:下面的例子FruitName注解就只有一个参数成员。
 *
 * @data 2019/5/18 13:53
 */

详情参考注释注解:https://www.cnblogs.com/gmq-sh/p/4798194.html

3.写一个 日志的 切面类

/**
 * @author Cc
 * @data 2019/4/23 16:59
 */
//定义切面
@Aspect
@Component
public class LogAopAspect {

	@Resource
	private LogTableDao logTableDao;

		@Before(value="execution( * cn.sys.controller.RwDaoController.delRwHist(..))")
	public void beforeAdvice(JoinPoint joinPoint){
		try {
			String operationType = "";
			String operateExplain = "";
			//获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
			Signature signature = joinPoint.getSignature();
			//目标方法名
			String methodName = signature.getName();
			//目标方法所属类的简单类名
			String simpleName = signature.getDeclaringType().getSimpleName();
			//获取传入目标方法的参数对象
			Object target = joinPoint.getTarget();
			//获取当前代理类的全限定名
			String targetName = joinPoint.getTarget().getClass().getName();

			//获取传入目标方法的参数对象
			Object[] args = joinPoint.getArgs();
			Class<?> aClass = null;
			try {
				aClass = Class.forName(targetName);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}

			Method[] methods = aClass.getMethods();
			for (int i = 0; i < methods.length; i++) {
				if (methods[i].getName() != methodName) {continue;}
				Class<?>[] clazzs = methods[i].getParameterTypes();
				if (clazzs.length == args.length) {
					operationType =	methods[i].getAnnotation(Log.class).operateType();  //获取指定类型的注释
					operateExplain =	methods[i].getAnnotation(Log.class).operateExplain();
					break;
				}

			}
			System.out.println("署名信息的对象:"+signature);
			System.out.println("目标方法所属类的简单类名:"+simpleName);
			System.out.println("获取传入目标方法的参数对象:"+target);

			System.out.println("代理类:"+targetName);
			System.out.println("方法名:"+methodName);
			System.out.println("操作类型:"+operationType);
			System.out.println("操作解释:"+operateExplain);

			System.out.println("---------------------------开始保存日志----------------------------------");

			SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-HH-dd hh:mm:ss");
			String date = dateFormat.format(new Date());
			Logtable logtable1 = new Logtable();

			logtable1.setOperateClassName(targetName);      //方法所在类名
			logtable1.setOperateMethodName(methodName);     //执行的方法
			logtable1.setOperateType(operationType);        //操作类型
			logtable1.setOperateExplain(operateExplain);    //操作说明
			logtable1.setOperateUser("超级管理员");         //操作人
			logtable1.setOperateDate(date);                 //执行的时间
			logtable1.setOperateResult("");
			logtable1.setRemark("");
			logTableDao.addLog(logtable1);
		}catch (Exception e){
			e.printStackTrace();
		}
	}

	//异常通知
	@AfterThrowing(value = "execution( * cn.sys.controller.RwDaoController.delRwHist(..))",throwing = "e")
	public void exceptionAdvice(JoinPoint joinPoint,Throwable e){
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		HttpSession session = request.getSession();
		//读取session中的用户
		Object user = session.getAttribute("user");
		//请求的IP
		String ip = request.getRemoteAddr();
		String params = "";
		if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
			params= Arrays.toString(joinPoint.getArgs());
		}
		System.out.println(params);
		try {
			String operationType = "";
			String operateExplain = "";
			//获取传入目标方法的参数对象
			Object[] args = joinPoint.getArgs();
			//目标方法所属类的简单类名
			String simpleName = joinPoint.getSignature().getDeclaringType().getSimpleName();
			//获取方法名
			String methodName = joinPoint.getSignature().getName();
			//获取类的全限定名
			String targetName = joinPoint.getTarget().getClass().getName();

			//获取该类的Class对象
			Class<?> clazz = null;
			try {
				clazz = Class.forName(targetName);
			} catch (ClassNotFoundException ee) {
				ee.printStackTrace();
			}
			Method[] methods = clazz.getMethods();
			for (int i = 0; i < methods.length; i++) {
				if (methods[i].getName() != methodName){continue;}

				Class<?>[] parameterTypes = methods[i].getParameterTypes();
				if (parameterTypes.length == args.length){
					Log annotation = methods[i].getAnnotation(Log.class);
					operationType = annotation.operateType();
					operateExplain = annotation.operateExplain();
					break;
				}
			}
			System.out.println("---------------------------开始保存日志----------------------------------");

			SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-HH-dd hh:mm:ss");
			String date = dateFormat.format(new Date());
			Logtable logtable1 = new Logtable();

			logtable1.setOperateClassName(targetName);      //方法所在类名
			logtable1.setOperateMethodName(methodName);     //执行的方法
			logtable1.setOperateType(operationType);        //操作类型
			logtable1.setOperateExplain(operateExplain);    //操作说明
			logtable1.setOperateUser("超级管理员");         //操作人
			logtable1.setOperateDate(date);                 //执行的时间
			logtable1.setOperateResult("删除失败,异常代码"+e.getClass().getName() +"异常信息:"+e.getMessage());
			logtable1.setRemark("");
			logTableDao.addLog(logtable1);
		}catch (Exception ee){
			ee.printStackTrace();
		}
	}
}

4.要切入点的类以及方法

Controller
@RequestMapping("/rw")
public class RwDaoController {

	@Resource(name = "rwService")
	private IRwService iRwService;

    @RequestMapping(value = "delRwHistServlet",produces = {"application/json;charset=UTF-8"})
    @ResponseBody
    @Log(operateType="Delete删除:",operateExplain="删除任务历史记录表数据")  //这里使用的自定义注解
    public Object delRwHist(HttpServletRequest request){
       int i = 1/0;   //模拟异常
    	try {
		    String id =  request.getParameter("id");
		    String [] arrId = id.split(",");
		    //删除数据
		    iRwService.delRwHistById(arrId);
	    }catch (Exception e){
    		e.printStackTrace();
		    return JSONObject.toJSONString("删除失败");
	    }
	    return JSONObject.toJSONString("删除成功");
    }
}

6.运行结果:
在这里插入图片描述

注:
1.如果切入点的方法出现异常了,则不会走 环绕方法。
2.

到此完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值