自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一種奇特的干掉 if..else 方式,Spring Boot+Aviator+Aop 挺有趣!

開發(fā)
從5.0.0版本開始,aviator升級(jí)成為了aviatorScript,成為一個(gè)高性能、輕量級(jí)寄宿于 JVM (包括 Android 平臺(tái))之上的腳本語言。

aviator本來是一個(gè)輕量級(jí)、高性能的基于JVM的表達(dá)式引擎。不過從5.0.0版本開始,aviator升級(jí)成為了aviatorScript,成為一個(gè)高性能、輕量級(jí)寄宿于 JVM (包括 Android 平臺(tái))之上的腳本語言。

根據(jù)官網(wǎng)的介紹,aviator支持的主要特性:

  • 支持?jǐn)?shù)字、字符串、正則表達(dá)式、布爾值、正則表達(dá)式等基本類型,完整支持所有 Java 運(yùn)算符及優(yōu)先級(jí)等。
  • 函數(shù)是一等公民,支持閉包和函數(shù)式編程
  • 內(nèi)置 bigint/decimal類型用于大整數(shù)和高精度運(yùn)算,支持運(yùn)算符重載得以讓這些類型使用普通的算術(shù)運(yùn)算符 +-*/ 參與運(yùn)算。
  • 完整的腳本語法支持,包括多行數(shù)據(jù)、條件語句、循環(huán)語句、詞法作用域和異常處理等。
  • 函數(shù)式編程結(jié)合 Sequence 抽象,便捷處理任何集合。
  • 輕量化的模塊系統(tǒng)。
  • 多種方式,方便地調(diào)用 Java 方法,完整支持 Java 腳本 API(方便從 Java 調(diào)用腳本)。
  • 豐富的定制選項(xiàng),可作為安全的語言沙箱和全功能語言使用。
  • 輕量化,高性能,ASM 模式下通過直接將腳本翻譯成 JVM 字節(jié)碼,解釋模式可運(yùn)行于 Android 等非標(biāo) Java 平臺(tái)。

使用場景包括:

  • 規(guī)則判斷及規(guī)則引擎
  • 公式計(jì)算
  • 動(dòng)態(tài)腳本控制
  • 集合數(shù)據(jù) ELT 等

一、Aviator的限制

  • 沒有if else、do while等語句,沒有賦值語句,僅支持邏輯表達(dá)式、算術(shù)表達(dá)式、三元表達(dá)式和正則匹配。
  • 不支持八進(jìn)制數(shù)字字面量,僅支持十進(jìn)制和十六進(jìn)制數(shù)字字面量。

二、aviator基本使用

1. 基本表達(dá)式

要使用aviator,只需要添加相應(yīng)依賴:

<dependency>
    <groupId>com.googlecode.aviator</groupId>
    <artifactId>aviator</artifactId>
    <version>5.3.3</version>
</dependency>

然后就可以進(jìn)行表達(dá)式求值了:

// 返回值為16
Long r = (Long) AviatorEvaluator.execute("2 * (3 + 5)");

為了提升性能,往往先編譯表達(dá)式,然后可以反復(fù)執(zhí)行,進(jìn)行表達(dá)式求值:

Expression expression = AviatorEvaluator.compile("2 * (3 + 5)");
Long r = (Long) expression.execute();

aviator支持?jǐn)?shù)字、字符串、布爾值等基本數(shù)據(jù)類型,數(shù)字類型值都當(dāng)作long或double類型處理。

aviator表達(dá)式支持大部分的運(yùn)算操作符,如常用的算術(shù)運(yùn)算操作符(+、-、*、/、%)、邏輯運(yùn)算操作符(&&、||、!)、比較運(yùn)算操作符(>、>=、==、!=、<、<=)、位運(yùn)算操作符(&、|、^、<<、>>)和優(yōu)先級(jí)操作符,還支持三元操作表達(dá)(?:)、正則表達(dá)式(=~)。

一些例子:

// 返回 hello world
    String r = (String) AviatorEvaluator.execute("'hello' + ' world'");
    
    // 返回 true
    Boolean r = (Boolean) AviatorEvaluator.execute("100 > 80 && 30 < 40");
    
    // 三元表達(dá)式,返回 30
    Long r = (Long) AviatorEvaluator.execute("100 > 80 ? 30 : 40");
    
    // 正則表達(dá)式,正則表達(dá)式放在//之間,返回 true
    Boolean r = (Boolean) AviatorEvaluator.execute("'hello' =~ /[\\w]+/");

