NopReport中如何通过可扩展性设计实现二维码导出

NopReport是从零开始编写的下一代中国式报表引擎,它的核心仅有3000多行代码,但是完整实现了中国式非线性报表理论所定义的层次坐标和行列对称展开算法。

  • 使用介绍:采用Excel作为设计器的开源中国式报表引擎:NopReport, 视频讲解
  • 源码分析: 非线性中国式报表引擎NopReport源码解析,视频讲解

NopReport并没有内置二维码展现这种业务相关的组件,但是它遵循了可逆计算理论,所以内置了大量可扩展机制可以用于引入扩展组件。本文以实现二维码导出为例介绍NopReport中的可扩展机制,这些机制是基于可逆计算理论自然导出,并不限于在Nop平台中使用,对于其他框架的可扩展性也可以起到指导作用。

一. 配置导出二维码

目前nop-report-ext模块提供了二维码扩展组件。使用时需要引入如下jar包

    <dependency>
        <groupId>io.github.entropy-cloud</groupId>
        <artifactId>nop-report-ext</artifactId>
    </dependency>

在Excel模板中,通过单元格的注解调用QRCODE()扩展函数。示例模板

  • valueExpr: 这里只是通过valueExpr来直接指定一个演示用的输出值,实际开发中可以利用NopReport内置的其他机制来生成单元格的值
  • formatExpr: 因为在最终输出的Excel以及展示用的HTML页面上我们并不需要输出单元格的值,所以这里指定formatExpr返回空字符串。否则在二维码上会叠加显示对应的文本。
  • processExpr: 调用扩展函数QRCODE,实际生成二维码
  • qr:barcodeFormat: 指定输出条码格式,缺省是QRCODE,指定为CODE_128生成条形码。

qr:为前缀的变量是传递给QRCODE函数的扩展数据,但是并不需要直接作为QRCODE函数的参数传递。可以设置的属性值对应于QrcodeOptions.java类中的成员变量。

可以通过qr:widthqr:height来指定输出图形的大小。如果不指定,则会自动使用当前单元格的宽高。

二. 实现原理

1. 单元格模型的可扩展属性

NopReport的设计遵循可逆计算原理,系统化的采用 (data,ext_data)这样的配对设计,确保在任何模型节点上都可以追加扩展属性。缺省情况下,所有具有名字空间的属性都不参与元模型校验,因此我们可以引入qr名字空间,通过它设置二维码输出所需要的配置信息,比如二维码格式、大小等。如果需要校验qr名字空间中的属性格式,则可以引入一个自定义的xdef元模型。

<workbook xdef:check-ns="qr">
  <sheets>
    <sheet>
      <table>
        <rows>
          <cell>
            <model xdef:name="XptCellModel"
                   qr:barcodeFormat="string" qr:margin="int" qr:imgType="string" qr:width="double"
                   qr:height="double" qr:encoding="string" qr:errorCorrection="int">
            </model>
          </cell>
        </rows>
      </table>
    </sheet>
  </sheets>
</workbook>

目前NopReport采用Excel为可视化设计器,在单元格的注解中设置单元格模型信息。后续还会提供在线可视化编辑,此时就可以xdef元模型中声明的属性定义自动生成可视化编辑页面。

2. 可扩展的函数空间

NopReport提供了expandExprvalueExprformatExprstyleIdExprprocessExpr等多种表达式配置,可以调用外部函数来完成复杂逻辑处理。NopReport的表达式引擎从Nop平台内置的XLang表达式引擎扩展而来(在XLang EL的基础上增加了报表层次坐标语法),因此它自动继承了XLang中定义的全局函数和全局对象。同时,报表引擎还为报表执行环境引入了报表专用的一系列函数。

全局函数
// 注册XLang EL全局函数
EvalGlobalRegistry.instance().registerStaticFunctions(GlobalFunctions.class);

// 注册Report执行环境专用的报表函数
ReportFunctionProvider.INSTANCE.registerStaticFunctions(ReportExtFunctions.class);

一般情况下可以仿照nop-report-ext模块中的做法,在初始化的时候注册扩展函数。

public class ReportExtInitializer {

