全栈低码设计开源框架 json-script-rule 自定义开发及扩展接口说明

自定义开发

说明

本篇的内容是框架的核心思想,较为重要,所有内置的插件也全都是基于这种开发模式开发出来的。自定义开发主要包括自定义模型,自定义插件,自定义数据库字段及函数。自定义模型包括自定义action,自定义result,自定义controller,自定义模型是实现了IJSRuleCustom接口的bean,有且只能有一个被注册进spring容器中。自定义插件是开发者根据自身业务场景封装的代码片段,它应具有高内聚低耦合的特性,它是脚本代调的基本单位,因此需要一定的抽象设计能力。自定义数据库字段及函数主要用于映射数据库的函数,如substr(),current_date,sum(),开发者可以自定义这些函数的名称,未定义的函数将不可用。

自定义action

action对应的扩展对象为edi.rule.model.JSRuleAction,通过继承这个类并将此类注册成spring bean开发者可以自定义一个action。这个action好比一个仓库,所有的插件类都会在这个仓库类中被定义成一个实现了edi.rule.extend.interfaces.IJSRuleActionModel接口类型的字段,字段的名字即是插件使用时的属性,如果要重写应用框架内置的插件,只需要重写它内部对应的插件类型的字段就可以了。

@Data
@EqualsAndHashCode(callSuper=false)
@Component
public class MyActions extends JSRuleAction<MyActions>{
    @JSRuleModelPermit(join={"role1"})
    public JSRuleGetCustomModel get;
    public JSRuleAddCustomModel add;
    @JsonAlias({"del"})
    public JSRuleDeleteCustomModel delete;
    public JSRuleEditCustomModel edit;
    private MyTestCustom mtc;
}

上面的例子重写了父类的get,add,delete,edit插件,因此需要提供get和set方法,当使用json中的get插件时将会直接进入开发者自定义的JSRuleGetCustomModel这个类里的逻辑。除此之外开发者还可以定义其它的插件类型,如上面的MyTestCustom,还可以增加一些可用的注解,例如@JSRuleModelPermit(join={"role1"}),此外由于框架是jackson进行序列化的,这里还可以使用jackson注解,例如@JsonAlias({"del"}),它将插件名称加了一个del的别名,这不会影响重写的机制,例如@JsonIgnore注解,忽略某个字段的反序列化。

自定义插件

public class MyTestCustom implements IJSRuleActionModel<MyActions>{

    @JSRuleInject
    @JsonIgnore
    private JSRuleGlobalVariable variable;
    @JSRuleModelField
    public List<String> list;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    public Date date;

    @Override
    public Object start(MyActions action) {
        return "这里直接返回结果->";
    }
}

注意:由于插件本身以及下面所有的属性都会经过jackson序列化,因此相关的jackson注解在这里也是可以使用的,比如@JsonIgnore,@JsonFormat等等,此外声明的变量要么是public访问权限,要么提供public类型的get方法,否则jackson会提示未被承认的属性


上面的例子是一个自定义插件的例子,插件其实就是一个实现了IJSRuleActionModel 接口的class类,其处理逻辑便是重写start方法,这里还有一些自定义开发时需要用到的注解,这些注解仅对插件内部属性生效,允许递归

  • @JSRuleInject:该注解与spring的@Autowired注解类似,用于依赖注入的,使用该注解时通常需要搭配@JsonIgnore注解,用于忽略某些注入字段的反序列化操作,因为被该注解标识的字段只有为空时才会有效。其中names属性表示获取指定的bean名称集合,types属性表示获取指定的bean类型集合,这两个属性通常用于注入Collection,Map,Array等集合类型的字段,表示获取多个bean,当用在非集合类型的字段上面时会按照顺序进行获取,当没有找到任何bean并且属性required为true的时候此时会报错,否则只要找到一个bean就会成功注入
    注意:此注解注入带有@Transactional注解的bean时会报错,因此不能使用该注解注入JSRuleService,为了避免嵌套循环调用,逻辑上在model中也不允许注入JSRuleService,如果需要嵌套执行action,可以参考接口IJSRuleActionModel中的startActions方法
  • @JSRuleModelField:此注解用于某些字段初始化后的一些后续处理,处理类需要实现IJSRuleModelFieldProcessor扩展接口并注册成spring bean。当此注解标记在一个类型为IJSRuleModel的字段时将会产生向下递归处理,此时该注解的作用将会失效。type属性表示该字段将会被哪个类进行处理,默认不进行任何处理
  • @JSRuleCheck:该注解用于校验字段值的合法性,如果该字段的类型是IJSRuleModel类型,那么它会向下递归检查。
    注意:上面3个任何一个注解标记一个IJSRuleModel类型的字段时都将产生向下递归的效果,会递归处理IJSRuleModel类型对象中的字段,如果没有标记则不会递归处理
    提示:以上3个注解的执行顺序是@JSRuleInject,@JSRuleModelField,@JSRuleCheck

