创建自定义注解接口
package com.example.lambda.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author: WZ
* @create: 2022-10-17 09:18
* @description: 1、自定义日志注解接口
* @Target(ElementType.TYPE) // 接口、类、枚举、注解
* @Target(ElementType.FIELD) // 字段、枚举的常量
* @Target(ElementType.METHOD) //方法
* @Target(ElementType.PARAMETER) //方法参数
* @Target(ElementType.CONSTRUCTOR) //构造函数
* @Target(ElementType.LOCAL_VARIABLE)//局部变量
* @Target(ElementType.ANNOTATION_TYPE)//注解
* @Target(ElementType.PACKAGE) ///包
* @Retention注解: 这个参数有三种,一般默认第三种
*
* 1. RetentionPolicy.SOURCE —— 这种类型的Annotations只在源代码级别保留,
*
* 编译时就会被忽略
*
* 2. RetentionPolicy.CLASS —— 这种类型的Annotations编译时被保留,在class文件中存在,
*
* 但JVM将会忽略
*
* 3. RetentionPolicy.RUNTIME —— 这种类型的Annotations将被JVM保留,
*
* 所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。
* 第二种写法:
* @Documented 和 @Order(优先级:数字越小优先级越高)
* @Documented 注解表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的. 但如果声明注解时指定了 @Documented,则它会被 javadoc 之类的工具处理, 所以注解类型信息也会被包括在生成的文档中。
* @Order标记定义了组件的加载顺序,这个标记包含一个value属性。属性接受整形值。 如:1,2 等等。值越小拥有越高的优先级。
*
* Ordered.HIGHEST_PRECEDENCE这个属性值是最高优先级的属性,它的值是-2147483648,对应的最低属性值是Ordered.LOWEST_PRECEDENCE,它的值是2147483647。
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
/**
* 模块
*/
String title() default "";
/**
* 是否保存请求的参数
*/
boolean isSaveRequestData() default true;
/**
* 是否保存响应的参数
*/
boolean isSaveResponseData() default true;
}
创建LogAspect类对自定义注解进行操作
package com.example.lambda.annotation;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.Map;
/**
* 操作日志记录处理
*
* @author: WZ
* @create: 2022-10-17 09:18
* @description: 2、自定义注解操作
*/
@Aspect
@Component
@Slf4j
public class LogAspect {
/**
* 配置织入点
*/
@Pointcut("@annotation(com.example.lambda.annotation.Log)")
public void logPointCut() {
}
/**
* 处理完请求后执行
*
* @param joinPoint 切点
*/
@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
handleLog(joinPoint, controllerLog, null, jsonResult);
}
/**
* 拦截异常操作
*
* @param joinPoint 切点
* @param e 异常
*/
@AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
handleLog(joinPoint, controllerLog, e, null);
}
protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
try {
//获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
Signature signature = joinPoint.getSignature();
//获取传入目标方法的参数对象
Object[] args = joinPoint.getArgs();
//获取被代理的对象
Object target = joinPoint.getTarget();
//获取代理的对象
Object aThis = joinPoint.getThis();
//接口请求方式
String method = getHttpMethod();
String params = argsArrayToString(joinPoint.getArgs());
/**
* 是否保存请求的参数
*/
if (controllerLog.isSaveRequestData()) {
}
/**
* 是否保存响应的参数
*/
if (controllerLog.isSaveResponseData()) {
}
log.info("---------------------signature:{}", signature);
log.info("---------------------params:{}", params);
log.info("---------------------target:{}", target);
log.info("---------------------aThis:{}", aThis);
log.info("---------------------method:{}", method);
log.info("---------------------异常信息:{}", e);
log.info("---------------------jsonResult:{}", jsonResult);
} catch (Exception exp) {
// 记录本地异常日志
log.error("==前置通知异常==");
log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace();
}
}
/**
* 获取请求方式
*
* @return
*/
public static ServletRequestAttributes getAttributes() {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
return (ServletRequestAttributes) attributes;
}
public static String getHttpMethod() {
String method = getAttributes().getRequest().getMethod();
return method;
}
/**
* 参数拼装
*/
private String argsArrayToString(Object[] paramsArray) {
String params = "";
if (paramsArray != null && paramsArray.length > 0) {
for (Object o : paramsArray) {
if (o != null && !isFilterObject(o)) {
try {
Object jsonObj = JSONObject.toJSONString(o);
params += jsonObj.toString() + " ";
} catch (Exception e) {
}
}
}
}
return params.trim();
}
/**
* 判断是否需要过滤的对象。
*
* @param o 对象信息。
* @return 如果是需要过滤的对象,则返回true;否则返回false。
*/
@SuppressWarnings("rawtypes")
public boolean isFilterObject(final Object o) {
Class<?> clazz = o.getClass();
if (clazz.isArray()) {
return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
} else if (Collection.class.isAssignableFrom(clazz)) {
Collection collection = (Collection) o;
for (Object value : collection) {
return value instanceof MultipartFile;
}
} else if (Map.class.isAssignableFrom(clazz)) {
Map map = (Map) o;
for (Object value : map.entrySet()) {
Map.Entry entry = (Map.Entry) value;
return entry.getValue() instanceof MultipartFile;
}
}
return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
|| o instanceof BindingResult;
}
}
使用自定义注解@Log
@PostMapping("test2")
@Log(title = "测试自定义日志post")
public Object test1(@RequestBody Map map) {
return new HashMap<String,Object>(){
{
put("name", "张三");
put("age", 18);
put("sex", "男");
}
};
}