    @PostConstruct
    public void init() {
        ReportFunctionProvider.INSTANCE.
                  registerStaticFunctions(ReportExtFunctions.class);
    }
}
集成IoC容器

除了全局注册之外,在表达式中还可以直接通过inject函数获取到NopIoC容器中管理的bean,例如inject('qrService').genQrCode('123456')

因为NopIoC支持类似Spring容器的BeanScope概念,从NopIoC获取的bean不一定都是单例对象

调用时传入

在调用具体报表时还可以通过scope对象传入帮助对象

IEvalScope scope = XLang.newEvalScope();
scope.setLocalValue("myTool", new MyTool());
reportEngine.getRenderer("/my.xpt.xlsx","html").generateToFile(file, scope);

在表达式中就可以调用myTool对象上的方法,例如myTool.myMethod(cell.value)

报表内定义

NopReport引擎与一般的报表引擎非常不一样的地方是,它非常强调报表模型的自包含性和自定义抽象的能力。在报表模型的【展开前】配置中,我们可以定义仅在这个报表中使用的函数。这个函数定义存放在报表模型中,而不需要外部注册或者传入

在【展开前】配置中,我们可以利用XPL模板语言的标签库抽象,来动态加载外部标签函数。后续Nop平台将会为所有XPL配置段提供通用的逻辑编排可视化设计器,这样就可以使用可视化配置的方式为报表模型引入自定义函数。

3. 隐式传递的上下文

Nop平台为开发自定义的领域模型(Domain Model)和领域特定语言(DSL, Domain Specific Language)提供了一系列标准的套路,这其中就包含在表达式语言中引入的隐式上下文的概念。

当我们在一个特定领域(或者特定业务场景)中工作的时候,总是会有一些系统性的背景知识,当我们编写特定的业务代码时,我们可以假定这些背景知识是已知的或者可以按照某种确定性的方式推导得到的,从而原则上并不需要在代码中明确指明。
但是一般情况下,我们编码使用的是通用语言和通用框架,并不存在一种简单的、标准化的方式将这些知识内置到语言中,因此我们经常会发现大量仅起粘结作用的胶水代码中,一些背景信息被重复的表达多次。

比如说,在报表引擎中,我们的背景知识是报表运行时总是存在一个上下文对象IXptRuntime,在我们调用函数的时候能否不显式传递这个参数,而是假定它是一种可以隐式传递的背景知识?
如果我们不希望在调用所有函数的时候都显式传递IXptRuntime,一般的做法是将上下文对象通过ThreadLocal这种近似全局变量的方式进行传递,这种方式会破坏函数的结构,引入不必要的复杂性。

Nop平台的XLang语言中引入了隐式参数的概念,它类似于Scala语言中的implicit语法。

// scala语言中的隐式参数
def welcome(implicit name: String) = s"Welcome, $name!"

implicit val guestName: String = "Guest"

println(welcome) // 输出: Welcome, Guest!

scala语言中会按照类型自动查找上下文中的implicit变量,并自动绑定为函数参数。 Nop平台的Xpl模板语言提供了implicit参数,但是它是按照name来实现隐式绑定。

<!-- 标签库my.xlib -->

<lib>
  <tags>
    <MyTag>
      <attr name="xptRt" implicit="true" />
      <source>
        ...
      </source>
    </MyTag>
  </tags>
</lib>

调用标签的时候可以传入xptRt参数。也可以不设置参数,则会自动绑定上下文中的同名变量

<my:MyTag />

在XLang表达式中,也提供了隐式传递IEvalScope的机制。

    @EvalMethod
    public static ExcelImage QRCODE(IEvalScope scope) {
        IXptRuntime xptRt = IXptRuntime.fromScope(scope);
        ExpandedCell cell = xptRt.getCell();

        QrcodeOptions options = new QrcodeOptions();
        cell.getModel().readExtProps("qr:", true, options);
        ...
        return image;
    }

如果函数上标记了@EvalMethod注解,则第一个参数必须是IEvalScope。在表达式中调用的时候会自动传入表达式的运行时scope。通过scope可以获取到上下文中的其他变量。

