AOP的定义
AOP通过 预编译方式 和 运行期动态代理 实现,在不修改源代码的情况下,给程序动态统一添加功能的一种技术,简称AOP,一句话总结:在不改变原有代码的条件下,对功能进行扩展
公式:AOP=切入点表达式 + 通知方法
AOP的一些概念
-
1.连接点:在执行正常的业务过程中满足了切入点表达式时进入切面的点.(织入)多个
-
2.通知: 在切面中执行的具体的业务 (方法)
(1)前置通知: 目标方法执行之前执行
(2)后置通知: 目标方法执行之后执行
(3)异常通知: 目标方法执行之后抛出异常时执行
(4)最终通知: 不管什么时候都需要执行的方法说明:上面的四大通知类型不能控制目标方法是否执行,一般适用上面的四大通知类型,都是用来记录程序的执行状态.
(5)环绕通知:在目标方法执行前后都要执行的通知方法.控制目标方法是否执行,并且环绕通知的功能最为强大
-
3.切入点:能够进入切面的一个判断 (if判断 一个)
切入点表达式说明:
1)bean(bean的id) 类名首字母小写 匹配一个类
2).within(包名.类名) 按包路径匹配类 匹配多个类上述表达式时粗粒度的控制,按类匹配
3)execution(返回值类型 包名.类名.方法名[参数列表])
4)@annotation(包名.注解名) 按注解进行拦截
使用AOP记录日志操作
- 1、自定义注解
/**
* 标记需要做业务日志的方法
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface BussinessLog {
/**
* 业务的名称,例如:"修改菜单"
*/
String value() default "";
/**
* 被修改的实体的唯一标识,例如:菜单实体的唯一标识为"id"
*/
String key() default "id";
/**
* 字典(用于查找key的中文名称和字段的中文名称)
*/
String dict() default Dict.SYSTEM_DICT;
/**
* request参数默认为json
* @return
*/
String type() default ParaType.JSON;
}
- 2、AOP相关配置类
/**
* 日志记录
*/
@Aspect
@Component
public class LogAop {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private final String POINT_CUT ="execution(public * net.ruixin.dao.*.*(..))";
//定义切点 @Pointcut
//在注解的位置切入代码
@Pointcut(value = "@annotation(net.ruixin.service.plat.log.aop.BussinessLog)")
public void cutService() {
}
@Pointcut(POINT_CUT)
public void cutDao() {
}
//切面 配置通知
@Around("cutService()")
public Object recordSysLog(ProceedingJoinPoint point) throws Throwable {
//先执行业务
Object result = point.proceed();
try {
handle(point);
} catch (Exception e) {
log.error("日志记录出错!", e);
}
return result;
}
private void handle(ProceedingJoinPoint point) throws Exception {
//从切面织入点处通过反射机制获取织入点处的方法
Signature sig = point.getSignature();
MethodSignature msig;
if (!(sig instanceof MethodSignature)) {
throw new IllegalArgumentException("该注解只能用于方法");
}
msig = (MethodSignature) sig;
Object target = point.getTarget();
Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
//获取切入点所在的方法
String methodName = currentMethod.getName();
//如果当前用户未登录,不做日志
ShiroUser user = ShiroKit.getUser();
if (null == user) {
return;
}
//获取拦截方法的参数
String className = point.getTarget().getClass().getName();
//获取当前用户操作信息
// Object[] params = point.getArgs();
//获取操作名称
BussinessLog annotation = currentMethod.getAnnotation(BussinessLog.class);
String bussinessName = annotation.value();
String key = annotation.key();
String dictClass = annotation.dict();
String paraType = annotation.type();
//如果涉及到修改,比对变化
String msg;
if (Objects.equals(paraType, ParaType.ATTRIBUTE)) {
if (bussinessName.contains("修改")) {
Object obj1 = LogObjectHolder.me().get();
Map<String, String> obj2 = HttpKit.getRequestParameters();
msg = Contrast.contrastObj(dictClass, key, obj1, obj2);
} else {
Map<String, String> parameters = HttpKit.getRequestParameters();
AbstractDictMap dictMap = DictMapFactory.createDictMap(dictClass);
msg = Contrast.parseMutiKey(dictMap, key, parameters);
}
} else {
//如何使用json数据,需要特殊转换处理
Map<String, String> parameters = HttpKit.getRequestParameters();
msg = "日志名称:"+bussinessName + "; 操作数据: " +parameters.toString();
}
// 保存操作日志
LogManager.me().executeLog(LogTaskFactory.bussinessLog(user, bussinessName, className, methodName, msg));
}
}
- 3、使用自定义注解
@ResponseBody
@RequestMapping(value = "/delSysOrgan")
@BussinessLog(value = "机构删除")
public AjaxReturn delSysOrgan(Long id, Long newOrganId) {
organService.delSysOrgan(id, newOrganId);
return success();
}
- 4、日志实体类
@Table(name = "SYS_LOG_OPERATION")
@Entity
@DynamicInsert
@DynamicUpdate
public class OperationLog extends BaseDomain {
@Id
@SequenceGenerator(name = "seq_sys_log", sequenceName = "SEQ_SYS_LOG_LOGIN", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_sys_log")
private Long id;
/**
* 日志类型
*/
@Column(name = "LOG_TYPE")
private String logType;
/**
* 日志名称
*/
@Column(name = "LOG_NAME")
private String logName;
/**
* 用户id
*/
@Column(name = "USER_ID")
private Long userId;
/**
* 用户名
*/
@Column(name = "USER_NAME")
private String userName;
/**
* 类名称
*/
@Column(name = "CLASS_NAME")
private String className;
/**
* 方法名称
*/
@Column(name = "METHOD")
private String method;
/**
* 创建时间
*/
@Column(name = "CREATE_TIME")
private Date createTime;
/**
* 是否成功
*/
@Column(name = "SUCCESS")
private String success;
}
标签:name,记录,private,AOP,日志,public,String
From: https://www.cnblogs.com/d111991/p/16892059.html