2. 表達(dá)式變量

跟其他表達(dá)式引擎一樣,aviator也是支持表達(dá)式求值時(shí)傳入?yún)?shù)的:

Long a = 12L;
Boolean r = (Boolean) AviatorEvaluator.exec("a > 10", a);

參數(shù)也可以是一個(gè)列表,如下:

List<Long> a = new ArrayList<>();
a.add(12L);
a.add(20L);
Boolean r = (Boolean) AviatorEvaluator.exec("a[0] > 10", a);

也可以是一個(gè)對象:

public static class Person {
        private String name;
        private Integer age;
    }

Person a = new Person("movee", 25);
Boolean r = (Boolean) AviatorEvaluator.exec("a.age > 10", a);

跟一般地,aviator會(huì)將參數(shù)放到一個(gè)map中:

Map<String, Object> env = new HashMap<>();
env.put("person", new Person("movee", 25));
env.put("a", 20L);
Object result = AviatorEvaluator.execute("person.name", env);

這樣一來,aviator可以非常方便的從json字符串中提取子json字符串:

String jsonStr = """
        {
            "a": {
                "b": [
                        {
                            "x": 3
                        },
                        {
                            "x": 4
                        }
                    ]
            }
        }
        """;


    JSONObject jsonObj = new JSONObject(jsonStr);
    // 結(jié)果返回 3
    Object value = AviatorEvaluator.execute("a.b[0]['x']", jsonObj.toMap());

3. 使用函數(shù)

aviator已經(jīng)提供了很多開箱即用的函數(shù)了:

// 返回4
    Long r = (Long) AviatorEvaluator.execute("math.round(4.3)");
    
    // 返回5
    Long r = (Long) AviatorEvaluator.execute("string.length('hello')");
    
    // 返回一個(gè)ArrayList:[1,2,3]
    Object r = AviatorEvaluator.execute("seq.list(1,2,3)");

我們也可以自定義一個(gè)java函數(shù),自己編寫一個(gè)類,繼承aviator的AbstractFunction類,然后實(shí)現(xiàn)相應(yīng)的方法即可:

public class AddFunction extends AbstractFunction {

        /**
         * 函數(shù)實(shí)現(xiàn)的功能
         * @param env 參數(shù)
         * @param arg1 函數(shù)的第一個(gè)參數(shù)
         * @param arg2 函數(shù)的第二個(gè)參數(shù)
         * @return 返回值
         */
        @Override
        public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
            long num1 = FunctionUtils.getNumberValue(arg1, env).longValue();
            long num2 = FunctionUtils.getNumberValue(arg2, env).longValue();
            return AviatorLong.valueOf(num1+num2);
        }

        /**
         * 注冊到aviator的名字
         * @return 函數(shù)名字
         */
        @Override
        public String getName() {
            return"add";
        }
    }

然后就可以注冊到aviator中,像使用內(nèi)置函數(shù)一樣使用自定義函數(shù):

// 注冊
    AviatorEvaluator.addFunction(new AddFunction());
    
    // 使用
    long sum = (Long) AviatorEvaluator.getInstance().execute("add(3,4)");

4. aviatorScript腳本

aviator已經(jīng)升級(jí)為一個(gè)腳本語言,所以不僅僅能進(jìn)行表達(dá)式求值,還可以執(zhí)行腳本程序。

// 返回1
    Object r = AviatorEvaluator.execute("if (true) { return 1; } else { return 2; }");

aviatorScript腳本一般放到獨(dú)立的腳本文件中,文件名后綴一般為.av。

例如,我們編寫一個(gè)hello.av腳本文件,內(nèi)容為:

if (a > 10) {
    return 10;
} else {
    return a;
}

然后就可以執(zhí)行該腳本文件,并傳入?yún)?shù)a的值:

Map<String, Object> env = new HashMap<>();
    env.put("a", 30);
    Expression exp = AviatorEvaluator.getInstance().compileScript("./hello.av", true);
    Object result = exp.execute(env);

三、實(shí)操