ReportExtFunctions中定义的QRCODE函数就是使用这种隐式参数机制,因此不需要显式传递IXptRuntime上下文对象。在QRCODE函数中可以通过IXptRuntime得到当前正在处理的单元格对象,并进而可以获取到单元格模型上的扩展属性。

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

  • gitee: canonical-entropy/nop-entropy
  • github: entropy-cloud/nop-entropy
  • 开发示例:docs/tutorial/tutorial.md
  • 可逆计算原理和Nop平台介绍及答疑_哔哩哔哩_bilibili

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/915255.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux(光速安装+rocky linux镜像)

寻找镜像 Download - Rocky Linux 如果用作桌面的&#xff0c;下载DVD的选项&#xff0c;占的存储比较多了&#xff0c;如果下载最小的&#xff0c;则没有桌面环境。 配置虚拟机 Linux&#xff08;光速安装centos镜像 图片大白话&#xff09;-CSDN博客 有些一样的我就不一…

python文件命名,不注意容易出错

在python中&#xff0c;文件名也会作为模块的名称使用。 举个例子 工程目录如下&#xff1a; 其中&#xff0c;文件夹为sys_check&#xff0c;其下还有一个sys_check1.py文件。 如果该文件名也是sys_check.py&#xff0c;可能会导致问题&#xff0c;在其它文件中引用模块时…

给阿里云OSS启用SSL

自定义域名需要指向阿里云 OSS&#xff0c;并且你希望为这个域名获取 SSL 证书&#xff0c;可以使用 DNS 验证的方法来获取证书。以下是详细步骤&#xff1a; 关键前提&#xff1a; 关键是需要在阿里云控制台的域名 权威域名解析中添加子域名aliyuncs.xxx.com 使用 DNS 验证获取…

边缘计算在智能制造中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 边缘计算在智能制造中的应用 边缘计算在智能制造中的应用 边缘计算在智能制造中的应用 引言 边缘计算概述 定义与原理 发展历程 …

定时任务进行简单监控、爬虫的自动化之旅

原文链接&#xff1a;「定时任务」进阶指南&#xff1a;监控、爬虫的自动化之旅

『VUE』25. 组件事件与v-model(详细图文注释)

目录 功能介绍示例总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 功能介绍 预期拿到一个输入搜索框,用户在搜索框中输入数据后实时把数据发送给父组件使用. 示例 主要是对前面的v-model和watch的结合使用,实现获取更新的子…

【Python TensorFlow】进阶指南(续篇二)

在前面的文章中&#xff0c;我们详细探讨了TensorFlow在实际应用中的高级功能和技术细节。本篇将继续深入探讨一些前沿话题&#xff0c;包括但不限于分布式训练、混合精度训练、神经架构搜索&#xff08;NAS&#xff09;、模型微调以及在实际项目中的最佳实践等&#xff0c;帮助…

什么是MVC模式?

MVC 模型处理数据 控制器做传递 视图用于展示 模型Model:数据验证、逻辑和持久性&#xff0c;直接与数据库进行交互控制器Controller&#xff1a;向模型询问数据&#xff0c;获取所有的数据信息视图View&#xff1a;视图用于显示信息&#xff0c;根据模型来获取信息&#xff0c…

Spring Boot 接口防重复提交解决方案

文章目录 前言使用Token机制实现步骤1.生成Token2.传递Token3.验证Token 使用Redis实现步骤1.引入Redis依赖2.生成Token3.传递Token4.验证Token 使用Spring AOP实现步骤1.定义注解2.创建切面3.使用注解 总结 前言 在Web开发中&#xff0c;防止用户重复提交表单是一个常见的需求…

【毫米波雷达(九)】前雷达软件开发遇到的问题汇总及解决方法

前雷达软件开发遇到的问题汇总及解决方法 一、CAN/CANFD通信1、雷达CAN未能正常发出数据2、雷达在车上接收不到车身信息3、程序下载失败4、DV试验发送数据偶发断连5、发送感知信息丢帧或者丢报文6、上电发出第一帧的报文时间长7、ZCANPRO有错误帧二、协议转换&#xff08;以太网…

图像处理实验四(Adaptive Filter)

