Spring切面 + 自定义注解实现日志记录
1.@Target
@Target注解,是专门用来限定某个自定义注解能够被应用在哪些Java元素上面的. 它使用一个枚举类型定义如下:
public enum ElementType {
/** 类,接口(包括注解类型)或枚举的声明 */
TYPE,
/** 属性的声明 */
FIELD,
/** 方法的声明 */
METHOD,
/** 方法形式参数声明 */
PARAMETER,
/** 构造方法的声明 */
CONSTRUCTOR,
/** 局部变量声明 */
LOCAL_VARIABLE,
/** 注解类型声明 */
ANNOTATION_TYPE,
/** 包的声明 */
PACKAGE
}
2.@Retention
@Retention注解用来修饰自定义注解的生命力。
注解的生命周期有三个阶段:1、Java源文件阶段;2、编译到class文件阶段;3、运行期阶段。同样使用了RetentionPolicy枚举类型定义了三个阶段:
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
* (注解将被编译器忽略掉)
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
* (注解将被编译器记录在class文件中,但在运行时不会被虚拟机保留,这是一个默认的行为)
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
* (注解将被编译器记录在class文件中,而且在运行时会被虚拟机保留,因此它们能通过反射被读取到)
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
3.@Documented
@Documented注解,是被用来指定自定义注解是否能随着被定义的java文件生成到JavaDoc文档当中。
4.自定义log注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnnotation {
/**
描述
*/
String describe() default "";
}
5.定义切面类
@Aspect
@Component
public class ControllerAspect {
@Resource
private SysLogService sysLogService;
/**
@annotation(注解类型):匹配被调用的方法上有指定的注解。
*/
@Pointcut("@annotation(com.test.annotation.LogAnnotation)")
public void logPointCut() {}
@Before("logPointCut()")
public void saveSysLog(JoinPoint joinPoint) throws ClassNotFoundException {
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
//获取请求头参数
String adminId = request.getParameter(BaseConstant.ADMIN_ID);
String userName = request.getParameter(BaseConstant.USER_NAME);
String requestUri = request.getRequestURI();
String httpMethod = request.getMethod();
SysLogEntity sysLog = new SysLogEntity();
//获取类全路径
String targetName = joinPoint.getTarget().getClass().getName();
Class targetClass = Class.forName(targetName);
//获取调用的方法
String methodName = joinPoint.getSignature().getName();
//获取本类以及父类或者父接口中所有的公共方法(public修饰符修饰的)
Method[] methods = targetClass.getMethods();
//获取传入目标方法的参数对象
Object[] params = joinPoint.getArgs();
for (Method method : methods) {
if (method.getName().equals(methodName)) {
//返回Class类型的数组
Class[] tmpCs = method.getParameterTypes();
if (tmpCs.length == params.length) {
// 获取注解内容
LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
if(logAnnotation != null){
//写入参数
if(params.length>0){
// 使用json转换工具 将参数转为json串,以便存入数据库
String jsonStr = JSON.toJSONString(params);
sysLog.setParams(jsonStr);
}
//获取操作名称
String operate = logAnnotation.operate();
sysLog.setOperate(operate);
sysLog.setClassName(targetName);
sysLog.setMethodName(methodName);
sysLog.setIp(IpUtils.getV4IP());
sysLog.setUserId(Long.parseLong(adminId));
sysLog.setUrl(requestUri);
sysLog.setMethod(httpMethod);
sysLog.setOperator(userName);
sysLogService.save(sysLog);
break;
}
}
}
}
}
}