利用aviator+aop實(shí)現(xiàn)參數(shù)校驗(yàn)。

1. pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springboot-demo</artifactId>
        <groupId>com.et</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>Aviator</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--AOP-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <!--Aviator-->
        <dependency>
            <groupId>com.googlecode.aviator</groupId>
            <artifactId>aviator</artifactId>
            <version>3.3.0</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.56</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8.1</version>
        </dependency>

    </dependencies>
</project>

2. controller

在方法上加上aviator校驗(yàn)規(guī)則:

package com.et.controller;

import com.et.annotation.Check;
import com.et.exception.HttpResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
publicclass HelloWorldController {
    @RequestMapping("/hello")
    public Map<String, Object> showHelloWorld(){
        Map<String, Object> map = new HashMap<>();
        map.put("msg", "HelloWorld");
        return map;
    }
    @GetMapping("/simple")
    @Check(ex = "name != null", msg = "Name cannot be empty")
    @Check(ex = "age != null", msg = "Age cannot be empty")
    @Check(ex = "age > 18", msg = "Age must be over 18 years old")
    @Check(ex = "phone != null", msg = "phone cannot be empty")
    @Check(ex = "phone =~ /^(1)[0-9]{10}$/", msg = "The phone number format is incorrect")
    @Check(ex = "string.startsWith(phone,\"1\")", msg = "The phone number must start with 1")
    @Check(ex = "idCard != null", msg = "ID number cannot be empty")
    @Check(ex = "idCard =~ /^[1-9]\\d{5}[1-9]\\d{3}((0[1-9])||(1[0-2]))((0[1-9])||(1\\d)||(2\\d)||(3[0-1]))\\d{3}([0-9]||X)$/", msg = "ID number format is incorrect")
    @Check(ex = "gender == 1", msg = "sex")
    @Check(ex = "date =~ /^[1-9][0-9]{3}-((0)[1-9]|(1)[0-2])-((0)[1-9]|[1,2][0-9]|(3)[0,1])$/", msg = "Wrong date format")
    @Check(ex = "date > '2019-12-20 00:00:00:00'", msg = "The date must be greater than 2019-12-20")
    public HttpResult simple(String name, Integer age, String phone, String idCard, String date) {
        System.out.println("name = " + name);
        System.out.println("age = " + age);
        System.out.println("phone = " + phone);
        System.out.println("idCard = " + idCard);
        System.out.println("date = " + date);
        return HttpResult.success();
    }
}

3. annotation

單個(gè)規(guī)則注解:

package com.et.annotation;

import java.lang.annotation.*;


@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
//add more on a method
@Repeatable(CheckContainer.class)
public @interface Check {

   String ex() default "";

   String msg() default "";

}

多個(gè)規(guī)則注解:

package com.et.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckContainer {

   Check[] value();
}

AOP攔截注解:

package com.et.annotation;

import com.et.exception.UserFriendlyException;
import com.googlecode.aviator.AviatorEvaluator;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.*;


@Aspect
@Configuration
publicclass AopConfig {

   /**
    * Aspects monitor multiple annotations, because one annotation is Check and multiple annotations are compiled to CheckContainer
    */
   @Pointcut("@annotation(com.et.annotation.CheckContainer) || @annotation(com.et.annotation.Check)")
   public void pointcut() {
   }

   @Before("pointcut()")
   public Object before(JoinPoint point) {
      //get params
      Object[] args = point.getArgs();
      //get param name
      Method method = ((MethodSignature) point.getSignature()).getMethod();
      LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
      String[] paramNames = u.getParameterNames(method);

      CheckContainer checkContainer = method.getDeclaredAnnotation(CheckContainer.class);
      List<Check> value = new ArrayList<>();

      if (checkContainer != null) {
         value.addAll(Arrays.asList(checkContainer.value()));
      } else {
         Check check = method.getDeclaredAnnotation(Check.class);
         value.add(check);
      }
      for (int i = 0; i < value.size(); i++) {
         Check check = value.get(i);
         String ex = check.ex();
         //In the rule engine, null is represented by nil
         ex = ex.replaceAll("null", "nil");
         String msg = check.msg();
         if (StringUtils.isEmpty(msg)) {
            msg = "server exception...";
         }

         Map<String, Object> map = new HashMap<>(16);
         for (int j = 0; j < paramNames.length; j++) {
            //Prevent index out of bounds
            if (j > args.length) {
               continue;
            }
            map.put(paramNames[j], args[j]);
         }
         Boolean result = (Boolean) AviatorEvaluator.execute(ex, map);
         if (!result) {
            thrownew UserFriendlyException(msg);
         }
      }
      returnnull;
   }
}