一、Adaptive Filter简介 自适应滤波器&#xff08;Adaptive Filter&#xff09;是一种能够根据输入信号的统计特性自动调整自身参数以达到最佳滤波效果的滤波器。它广泛应用于信号处理领域&#xff0c;如信道均衡、系统识别、声学回波抵消、生物医学、雷达、波束形成等模块。 …

计算机网络(8)数据链路层之子层

上一篇已经讲到数据链路层可以分为两个子层&#xff0c;这次将重点讲解子层的作用和ppp协议 数据链路层的子层 数据链路层通常被分为两个子层&#xff1a; 逻辑链路控制子层&#xff08;LLC&#xff0c;Logical Link Control&#xff09;&#xff1a; LLC子层负责在数据链路…

论文5—《基于改进YOLOv5s的轻量化金银花识别方法》文献阅读分析报告

论文报告&#xff1a;基于改进YOLOv5s的轻量化金银花识别方法 论文报告文档 基于改进YOLOv5s的轻量化金银花识别方法 论文报告文档摘要国内外研究现状国内研究现状国外研究现状 研究目的研究问题使用的研究方法试验研究结果文献结论创新点和对现有研究的贡献1. 目标检测技术2. …

雷池waf安装并部署防护站点

雷池waf安装并部署防护站点 最低配置要求 操作系统&#xff1a;Linux 指令架构&#xff1a;x86_64 软件依赖&#xff1a;Docker 20.10.14 版本以上 软件依赖&#xff1a;Docker Compose 2.0.0 版本以上 最小化环境&#xff1a;1 核 CPU / 1 GB 内存 / 5 GB 磁盘 写在前面 本文…

2024第四次随堂测验参考答案

从第四次开始答案会以c语言提供&#xff0c;自行了解&#xff0c;学习 6-1 报数 报数游戏是这样的&#xff1a;有n个人围成一圈&#xff0c;按顺序从1到n编好号。从第一个人开始报数&#xff0c;报到m&#xff08;<n&#xff09;的人退出圈子&#xff1b;下一个人从1开始报…

开源 - Ideal库 - 常用枚举扩展方法(二)

书接上回&#xff0c;今天继续和大家享一些关于枚举操作相关的常用扩展方法。 今天主要分享通过枚举值转换成枚举、枚举名称以及枚举描述相关实现。 我们首先修改一下上一篇定义用来测试的正常枚举&#xff0c;新增一个枚举项&#xff0c;代码如下&#xff1a; //正常枚举 in…

如何平滑切换Containerd数据目录

如何平滑切换Containerd数据目录 大家好&#xff0c;我是秋意零。 这是工作中遇到的一个问题。搭建的服务平台&#xff0c;在使用的过程中频繁出现镜像本地拉取不到问题&#xff08;在项目群聊中老是被人出来&#x1f605;&#xff09;原因是由于/目录空间不足导致&#xff0…

(附项目源码)Java开发语言,监督管家APP的设计与实现 58,计算机毕设程序开发+文案(LW+PPT)

摘要 随着互联网的快速发展和智能手机的普及&#xff0c;越来越多的用户选择通过移动应用程序进行事项设定、提醒通知和事项打卡。监督管家APP作为一个专注于事项设定、提醒通知、事项打卡的监督管理平台&#xff0c;具有广泛的应用前景和商业价值。本研究旨在构建一个功能丰富…

ffmpeg+D3D实现的MFC音视频播放器,支持录像、截图、音视频播放、码流信息显示等功能

一、简介 本播放器是在vs2019下开发&#xff0c;通过ffmpeg实现拉流解码功能&#xff0c;通过D3D实现视频的渲染功能。截图功能采用libjpeg实现&#xff0c;可以截取jpg图片&#xff0c;图片的默认保存路径是在C:\MYRecPath中。录像功能采用封装好的类Mp4Record实现&#xff0c…

LLM在Transformer上的改动

LLM在Transformer上的改动 1.multi-head共享1.1BERT的逻辑1.2multi-head共享 2.attention的前后网络2.1传统Transformer&#xff1a;2.2GPTJ结构&#xff1a; 3.归一化层的位置&#xff08;LayerNorm&#xff09;4.归一化层函数的选择4.1LayerNorm4.2RMSNorm 3.激活函数4.LLama…