当前位置: 代码网 > it编程>编程语言>Java > SpringBoot集成Aviator实现参数校验的代码工程

SpringBoot集成Aviator实现参数校验的代码工程

2024年11月05日 Java 我要评论
1.什么是aviator?aviator是一个高性能、轻量级的java语言实现的表达式求值引擎,主要用于各种表达式的动态求值。现在已经有很多开源可用的java表达式求值引擎,为什么还需要avaitor

1.什么是aviator?

aviator是一个高性能、轻量级的java语言实现的表达式求值引擎,主要用于各种表达式的动态求值。现在已经有很多开源可用的java表达式求值引擎,为什么还需要avaitor呢? aviator的设计目标是轻量级高性能 ,相比于groovy、jruby的笨重,aviator非常小,加上依赖包也才450k,不算依赖包的话只有70k;当然,aviator的语法是受限的,它不是一门完整的语言,而只是语言的一小部分集合。 其次,aviator的实现思路与其他轻量级的求值器很不相同,其他求值器一般都是通过解释的方式运行,而aviator则是直接将表达式编译成java字节码,交给jvm去执行。简单来说,aviator的定位是介于groovy这样的重量级脚本语言和ikexpression这样的轻量级表达式引擎之间

aviator的特性

  • 支持大部分运算操作符,包括算术操作符、关系运算符、逻辑操作符、位运算符、正则匹配操作符(=~)、三元表达式?: ,并且支持操作符的优先级和括号强制优先级,具体请看后面的操作符列表。
  • 支持大整数和精度运算(2.3.0版本引入)
  • 支持函数调用和自定义函数
  • 内置支持正则表达式匹配,类似ruby、perl的匹配语法,并且支持类ruby的$digit指向匹配分组。
  • 自动类型转换,当执行操作的时候,会自动判断操作数类型并做相应转换,无法转换即抛异常。
  • 支持传入变量,支持类似a.b.c的嵌套变量访问。
  • 函数式风格的seq库,操作集合和数组
  • 性能优秀

aviator的限制

  • 没有if else、do while等语句,没有赋值语句,仅支持逻辑表达式、算术表达式、三元表达式和正则匹配。
  • 不支持八进制数字字面量,仅支持十进制和十六进制数字字面量。

使用场景

  • 规则判断以及规则引擎
  • 公式计算
  • 动态脚本控制

2.代码工程

实验目的

利用aviator+aop实现参数校验

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>

controller

在方法上加伤aviator校验规则

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
public class 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();
    }
}

annotation

单个规则注解

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 "";
 
}

多个规则注解

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
public class 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) {
            throw new userfriendlyexception(msg);
         }
      }
      return null;
   }
}

全局异常拦截

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
public class defaultglobalexceptionhandler extends responseentityexceptionhandler {
   private static final 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());
      return super.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());
      } 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 = 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());
      }
      return new responseentity<>(httpresult, httpstatus);
   }
 
}

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

3.测试

  • 启动spring boot应用
  • 访问 http://127.0.0.1:8088/simple?name=jack&age=12
  • 返回校验信息{"status":false,"code":4,"message":"age must be over 18 years old","entry":null}

4.引用

https://github.com/killme2008/aviatorscript/blob/master/readme-en.md

以上就是springboot集成aviator实现参数校验的代码工程的详细内容,更多关于springboot aviator参数校验的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com