Nop入门-如何通过配置扩展服务函数的返回对象

讲解视频:www.bilibili.com/video/BV12K...

Nop平台的服务框架是下一代RPC服务框架NopGraphQL。NopGraphQL与普通的REST框架不同,它采用了最小化信息表达的架构设计,将GraphQL的任务分解组合能力推广到了所有RPC服务调用场景。一个POJO的服务函数(只需增加少量注解)可以同时支持GraphQL、REST和gRPC等多种调用方式。

依托于NopGraphQL,采用Nop平台实现的后端服务拥有远超普通Web服务的可扩展性。本文将介绍在不修改DTO类也不修改服务函数的情况下,如何通过配置来扩展服务函数的返回值。

关于NopGraphQL的设计详解,参见为什么在数学的意义上GraphQL严格的优于REST?,业务开发自由之路:如何打破框架束缚,实现真正的框架中立性

使用NopGraphQL实现服务函数非常简单,它使用的注解个数和隐含约定远少于SpringMVC。比如,在下面的示例中,我们定义了一个查询操作

java 复制代码
@BizModel("Demo")
public class DemoBizModel {
  @BizQuery
  public CustomObj testCustomObj(@Name("name") String name) {
    CustomObj obj = new CustomObj();
    obj.setName(name);
    obj.setStatus(1);
    return obj;
  }
}
  • @BizModel注解用于定义服务对象名。多个不同的BizModel类可以对应于同一个服务对象,它们的服务函数会聚合到一起对外暴露。
  • @BizQuery注解表示这是一个查询操作,如果是@BizMutation则表示是修改操作。修改操作会自动打开事务环境,一般不需要手工标注@Transactional
  • @Name注解用于指定服务函数的参数名。与SpringMVC不同,NopGraphQL并没有假定它在Web环境中调用,因此所有概念都与Web无关。具体通过REST服务调用时,可以通过url参数传递参数,也可以通过HTTP JSON Body来传递参数。
  • 服务函数上无需指定REST链接。NopGraphQL在REST调用模式下固定使用/r/{bizObjName}__{bizAction}这一链接模式。返回值会被自动包装为ApiResponse<T>对象。

在上面的示例中,CustomObj具有两个属性name和status。现在要求返回一个status_label字段,它对应于status属性的中文描述。比如,如果status为1,则status_label返回"已启用",如果status为0,则返回"已禁用"。

要实现这一功能,对于传统的RPC框架或者Web框架,肯定是需要修改服务函数的源码,在其中加载字典表然后实现文本翻译。返回的结果对象CustomObj上也需要主动增加status_label字段。 但是,在NopGraphQL中,我们无需修改testCustomObj函数,也不需要修改CustomObj类。生成status_label的逻辑是一个按照确定性的规则进行衍生计算的逻辑,所以它本质上与服务函数中如何构建CustomObj的逻辑是解耦的。 服务函数只需要知道如何加载、构建CustomObj对象就好了,并不需要将所有返回属性都计算出来。在NopGraphQL引擎中,服务函数的返回值并不是是直接返回给前端的DTO数据。服务函数返回的结果对象还需要进行GraphQL引擎的后处理,执行各种各样的DataLoader,最终才会将DataLoader的返回结果合成为一个JSON数据。

如果要扩展返回值对象,增加status_label属性,我们只需要标记CustomObj是一个BizObject,然后在model目录下增加一个Meta元数据定义。

java 复制代码
@BizObjName("CustomObj")
public class CustomObj {
  private String name;
  private int status;

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getStatus() {
    return status;
  }

  public void setStatus(int status) {
    this.status = status;
  }

