AOP技术限制后端接口调用次数

系列文章目录

第一章 AOP后端控制接口调用次数
第二章 前后端配合控制接口调用次数


@[TOC](AOP技术限制后端接口调用次数)

背景

最近工作上在做安全管控的需求,需要限制一些接口的调用次数,一般可以采用两种方案,一种是将在后端使用AOP进行限制,另外一种是在后端开一个http接口,前端每次调用的时候,先调用安全管控的接口,接口返回成功的情况下,才进行实际业务操作。本文主要总结使用AOP限制次数踩的一些坑


一、整体方案

plan
整体方案如上图所示,使用AOP技术,在原有的基础上,增加规则判断。

二、AOP

1.反射解析属性

getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段。
getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段。
同样类似的还有getConstructors()和getDeclaredConstructors()、getMethods()和getDeclaredMethods(),这两者分别表示获取某个类的方法、构造函数。

private Object parseFieldValue(JoinPoint jp, String filed){
        Signature signature = jp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        Object[] args = jp.getArgs();
        String[] parameterNames = methodSignature.getParameterNames();
        Class[] parameterTypes = method.getParameterTypes();
        String[] filedNames = filed.split("\\.");
        for (int i = 0; i < parameterNames.length; i++){
            if (!parameterNames[i].equals(filedNames[0])){
                continue;
            }

            if (filedNames.length == 1){
                return args[i];
            }

            try{
                return parseFiled(parameterTypes[i], args[i], filedNames, 1);
            } catch (IllegalAccessException e1){
                e1.printStackTrace();
            }
        }

        throw new IllegalArgumentException("解析field失败");
    }

    private Object parseFiled(Class<?> parameterType, Object targetObject, String[] filedNames, int index) throws IllegalAccessException{
        try{
            Field field = parameterType.getDeclaredField(filedNames[index]);
            field.setAccessible(true);
            Object result = field.get(targetObject);
            if (filedNames.length == index){
                return result;
            } else {
                return parseFiled(result.getClass(), result, filedNames, ++index);
            }
        } catch (NoSuchFieldException e) {
            return parseFiled(parameterType.getSuperclass(), targetObject, filedNames, index);
        }
    }

2.SpEL解析属性

private <T> T parseSpel(ProceedingJoinPoint jp, String spel, Class<T> clazz, T defaultResult) {
        ExpressionParser parser = new SpelExpressionParser();
        Signature signature = jp.getSignature();
        MethodSignature methodSignature = null;
        if (signature instanceof MethodSignature){
            methodSignature = (MethodSignature) signature;
        }
        if (methodSignature == null){
            return defaultResult;
        }

        Method method = methodSignature.getMethod();
        String[] params = methodSignature.getParameterNames();
        Object[] arguments = jp.getArgs();
        EvaluationContext context = new StandardEvaluationContext();
        for (int len = 0; len < params.length; len++) {
            context.setVariable(params[len], arguments[len]);
        }
        try {
            Expression expression = parser.parseExpression(spel);
            return expression.getValue(context, clazz);
        } catch (Exception e) {
            return defaultResult;
        }
    }

3.下载接口

附件下载的时候,由于下载直接是浏览器控制,所以返回特定的错误,或者返回null,对于用户的提示效果都不太好。可以通过页面跳转到固定的错误页面,或者直接html的方式进行解决。

HttpHeaders headers = new HttpHeaders();
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
headers.add("Content-Type", "text/html;charset=utf-8");
String content = "<!DOCTYPE html>\n" +
                "<html>\n" +
                "    <head>\n" +
                "        <meta charset=\"UTF-8\">\n" +
                "        <title>xxx失败</title>\n" +
                "    </head>\n" +
                "\n" +
                "    <body>\n" +
                "        <h2>xxx,请联系管理员进行配置!</h2>\n" +
                "    </body>\n" +
                "</html>";
byte[] data = content.getBytes("UTF-8");
ResponseEntity.status(HttpStatus.OK)
                .headers(headers)
                .contentLength(data.length)
                .body(data);

4.预览接口

项目上面预览使用的viewer.js来做的,直接url绑定到img上面,所以这个根本上就没有好的方法给用户进行提示,只能在前端进行改造。

总结

涉及前端到类似的方案评审的时候,需要拉上前端的同事,自己本来是前端小白,经验有限,临时改方案,增加自己的工作量,吃力不讨好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值