异常以及国际化处理

异常的处理只需要throw new JSRuleException(msg)即可,如果需要国际化消息,则可以通过JSRuleMessage对象的read方法
例如:throw new JSRuleException(JSRuleMessage.read(key))
如果想要自己捕获该JSRuleException类异常也可以自定义一个@ControllerAdvice注解的类用于捕获JSRuleException,可以搭配@Order注解一起使用,或搜索JSRuleExceptionProcess类查看源码是如何处理的
国际化文件可在application文件中配置属性edi.rule.config.message,以resources为根目录,以/开头输入国际化文件的位置

自定义result

自定义result模型需要继承JSResult类,如果需要更改原有的字段名称,可通过重写父类的属性并加上@JsonProperty注解来进行更改,如果需要新增一个属性,可以直接在子类中新增一个字段,如果需要删除原有的字段,可通过重写父类的属性并加上@JsonIgnore注解来进行删除,用例如下

@Data
@EqualsAndHashCode(callSuper=false)
@Component
public class TestJSResult extends JSResult{
    @JsonProperty("codeAlias")
    public int code;
    public String msgCustom;
    public LinkedHashMap<String,Object> result;
    @JsonIgnore
    public String log;
    @JsonIgnore
    public Map<String,String> actionSql = new HashMap<String,String>();
    
    public TestJSResult() {
        code = 200;
        msg = "any message";
        result = new LinkedHashMap<String,Object>();
    }
}

构造函数中用于定义结果集对象内部属性的默认值,重写父类属性意味着要对父类属性进行更改

自定义controller

json-script-rule内置的控制器为JSRuleController,它的固定访问路径为/json/script,当你需要更改这个路径的时候可以自定义一个控制器,如下

@Data
@RestController
@RequestMapping("/xxx/xxx")
public class MyTestController {
    
    @Autowired
    protected JSRuleService service;
    @Autowired
    protected HttpServletRequest request;
    @Autowired
    protected HttpServletResponse response;

    @PostMapping(value = JSRuleJsonConfig.DEFAULT_REQUEST_START)
    public String start() {
        return service.start(ZSHttp.getJsonStrFromReq(request),ZSHttp.initGlobalArgs(request,response));
    }
}

上面的例子还可以通过继承JSRuleController来实现一个自定义控制器,与此同时还应该关闭内置的控制器,可以通过以下方法来关闭

edi:
  rule:
    close:
      engineController: true

自定义数据库函数及字段

自定义函数

所有的扩展类和接口均位于edi.rule.extend包下,其中JSRuleDBFunctions为自定义函数的顶级类,它下面有对应的各种数据库的子类,如JSRuleMysqlFunctions,JSRuleOracleFunctions等,通过继承这些子类来实现一个数据库函数的映射关系

public class JSRuleMysqlFunctions extends JSRuleDBFunctions{
    static {
        functions.put("abs", new JSRuleFunctionInfo("abs",1));
        functions.put("concat", new JSRuleFunctionInfo("concat"));
        functions.put("now", new JSRuleFunctionInfo("now",0));
    }
}