  public boolean isActive(){
    return status == 1;
  }
}
xml 复制代码
<!--  resources/_vfs/nop/demo/model/CustomObj/CustomObj.xmeta -->
<meta x:schema="/nop/schema/xmeta.xdef" xmlns:x="/nop/schema/xdsl.xdef">
  <props>

    <prop name="name" displayName="名称" queryable="true" insertable="true" updatable="true">
      <schema type="String"/>
    </prop>

    <prop name="status" displayName="状态" queryable="true" insertable="true" updatable="true">
      <schema type="Integer"/>
    </prop>

    <prop name="status_label" displayName="状态文本">
      <schema type="String"/>
      <getter>
        <c:script><![CDATA[
            if(entity.status == 1)
                return "已启用";
            return "已禁用";
        ]]></c:script>
      </getter>
    </prop>
  </props>
</meta>
  • 在XMeta文件中可以增加一个自定义属性status_label,通过getter段来编写它的计算逻辑。
  • 在XMeta文件中没有定义的字段,即使在CustomObj上存在,也不会返回到前台。比如CustomObj对象上具有isActive函数,但是CustomObj.xmeta文件中并没有定义active字段,返回结果中也就不会包含这个属性。

一旦启用了XMeta这个DSL模型,那么就可以进一步利用Nop平台提供的元编程能力,通过x:gen-extendsx:post-extends等内置的编译期代码生成器来动态生成扩展逻辑。

xml 复制代码
<meta x:schema="/nop/schema/xmeta.xdef" xmlns:x="/nop/schema/xdsl.xdef"
      xmlns:xpl="xpl" xmlns:meta-gen="meta-gen" xmlns:c="c">

    <x:post-extends>
        <meta-gen:DefaultMetaPostExtends xpl:lib="/nop/core/xlib/meta-gen.xlib"/>
    </x:post-extends>

    <props>

        <prop name="name" displayName="名称" queryable="true" insertable="true" updatable="true">
            <schema type="String"/>
        </prop>

        <prop name="status" displayName="状态" queryable="true" insertable="true" updatable="true">
            <schema type="Integer" dict="core/active-status"/>
        </prop>
    </props>
</meta>

在上面的示例中,我们没有显式添加status_label字段,而是为status字段指定了字典表core/active-statusx:post-extends段调用了<meta-gen:DefaultMetaPostExtends>标签,这个标签引入了一系列的编译期生成规则,会自动查找所有配置了dict的字段,逐个为它们生成对应的label字段。

完整的示例可以参见 nop-spring-simple-demo这个示例项目

Nop平台中所有自动生成数据库实体对象都已经标记为BizObject,并且自动生成了对应的XMeta元数据描述文件。因此所有的增删改查操作的输入输出对象都是可以通过XMeta进行扩展的。

基于可逆计算理论设计的低代码平台NopPlatform已开源:

相关推荐
晓晓_za8986682 小时前
Geo 优化服务 CI/CD 流水线搭建:源码自动构建、测试与灰度发布
运维·服务器·tcp/ip·spring·缓存·ci/cd
卓怡学长3 小时前
w180springboot基于Java的悠扬乐器管理
java·spring boot·mysql·spring·maven·intellij-idea
小白说大模型5 小时前
Spring AI 框架中集成 MCP 的完整指南:从服务端到客户端的全流程实践
大数据·数据库·人工智能·安全·spring·chatgpt·开源
卓怡学长6 小时前
w181springboot机场乘客服务系统
java·数据库·spring boot·spring·intellij-idea
卓怡学长11 小时前
w192基于springboot教务管理系统
java·数据库·spring boot·spring·maven·intellij-idea
手握风云-11 小时前
Spring Cloud:分布式系统的“粘合剂”(六)
后端·spring·spring cloud
AI_小站21 小时前
刚面完百度的 Agent 开发岗,我才发现:世界就是个巨大的草台班子
java·开发语言·人工智能·spring·百度·langchain
晓晓_za8986681 天前
Geo 优化源码蒸馏词机制:地域词库构建与匹配逻辑详解
运维·tcp/ip·spring·缓存·ci/cd
ycjunhua1 天前
Spring AI 2.0 GA:ToolCallingAdvisor 重构与 Java Agent 新范式
java·人工智能·spring
让你三行代码QAQ1 天前
SpringAI-依赖问题
spring·ai编程