一个简单版本。
在写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.
到此完成。