上面的例子展示了如何定义一个函数映射,其中key "abs"为json中使用的函数名,它可以是任意名称,JSRuleFunctionInfo对象为实际的函数名和参数个数。函数映射定义完成后可以在json中直接通过R表达式来使用,例如:#$now(),这里的now便是key,未定义的函数不能在json中使用

自定义字段

数据库中存在一些非函数的字段,例如mysql的currentDate,这些字段不同于表字段,它的结果不属于任何一个表的结果,因此要定义这个字段必须要用另外的方式。框架提供了JSRuleDBFields对象用于这些特殊字段的定义,下面有四个子类对应四种不同的数据库类型,下面先以mysql为例

public class JSRuleMysqlSysFields extends JSRuleDBFields{
    static {
        fields.put("currentDate", "current_date");
        fields.put("currentTime", "current_time");
    }
}

通过上面的例子不难看出,它与自定义函数没有什么太大的区别,因此在这里就不多赘述了

自定义断言器

在使用shunt插件时,框架内置的JSRuleAssertUsual对象只提供了一些基本的判断功能,对于一些复杂的判断还无法实现,因此这个时候就需要开发者自定义一些断言的逻辑,如下面的例子

@Component
public class TestAsserts implements IJSRuleAssert{
    @Override
    public boolean ifTrue(String name, String path, Object value, boolean ifAnd, JSRuleGlobalVariable variable) {
        if (value instanceof Number) {
            return true;
        }
        return false;
    }
}

断言器与自定义模型一样需要注册成spring bean,断言器在json调用时可直接写bean的名字,不是java class的名字

自定义开发需要了解的

获取json参数

Spring bean中可以通过如下方式获取

@Autowired
private JSRuleArgsVessel v

插件中可以使用如下方式获取

@JSRuleInject
private JSRuleArgsVessel v

上下文对象

上下文对象JSRuleContext,它提供了如下参数

  • properties:用于获取spring application配置属性
  • beanFactory:spring bean工厂
  • dataSource:框架最终使用的数据源,类型为javax.sql.DataSource
  • dbInfo:框架使用的数据库信息,包含数据库名称、"mapper"类型和function类型等
  • security:框架目前所采用的安全模式信息

扩展接口

  • JSRuleDefaultExtend:该扩展类实现了IJSRequestHandler和IJSRuleRoleHandler以及IJSRuleMappingsInfo接口,因此通过继承该类可以对上述三个接口方法进行自定义扩展,IJSRuleMappingsInfo接口用于处理非实体类映射的场景,如映射信息来自于xml文件或数据库而非java实体类。IJSRequestHandler用于自定义处理每次请求时json中的body对象的初始化,IJSRuleRoleHandler接口用于处理请求方的角色信息,开发者需要手动识别请求方的角色并返回一个请求方角色的set集合。该类需要通过注解@Component注解注册成spring bean或在application中配置edit.rule.processor属性,并输入类的全限定名称,如下
edi:
  rule:
    processor: test.myrule.JSRuleDBProcessor
  • IJSRuleModel:json中所有对象属性的顶级接口,如果你自定义的类是json中的一个属性,那么理论上来说应该实现这个接口
  • IJSRuleModelFieldProcessor:注解@JSRuleModelField所标识字段的处理接口,实现该接口的处理类可以在字段反序列化后重新赋值,该接口可以存在多个,重写order方法将实现排序
  • IJSRuleActionModel:所有插件的顶级接口,自定义插件必须实现该接口,其start方法用于对action逻辑的处理
  • IJSRuleAssert:实现该接口的spring bean可以在shunt插件中进行调用
  • IJSRulePostLaunch:实现该接口的类在框架加载完成后会自动被调用,允许存在多个实现类,重写order方法将实现排序
  • IJSRuleRoleAuthority:该接口用于初始化框架权限,其内部方法将返回一个"Map"集合,"key"为角色名称,"value"为权限对象。权限对象包含crud权限以及插件权限,crud权限为表与角色之间的关联关系。初始化的crud权限受注解@JSRuleTable中的permit以及roles属性制约
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容