AOPを使用して、ユーザリクエストのパラメータを記録します

起因

本番環境では、エラーが発生し、振り返ってみることで、あなたは、インターフェイスやメソッドのエラーを見つけることができますが、引数がない場合は、問題を再現することはできませんので、リクエストの記録パラメータということ、質問を繰り返しすることが重要です

需要

図1は、方法及び印刷要求のパラメータ
2、及び関連するユーザは、リストタイプ(ロング)印刷パラメータがないパスワード

実装プロセス

1、AOPクラスを追加、実行モードセクションを使用

@Slf4j
@Aspect
@Component
public class ControllerLog {
    private static final ThreadLocal<Long> START_TIME_THREAD_LOCAL =
            new NamedThreadLocal<>("ThreadLocal StartTime");

    private static final ThreadLocal<Integer> ID_THREAD_LOCAL =
            new NamedThreadLocal<>("ThreadLocal ID");

    private static final ThreadLocal<String> LOG_PREFIX_THREAD_LOCAL =
            new NamedThreadLocal<>("ThreadLocal LogPrefix");

    /**
     * <li>Before       : 在方法执行前进行切面</li>
     * <li>execution    : 定义切面表达式</li>
     * <p>public * com.example.javadevelopmentframework.javadevelopmentframework.controller..*.*(..))
     * <li>public :匹配所有目标类的public方法,不写则匹配所有访问权限</li>
     * <li>第一个* :方法返回值类型,*代表所有类型 </li>
     * <li>第二个* :包路径的通配符</li>
     * <li>第三个..* :表示impl这个目录下所有的类,包括子目录的类</li>
     * <li>第四个*(..) : *表示所有任意方法名,..表示任意参数</li>
     * </p>
     *
     * @param
     */
    @Pointcut("execution(public * XXX.XXX.XXX.*.*.controller..*.*(..))")
    public void exectionMethod() {
    }


    @Before("exectionMethod()")
    public void doBefore(JoinPoint joinPoint) {
        START_TIME_THREAD_LOCAL.set(System.currentTimeMillis());
        // 接收到请求,记录请求内容
        StringBuilder argsDes = new StringBuilder();
        //获取方法名
        String className = joinPoint.getSignature().getDeclaringType().getSimpleName();
        String methodName = joinPoint.getSignature().getName();
        String logPrefix = className + "." + methodName + "()";
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Object[] args = joinPoint.getArgs();
        Method method = signature.getMethod();
        LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
        String[] paramNames = u.getParameterNames(method);
        if (args != null && paramNames != null) {
            argsDes.append(LogUtil.getMethodParams(signature, args, paramNames));
        }
        LOG_PREFIX_THREAD_LOCAL.set(logPrefix);
        int id = RandomUtil.randomInt();
        ID_THREAD_LOCAL.set(id);
        log.info("id={} =========开始请求:{},参数:{}", id, logPrefix, argsDes.toString());
    }

    @AfterReturning(pointcut = "exectionMethod()", returning = "rtn")
    public Object doAfter(Object rtn) {
        long endTime = System.currentTimeMillis();
        long begin = START_TIME_THREAD_LOCAL.get();
        if (rtn instanceof R) {
            R result = (R) rtn;
            if (result.getErrcode() != HttpStatus.OK.value()) {
                log.warn("请求异常:{},响应结果:{}", getLogPrefix(), rtn);
            }
        }
        log.info("id={} =========结束请求:{},耗时:{} ms", ID_THREAD_LOCAL.get(), getLogPrefix(), endTime - begin);
        destroyThreadLocal();
        return rtn;
    }

    private static String getLogPrefix() {
        return LOG_PREFIX_THREAD_LOCAL.get();
    }

    private static void destroyThreadLocal() {
        START_TIME_THREAD_LOCAL.remove();
        LOG_PREFIX_THREAD_LOCAL.remove();
        ID_THREAD_LOCAL.remove();
    }
}

2、LogUtil.getMethodParams実装方法

	public static StringBuilder getMethodParams(MethodSignature signature, Object[] args, String[] paramNames) {
        StringBuilder params = new StringBuilder();
        //密码类型的信息,不打印出来
        PasswordType passwordType = signature.getMethod().getAnnotation(PasswordType.class);
        if (null == passwordType) {
            for (int i = 0; i < args.length; i++) {
                //参数类型为List的参数也不打印值
                if (args[i] instanceof List) {
                    params.append(paramNames[i]).append("=").append("【List类型的参数不打印】").append(",");
                } else {
                    params.append(paramNames[i]).append("=").append(args[i]).append(",");
                }

            }
        } else {
            String[] fieldNames = passwordType.fieldNames();
            for (int i = 0; i < args.length; i++) {
                Map<String, Object> map = JsonUtil.objectToMap(args[i]);
                for (String fieldName : fieldNames) {
                    if (map != null && map.containsKey(fieldName) && null != map.get(fieldName)) {
                        map.put(fieldName, "*");
                    }
                }
                params.append(paramNames[i]).append("=").append(map).append(",");
            }
        }
        return params;
    }

3、@PasswordTypeノート、デフォルトのパスワードが、他の名前があるかもしれません

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PasswordType {
    String[] fieldNames() default {"password"};
}

4、@ PasswordTypeは例を使用して
、パスワードを変更するには、JSONのパラメータの受け渡しを

	@PasswordType(fieldNames = {"password","newPassword"})
    @PostMapping("/editPwd")
    public R changePwd(@Valid @RequestBody UserChangePwdParamDTO dto) {
       
    }

効果

04-09 15:24:12.245 INFO  [xxx.xxx.xxx.aop.ControllerLog] - id=1638566979 =========开始请求:XXXXController.getSetting(),参数:yxH=10572,
04-09 15:24:12.255 INFO  [xxx.xxx.xxx..aop.ControllerLog] - id=1638566979 =========结束请求:XXXXController.getSetting(),耗时:11 ms

リリース元の4件の記事 ウォンの賞賛0 ビュー35

おすすめ

転載: blog.csdn.net/m0_37453314/article/details/105411212