全局異常攔截:

package com.et.exception;

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import javax.servlet.http.HttpServletRequest;


@Configuration
@ControllerAdvice
publicclass DefaultGlobalExceptionHandler extends ResponseEntityExceptionHandler {
   privatestaticfinal Logger LOGGER = LoggerFactory.getLogger(DefaultGlobalExceptionHandler.class);

   @Override
   protected ResponseEntity<Object> handleExceptionInternal(Exception ex, @Nullable Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
      HttpResult httpResult = HttpResult.failure(status.is5xxServerError() ? ErrorCode.serverError.getDesc() : ErrorCode.paramError.getDesc());
      LOGGER.error("handleException, ex caught, contextPath={}, httpResult={}, ex.msg={}", request.getContextPath(), JSON.toJSONString(httpResult), ex.getMessage());
      returnsuper.handleExceptionInternal(ex, httpResult, headers, status, request);
   }

   @ExceptionHandler(Exception.class)
   protected ResponseEntity handleException(HttpServletRequest request, Exception ex) {
      boolean is5xxServerError;
      HttpStatus httpStatus;
      HttpResult httpResult;
      if (ex instanceof UserFriendlyException) {
         UserFriendlyException userFriendlyException = (UserFriendlyException) ex;
         is5xxServerError = userFriendlyException.getHttpStatusCode() >= 500;
         httpStatus = HttpStatus.valueOf(userFriendlyException.getHttpStatusCode());
         httpResult = HttpResult.failure(userFriendlyException.getErrorCode(), userFriendlyException.getMessage());
      } elseif (ex instanceof IllegalArgumentException) {
         // Spring assertions are used in parameter judgment. requireTrue will throw an IllegalArgumentException. The client cannot handle 5xx exceptions, so 200 is still returned.
         httpStatus = HttpStatus.OK;
         is5xxServerError = false;
         httpResult = HttpResult.failure("Parameter verification error or data abnormality!");
      } else {
         httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
         is5xxServerError = true;
         httpResult = HttpResult.failure(ErrorCode.serverError.getDesc());
      }
      if (is5xxServerError) {
         LOGGER.error("handleException, ex caught, uri={}, httpResult={}", request.getRequestURI(), JSON.toJSONString(httpResult), ex);
      } else {
         LOGGER.error("handleException, ex caught, uri={}, httpResult={}, ex.msg={}", request.getRequestURI(), JSON.toJSONString(httpResult), ex.getMessage());
      }
      returnnew ResponseEntity<>(httpResult, httpStatus);
   }

}

責(zé)任編輯:趙寧寧 來源: 程序員小富
相關(guān)推薦

2025-03-12 14:09:56

2024-04-01 08:38:57

Spring@AspectAOP

2019-04-25 14:25:24

Spring Bootif elseJava

2022-08-18 09:38:02

Spring跨域

2021-06-11 00:11:23

GPS數(shù)據(jù)協(xié)議

2013-05-22 15:31:07

AOP的CGlib實(shí)現(xiàn)

2014-12-01 09:54:40

JavaScript

2024-04-26 08:58:54

if-else代碼JavaSpring

2022-02-17 13:39:09

AOP接口方式

2020-11-09 14:03:51

Spring BootMaven遷移

2023-07-27 08:14:29

2015-05-06 10:05:22

javajava框架spring aop

2021-04-20 08:02:08

業(yè)務(wù)數(shù)據(jù)用戶

2024-01-12 16:20:04

2023-01-26 23:46:15

2022-06-06 15:44:24

大數(shù)據(jù)數(shù)據(jù)分析思維模式

2021-03-01 23:26:41

日志Spring BootAOP

2022-07-28 11:29:23

數(shù)據(jù)安全數(shù)據(jù)令牌化

2023-03-07 15:08:57

2025-01-08 09:55:37

Spring接口數(shù)據(jù)庫
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)