全栈低码设计开源框架 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属性制约
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容