#7注解+切面AOP+枚举类记录日志

 

目录

1、分析

2、示例(可直接复制修改使用)

2.1、注解UserLog

2.2、被记录方法:

2.3、枚举类:

2.4、UserLogUtil:

2.5、切面

2.6、UserLogEvaluationContext


 


 

1、分析

通过枚举类将每个方法需要记录的日志内容单独存储,降低了耦合度,增加了可扩展性。

通过注解的方式切入具体的方法,在返回成功后再进行日志记录。

将参数注入到StandardEvaluationContext上下文中,通过#name的方式来获取参数,进行必要参数的日志记录。

将自定义的增强方法注册到Spel上下文中,可以在Spel表达式中进行调用。

2、示例(可直接复制修改使用)

2.1、注解UserLog

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Target(ElementType.METHOD)
public @interface UserLog {
    UserLogEnum value();
}

2.2、被记录方法:

@UserLog(UserLogEnum.NEW_ADJUST_TRADE_AUDIT)
public int insertAdjustTradeRequest(AdjustTradeRequest adjustTradeRequest, String methodName, String modelName) 

2.3、枚举类:

NEW_ADJUST_TRADE_AUDIT(
	 "''",
        "#modelName",
        "(#aspectMethodName=='insertAdjustTradeRequest'?'新增':'修改')+'交易调整请求信息'+#convertDescription(',id: ',#adjustTradeRequest.getId())” )

private final String methodParams;
private final String modelName;
private final String description;

UserLogEnum(String methodParams, String modelName, String description) {
    this.methodParams = methodParams;
    this.modelName = modelName;
    this.description = description;
}

#是Spel表达式中获取方法参数的意思,对于实体直接使用.即可获得其属性,

在Spel表达式中字符串要以’’单引号做为开始和结束,

编译器中换行的+号不包裹在枚举类属性的“”双引号中(此处因为使用了String做为其属性所以使用双引号

Spel中的表达式连接直接使用+

convertDescription是注册到Spel上下文中的方法

aspectMethodName 是通过上下文中的setVariables方法来注册的。

 

2.4、UserLogUtil:

public class UserLogUtil {
	
	private static UserLogEvaluationContext userLogEvaluationContext;

    /**
     * 获取单例的上下文
     */
    public UserLogEvaluationContext getUserLogEvaluationContext() {
        if (userLogEvaluationContext == null){
            userLogEvaluationContext = new UserLogEvaluationContext();
        }
        return userLogEvaluationContext;
    }

    public UserLogUtil() throws NoSuchMethodException {
        this.getUserLogEvaluationContext();
      
        userLogEvaluationContext.registerFunction("convertDescription", this.getClass().getDeclaredMethod("convertDescription",String.class,Object.class));
    }
	public static <T> String convertDescription(String description,T fieldValue) throws ParseException {
      if (ObjectUtils.isEmpty(fieldValue)) {
          return "";
      }
      if(fieldValue instanceof Date) {
          return description + formatDate(fieldValue.toString());
      }
      return description  + fieldValue ;
    }
}

2.5、切面

@AfterReturning(value = "@annotation(userLog)",returning = "res")
public void doUserLog(JoinPoint joinPoint, UserLog userLog,Object res){
    modelName=null;
    methodParams = null;
    description = null;
    Method method ;
    Object[] args ;
    try{
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature)signature;
        Method targetMethod = methodSignature.getMethod();
        method = joinPoint.getTarget().getClass().getDeclaredMethod(signature.getName(), targetMethod.getParameterTypes());
        args = joinPoint.getArgs();
    } catch (Exception e){
        return;
    }

    String userName = SecurityContextHolder.getContext().getAuthentication().getName();
    try {
        parseExpression(method, args, userLog);
    } catch (Exception e) {   
  return;
    }
//记录日志
}
private void parseExpression(Method method, Object[] args, UserLog userLog) throws NoSuchFieldException, IllegalAccessException {
    // 获取被拦截方法参数名列表
    ParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
    String[] parametersOfMethod = discoverer.getParameterNames(method);
List<String> parametersList = new ArrayList<>(Arrays.asList(parametersOfMethod));
    List<Object> argsList = new ArrayList<>(Arrays.asList(args));
userLogUtil.getUserLogEvaluationContext().setVariables(parametersList, argsList);
    // SPEL解析
    ExpressionParser parser = new SpelExpressionParser();
    modelName =    parser.parseExpression(userLog.value().getModelName()).getValue(userLogUtil.getUserLogEvaluationContext(), String.class);
    methodParams = parser.parseExpression(userLog.value().getMethodParams()).getValue(userLogUtil.getUserLogEvaluationContext(), String.class);
    description = parser.parseExpression(userLog.value().getDescription()).getValue(userLogUtil.getUserLogEvaluationContext(), String.class);
    // 将刚刚加的参数释userLogUtil.getUserLogEvaluationContext().removeVariables(parametersOfMethod);
}

2.6、UserLogEvaluationContext

public class UserLogEvaluationContext extends StandardEvaluationContext {
public UserLogEvaluationContext() {
      super();
  }
  public void setVariables(List<String> names, List<Object> args){
      for (int i = 0; i < names.size(); i++){
        this.setVariable(names.get(i), args.get(i));
      }
  }
public void removeVariables(String[] names) throws NoSuchFieldException, IllegalAccessException {
    if (names.length == 0){
        return;
    }
    // 反射获取当前实例的variables属性
    Field field = this.getClass().getSuperclass().getDeclaredField("variables");
    field.setAccessible(true);
    Map<String, Object> originVariables = (Map<String, Object>) field.get(this);
    for (String name: names){
        originVariables.remove(name);
    }
    field.set(this, originVariables);
    field.setAccessible(false);
  }
}

 

 往期精彩:

#2Vite+Vue3+SpringMVC前后端分离 解决跨域问题和session每次请求不一致问题-CSDN博客文章浏览阅读1.1k次,点赞37次,收藏15次。Vite+Vue3+SpringMVC前后端分离通过vite/nginx解决跨域问题和session一致性问题https://blog.csdn.net/weixin_42718399/article/details/135388463?spm=1001.2014.3001.5502
#3Jenkins(Windows环境)版本升级、迁移、负载均衡、双机器同步与备份-CSDN博客文章浏览阅读993次,点赞28次,收藏17次。Jenkins(Windows环境)版本升级、迁移、负载均衡、双机器同步与备份https://blog.csdn.net/weixin_42718399/article/details/135404525?spm=1001.2014.3001.5502
#4详解@RequestParam、@RequestBody和@PathVariable-CSDN博客文章浏览阅读933次,点赞26次,收藏19次。详解@RequestParam @RequestBody和@PathVariablehttps://blog.csdn.net/weixin_42718399/article/details/135475436?spm=1001.2014.3001.5502
#5解析filter为什么不能注入bean和解决办法以及filter、interceptor、aspect之间的执行顺序-CSDN博客文章浏览阅读961次,点赞35次,收藏7次。filter过滤器为什么不能注入bean以及解决办法https://blog.csdn.net/weixin_42718399/article/details/135517565?spm=1001.2014.3001.5502
#6解析@PreAuthorize以及其中的Spel-CSDN博客文章浏览阅读1.1k次,点赞41次,收藏18次。#6解析@PreAuthorize以及其中的Spelhttps://blog.csdn.net/weixin_42718399/article/details/135558235?spm=1001.2014.3001.5502

 

  • 22
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

火鸡nobug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值