SoFunction
Updated on 2025-03-03

SpringBoot integrated Aviator to implement code engineering for parameter verification

1.What is aviator?

Aviator is a high-performance, lightweight Java language implementation expression evaluation engine, mainly used for dynamic evaluation of various expressions. There are already many open source available java expression evaluation engines, so why do you still need Avaitor? The design goal of Aviator isLightweightandhigh performanceCompared with the bulkiness of Groovy and JRuby, Aviator is very small, and the dependency package is only 450K, and if it is not considered a dependency package, it is only 70K; of course, Aviator's syntax is limited, it is not a complete language, but just a small collection of languages. Secondly, the implementation idea of ​​Aviator is very different from other lightweight evaluators. Other evaluators are generally run through explanations, while Aviator directly uses expressions.Compile into Java bytecode, leave it to the JVM for execution. Simply put, Aviator is positioned between a heavyweight scripting language like Groovy and a lightweight expression engine like IKExpression.

Features of Aviator

  • Most operators are supported, including arithmetic operators, relational operators, logical operators, bit operators, regular matching operators (=~), ternary expressions?: , and support the operator's priority and bracket-forced priority. For details, please see the operator list below.
  • Supports large integer and precision operations (introduced in version 2.3.0)
  • Supports function calls and custom functions
  • Built-in support for regular expression matching, similar to Ruby and Perl's matching syntax, and supports Ruby's $digit pointing to matching grouping.
  • Automatic type conversion. When performing an operation, the operand type will be automatically judged and the corresponding conversion will be performed. If the conversion cannot be converted, the exception will be thrown.
  • Supports incoming variables, and supports similar nested variable access.
  • Functional style seq library, operation sets and arrays
  • Excellent performance

Aviator limitations

  • There are no if else, do while and other statements, no assignment statements, only logical expressions, arithmetic expressions, ternary expressions and regular matching are supported.
  • Octal numeric literals are not supported, only decimal and hexadecimal numeric literals are supported.

Use scenarios

  • Rule judgment and rule engine
  • Formula calculation
  • Dynamic script control

2. Code Engineering

Purpose of the experiment

Use aviator+aop to implement parameter verification

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="/POM/4.0.0"
         xmlns:xsi="http:///2001/XMLSchema-instance"
         xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.">
    <parent>
        <artifactId>springboot-demo</artifactId>
        <groupId></groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
 
    <artifactId>Aviator</artifactId>
 
    <properties>
        <>8</>
        <>8</>
    </properties>
    <dependencies>
        <dependency>
            <groupId></groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
 
        <dependency>
            <groupId></groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId></groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId></groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--AOP-->
        <dependency>
            <groupId></groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
 
        <!--Aviator-->
        <dependency>
            <groupId></groupId>
            <artifactId>aviator</artifactId>
            <version>3.3.0</version>
        </dependency>
 
        <dependency>
            <groupId></groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.56</version>
        </dependency>
 
        <dependency>
            <groupId></groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8.1</version>
        </dependency>
 
    </dependencies>
</project>

controller

Adding the injury aviator verification rule to the method

package ;
 
import ;
import ;
import ;
import ;
import ;
 
import ;
import ;
 
@RestController
public class HelloWorldController {
    @RequestMapping("/hello")
    public Map<String, Object> showHelloWorld(){
        Map<String, Object> map = new HashMap<>();
        ("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 = "(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) {
        ("name = " + name);
        ("age = " + age);
        ("phone = " + phone);
        ("idCard = " + idCard);
        ("date = " + date);
        return ();
    }
}

annotation

Single rule annotation

package ;
 
import .*;
 
 
@Target({, , })
@Retention()
//add more on a method
@Repeatable()
public @interface Check {
 
   String ex() default "";
 
   String msg() default "";
 
}

Multiple rule notes

package ;
 
import ;
import ;
import ;
import ;
 
 
@Target({, , })
@Retention()
public @interface CheckContainer {
 
   Check[] value();
}

AOP Intercept Annotation

package ;
 
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
 
import ;
import .*;
 
 
@Aspect
@Configuration
public class AopConfig {
 
   /**
    * Aspects monitor multiple annotations, because one annotation is Check and multiple annotations are compiled to CheckContainer
    */
   @Pointcut("@annotation() || @annotation()")
   public void pointcut() {
   }
 
   @Before("pointcut()")
   public Object before(JoinPoint point) {
      //get params
      Object[] args = ();
      //get param name
      Method method = ((MethodSignature) ()).getMethod();
      LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
      String[] paramNames = (method);
 
      CheckContainer checkContainer = ();
      List<Check> value = new ArrayList<>();
 
      if (checkContainer != null) {
         ((()));
      } else {
         Check check = ();
         (check);
      }
      for (int i = 0; i < (); i++) {
         Check check = (i);
         String ex = ();
         //In the rule engine, null is represented by nil
         ex = ("null", "nil");
         String msg = ();
         if ((msg)) {
            msg = "server exception...";
         }
 
         Map<String, Object> map = new HashMap<>(16);
         for (int j = 0; j < ; j++) {
            //Prevent index out of bounds
            if (j > ) {
               continue;
            }
            (paramNames[j], args[j]);
         }
         Boolean result = (Boolean) (ex, map);
         if (!result) {
            throw new UserFriendlyException(msg);
         }
      }
      return null;
   }
}

Global exception interception

package ;
 
import ;
import org.;
import org.;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
 
import ;
 
 
@Configuration
@ControllerAdvice
public class DefaultGlobalExceptionHandler extends ResponseEntityExceptionHandler {
   private static final Logger LOGGER = ();
 
   @Override
   protected ResponseEntity<Object> handleExceptionInternal(Exception ex, @Nullable Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
      HttpResult httpResult = (status.is5xxServerError() ? () : ());
      ("handleException, ex caught, contextPath={}, httpResult={}, ={}", (), (httpResult), ());
      return (ex, httpResult, headers, status, request);
   }
 
   @ExceptionHandler()
   protected ResponseEntity handleException(HttpServletRequest request, Exception ex) {
      boolean is5xxServerError;
      HttpStatus httpStatus;
      HttpResult httpResult;
      if (ex instanceof UserFriendlyException) {
         UserFriendlyException userFriendlyException = (UserFriendlyException) ex;
         is5xxServerError = () >= 500;
         httpStatus = (());
         httpResult = ((), ());
      } else if (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 = ;
         is5xxServerError = false;
         httpResult = ("Parameter verification error or data abnormality!");
      } else {
         httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
         is5xxServerError = true;
         httpResult = (());
      }
      if (is5xxServerError) {
         ("handleException, ex caught, uri={}, httpResult={}", (), (httpResult), ex);
      } else {
         ("handleException, ex caught, uri={}, httpResult={}, ={}", (), (httpResult), ());
      }
      return new ResponseEntity<>(httpResult, httpStatus);
   }
 
}

The above are just some key codes. Please refer to the code repository below.

Code Repository

  • /Harries/springboot-demo(aviator)

3. Test

  • Start Spring Boot app
  • Visit http://127.0.0.1:8088/simple?name=jack&age=12
  • Return to the verification information{"status":false,"code":4,"message":"Age must be over 18 years old","entry":null}

4. Quotation

/killme2008/aviatorscript/blob/master/

The above is the detailed content of the code project for SpringBoot integrated Aviator to implement parameter verification. For more information about SpringBoot Aviator parameter verification, please pay attention to my other related articles!