反馈已提交

网络繁忙

数据工厂数据集

  • 文档创建者:秃破天际
  • 编辑次数:27次
  • 最近更新:秃破天际 于 2022-09-26
  • 1. 描述

    1.1 版本


    报表服务器版本
    JAR 包版本插件版本
    10.02020-12-30V2.5
    11.02020-12-30V2.5


    1.2 应用场景

    对 FineReport 的程序数据集接口进行改善和封装。

    支撑企业IT轻松进行混合数据集成,为restful等数据结构提供高可用的数据处理服务,具有高度扩展性,通过二次开发来适应更复杂的场景。

    注:基于此插件进行扩展开发需要具备最基础的 FineReport 插件开发能力。

    1.3 功能介绍

    插件提供了额外的取数接口,将 FineReport 的数据集逻辑再次切割为两个部分:

    • 装载器:从数据来源装载数据。

    • 解析器:将装载到的数据组装成 FineReport 支持的数据模型。

    插件内置了两个装载器和一个解析器,分别如下:

    1)装载器:

    • 参数装载器:数据通过参数直接传入。( 比如 JSON、XML 等结构化数据 )

    • 网络数据装载器:通过配置相关请求,从 Web 端装载数据。( 比如 JSON 服务等 )

    2)解析器:

    • JSON 解析器:对结构化的 JSON 文本进行解析,生成 FineReport 支持的数据模型。

    注:只能解析结构型描述的 JSON,业务型描述的 JSON 无法解析,业务型 JSON 解析依赖具体的业务的描述,需要单独实现解析器。

    • JS解析器:通过JS脚本来解析文本,生成数据模型

    注:对于较大数据量时要谨慎使用

    • 原始解析器:原样返回数据,供调试用。           

    2. 插件介绍

    2.1 插件安装

    点击下载插件:数据工厂数据集

    设计器插件安装方法参照:设计器插件管理

    服务器安装插件方法参照:服务器插件管理

    2.2 操作方法

    1)插件安装后,数据集管理面板新增数据工厂数据集,如下图所示:

    Snag_111cc73f.png

    3. 基础使用篇

    使用主面板可以应对绝大多数的场景

    3.1 信息流程

    基础面板包括装载方式,解析方式,参数面板三个部分。

    语法:同数据库查询 ${}可包裹参数或公式,右侧参数面板可自动识别参数,参数支持公式,文本等多种形式。支持从报表中读取参数。

    使用示例

    内置装载器

    HTTP装载器

    HTTP装载器内容是一个JSON,里面4个字段,分别是url:请求地址 ,type:请求类型 可选GET,POST,JSON,charset:编码,header:请求头,以json键值对形式写入,还有一个JSON模式专有的body字段。

    参数栏里面的参数会在后台被分为两类,第一类是装载器界面出现过的参数(${参数}),第二类则是未出现过的。出现过的会解析到装载器配置的字符串里,而剩下的则作为请求的参数。

    GET示例  示例中的http://example.com/仅表示演示,实际请按照真实接口进行调整
    {
        url:"http://example.com/",
        type:"GET", 
        charset:"UTF-8",
        header:{
            aa:${bb}
        }
    }
     
    参数      值
    bb          p_BB
    cc          p_CC
     
    实际请求为 url:http://example.com/?cc=p_CC header:{aa:p_BB}

    对于GET,额外参数会作为query参数拼接到url后

    POST和GET类似,不同之处就是参数在请求体里


    {
        url:"http://example.com/",
        type:"POST", 
        charset:"UTF-8",
        header:{
            aa:${bb}
        }
    }
    参数      值
    bb          p_BB
    cc          CC
     
    实际请求为 url:http://example.com/ header:{aa:p_BB}
    body为x-www-form-urlencoded模式 内容为cc=p_CC


    JSON 实际上是post raw模式,第二类参数会被装载成JSON的格式作为请求体发送。对于POST请求这种方式使用的更普遍

    body有两种装载方式,一种是类似用post get的

    {
        url:"http://example.com/",
        type:"JSON", 
        charset:"UTF-8",
        header:{
            aa:${bb}
        }
    }
    参数      值
    bb          p_BB
    cc          p_CC
     
    实际请求为 url:http://example.com/ type:post  header。 里面会加上content-type: json
    header:{aa:p_BB}
    body为
    {
        cc:p_CC
    }
    第二种是直接写body键


    {
        url:"http://example.com/",
        type:"JSON", 
        charset:"UTF-8",
        header:{
            aa:${bb}
        },
        body:{
            cc:${dd}
        }
    }
    参数      值
    bb          p_BB
    dd          p_DD
     
    实际请求为 url:http://example.com/  type:post。 header 里面会加上content-type: json
    header:{aa:p_BB}
    body为
    {
        cc:p_DD
    }

    单参数装载器 

    单参数的逻辑就比较简单了,将面板的数据参数计算后原样传给解析器。主要是调试用

    ${data}${today()}
      
    参数      值
    data        myData
     
    计算结果为myData今天的日期

    内置解析器

    JSON解析器

    提供了不完整的JPATH语法



    {
        dataPath:"root",
        showmap:"path1,value1,path2,value2"
    }


    root.key1.key2.arr[1] 就表示定位到{ key1 : { key2 : { arr:[ {},{<这里>} ] } } },只解析定位路径下的json内容

    如果是默认root则就是处理全部数据


    showmap提供列名映射将原始的列名(path1)转换为自定义的列名(value1)

    JS解析器

    参照JSON数据集插件中JS语法,$data变量为接受到的原始数据,最终需要通过JS生成如下一个数据表对象 

    返回的对象样例,column为列名,content为二维数组,保存数据集单元格的值
    {
        "column":["col1", "col2", "col3"],
        "content":[
            [1, 2, 3],
            [4, 5, 6]
        ]
    }

    示例:具体代码请按照实际场景开发

    js解析器性能比较低,数据量大的时候要慎用

    原始数据

    类比单参数装载器 返回一个只有一个单元格的数据集,内容是从装载器接受到的数据,参数面板无意义,

    实际案例

    获取帆软市场的插件列表

    装载方式 HTTP装载器


    {
        url:"https://market.fanruan.com/plugins/commodity?cid=&fee=&seller=&version=&language=&searchKeyword=&_=1650781600900",
        type:"GET",
        charset:"UTF-8",
        header:{}
    }

    解析方式 JSON解析器

    {
        dataPath:"root.result",
        showmap:"path1,value1,path2,value2",
    }


    具体的装载器逻辑可以单独客制,所以并没有什么统一的写法规范

    使用案例

    假设有如下接口用来获取某城市天气 http://example.com?city=北京

    果我们希望与根据模板控件内容进行动态获取城市的数据 可以在模板中设置一个控件 city

    然后在数据集装载器中进行如下配置:

    方式一:

    装载方式 HTTP装载器 

    添加同名参数 参数默认值置空


    {
        url:"http://example.com?city=${city}",
        type:"GET",
        charset:"UTF-8",
        header:{}
    }


    方式二

    {
        url:"http://example.com",
        type:"GET",
        charset:"UTF-8",
        header:{}
    }
    参数      值
    city        {置空}

    这样就可以取到原始的返回值了。

    假设接口返回值如下


    {
        result:[
            {
                district:海淀区,
                temperature:20,
            },
            {
                district:朝阳区,
                temperature:23,
            }
        ]
    }


    我们可以使用json解析器 取result部分。让dataPath定位到result,如果需要把列名变为自己想要的可以使用showmap字段进行映射,如下示例

    {
        dataPath:"root.result",
        showmap:"district,辖区,temperature,温度"
    }



    返回结果如下

    缓存

    数据工厂配置界面的缓存是指数据集的缓存,有缓存的话,不走接口取数,直接从缓存里面取数。

    注2:缓存有 3 个选项:无、磁盘、内存。选择表示不启用缓存功能,选择磁盘表示缓存到本地磁盘,选择内存表示缓存到内存。

    进阶使用篇

    进阶使用需要有一定的插件开发能力

    加入使用者认为的装载方式不足以满足使用场景,又不想重新开发一个装载器/解析器时,可以自定义辅助步骤

    高级面板的作用是用来添加装载前,装载后,解析后事件作为装载方式,解析方式的补足,支持多个同步骤事件的添加。


    处理流程

    最上层下拉框可以选择  为该数据集单独配置,使用模板配置,使用服务器全局配置。

    使用单独配置时下方会出现列表,支持事件的增删改。

    选择全局设置/模板设置时不显示列表面板,具体设置项打开全局设置/模板设置进行编辑

    各个事件的作用

    目前各个事件并没有实装具体的应用,仅提供了接入框架,高级步骤是装载-解析模式的增强和补全,结合开发篇来使用。

    装载前事件 

    提供额外的参数引入 比如说token获取的逻辑可以写在自定义装载前事件里。多个装载前事件参数可以累积,重复的参数前者会被后者覆盖。

    在主面板使用,使用方法同常规参数调用,右侧参数栏内默认值无效。

    场景示例:  获取token,可以开发一个token获取的装载前事件,将获取的token作为参数引入主逻辑中

    装载后事件

    提供装载器获取的原始数据的整理 通常装载器返回的是一个字符串类型,可以在这个阶段进行额外的整理行为,多个事件从上到下顺序执行。

    场景示例:返回的数据虽然是json但不适合直接用json解析器,用js解析器性能又不够好的时候,可以定制一个装载后事件,把结构格式化为json解析器能够识别的样式

    解析后事件

    提供解析器返回的数据集的进一步处理 比如增删列,修改列名,重排序,条件过滤等,可以在这个阶段进行额外的整理行为,多个事件从上到下顺序执行

    场景示例: 排序,筛选,取前n项,取奇数项,调整数据格式等等自由操作数据集内容。

    警告: 使用子插件时升级,需要先禁用子插件,或升级后重启服务器



     接口介绍

    装载前事件 preprocessor

    接口描述

    package com.tptj.plugin.hg.fun;
     
    import com.fr.script.Calculator;
    import com.fr.stable.ParameterProvider;
     
    /**
     * 预处理阶段
     */
    public interface Preprocessor extends Configuration {
        String XML_TAG = "TableDataPreprocessor";
        int CURRENT_LEVEL = 1;
     
        /**
         * 预处理  可以改变参数
         * @param calculator 算子
         * @param config 面板配置内容
         * @return 注入的参数
         * @throws Exception
         */
        ParameterProvider[] process(Calculator calculator, String config) throws Exception;
    }

    装载后事件 formatter

    接口描述

    package com.tptj.plugin.hg.fun;
     
    public interface Formatter extends Configuration{
     
        String XML_TAG = "TableDataFormatter";
     
        int CURRENT_LEVEL = 1;
     
        /**
         * 数据格式化
         * @param data 装载器返回的数据
         * @param config 配置
         * @return 格式化后的数据
         * @throws Exception
         */
        Object format(Object data, String config) throws Exception;
    }


    解析后事件 filter

    接口描述

    package com.tptj.plugin.hg.fun;
     
    import com.tptj.plugin.hg.stable.SimpleDataModel;
     
    /**
     *
     */
    public interface Filter extends Configuration {
     
        String XML_TAG = "TableDataFilter";
     
        int CURRENT_LEVEL = 1;
     
        /**
         * 整理数据
         * @param dataModel 数据模型
         * @param config 配置
         * @return 整理后的数据
         * @throws Exception
         */
        SimpleDataModel doAction(SimpleDataModel dataModel, String config) throws Exception;
      
    }

    装载事件 loader

    接口描述

    package com.tptj.plugin.hg.fun;
     
    import com.fr.script.Calculator;
    import com.fr.stable.ParameterProvider;
    import com.fr.stable.fun.mark.Mutable;
     
    public interface Loader extends Mutable {
         
        String XML_TAG = "TableDataLoader";
     
        int CURRENT_LEVEL = 1;
         
        /**
         * 装载数据
         * @param cal   当前算子
         * @param params    需要用到的参数
         * @param others        其他你可能用到的但是又不希望通过参数控制的配置项,即装载器面板内容
         * @return  保存数据的对象
         */
        Object load( Calculator cal, ParameterProvider[] params, String others);
         
        /**
         * 装载器的名字【显示在数据工厂配置界面的下拉列表里面的】,唯一,支持国际化的key
         * @return
         */
        String getName();
         
        /**
         *
         * @return 默认显示的配置【显示在数据工厂配置界面装载器配置文本域里面的,配置项自定义,其实就是放一些,不想写死在代码里,又不希望被参数篡改的部分】
         */
        String getDefaultConfig();
    }


    解析事件 resolver

    接口描述

    package com.tptj.plugin.hg.fun;
     
    import com.fr.stable.fun.mark.Mutable;
    import com.tptj.plugin.hg.stable.SimpleDataModel;
     
    public interface Resolver extends Mutable {
         
        String XML_TAG = "TableDataResolver";
     
        int CURRENT_LEVEL = 1;
         
        /**
         * 解析数据
         * @param data 从装载器得到的原始数据
         * @param others  解析时会使用,但是不希望是参数的配置,即解析器面板内容
         * @return 解析出来的二维数据模型
         */
        SimpleDataModel parse(Object data, String others );
         
        /**
         * 解析器的名字【显示在数据工厂配置界面的下拉列表里面的】,唯一,支持国际化的key
         * @return
         */
        String getName();
          
        /**
         *
         * @return 默认显示的配置【显示在数据工厂配置界面解析器配置文本域里面的,配置项自定义,其实就是放一些,不想写死在代码里,又不希望被参数篡改的部分】
         */
        String getDefaultConfig();
         
    }


    功能点注册

         <extra-core>
           <TableDataLoader class="com.fr.plugin.tptj.tabledata.factory.demo.DemoLoader"/>
           <TableDataResolver class="com.fr.plugin.tptj.tabledata.factory.demo.DemoResolver"/>
           <TableDataPreprocessor class="com.fr.plugin.tptj.tabledata.factory.demo.DemoPreprocessor"/>
           <TableDataFormatter class="com.fr.plugin.tptj.tabledata.factory.demo.DemoFormatter"/>
           <TableDataFilter class="com.fr.plugin.tptj.tabledata.factory.demo.DemoFilter"/>
       </extra-core>
    <dependence>
           <Item key="com.tptj.plugin.hg.tabledata.factory.v10" type="plugin"/>  <!-- 依赖于数据工厂主框架 -->
     </dependence>


    我们通常继承抽象类来开发


    package com.fr.plugin.tptj.tabledata.factory.demo;
     
    import com.fr.base.Parameter;
    import com.fr.json.JSONObject;
    import com.fr.script.Calculator;
    import com.fr.stable.ParameterProvider;
    import com.tptj.plugin.hg.impl.AbstractPreprocessor;
     
    public class DemoPreprocessor extends AbstractPreprocessor {
        @Override
        public ParameterProvider[] process(Calculator calculator, String s) {
     
            JSONObject jo = new JSONObject(s);
            ParameterProvider[] results = new ParameterProvider[1];
            results[0] = new Parameter("token", jo.get("token"));
            //jo.get("token");
            return results;
        }
     
        @Override
        public String getName() {
            return "Demo_PreProcess";
        }
     
        @Override
        public String getDefaultConfig() {
            return "{\n" +
                    "   token:token\n" +
                    "}";
        }
    }



    package com.fr.plugin.tptj.tabledata.factory.demo;
     
    import com.tptj.plugin.hg.impl.AbstractFormatter;
     
    public class DemoFormatter extends AbstractFormatter {
        @Override
        public Object format(Object o, String s) {
            String data = (String) o;
            String[] lines = data.split("\n");
            StringBuilder result = new StringBuilder();
            for (int i = 1; i < lines.length; i++) {
                result.append(lines[i]).append("\n");
            }
            return result.toString();
        }
     
        @Override
        public String getName() {
            return "Demo_Formatter";
        }
     
        @Override
        public String getDefaultConfig() {
            return "remove first line";
        }
    }


    package com.fr.plugin.tptj.tabledata.factory.demo;
     
    import com.fr.general.data.TableDataException;
    import com.fr.log.FineLoggerFactory;
    import com.tptj.plugin.hg.impl.AbstractFilter;
    import com.tptj.plugin.hg.stable.SimpleDataModel;
     
    import java.util.ArrayList;
    import java.util.List;
     
    public class DemoFilter extends AbstractFilter {
        @Override
        public SimpleDataModel doAction(SimpleDataModel simpleDataModel, String s) {
            try {
                simpleDataModel.removeColumn(simpleDataModel.getColumnCount() - 1);
                List<Object[]> newData = new ArrayList<Object[]>();
                for(Object[] row : simpleDataModel.getDatas()) {
                    Object[] newRow = new Object[row.length - 1];
                    System.arraycopy(row, 0, newRow, 0, row.length - 1);
                    newData.add(newRow);
                }
                simpleDataModel.setDatas(newData);
                //simpleDataModel.getDatas().remove(simpleDataModel.getColumnCount() - 1);
            } catch (TableDataException e) {
                FineLoggerFactory.getLogger().error(e, "{}", e.getMessage());
            }
            return simpleDataModel;
        }
     
        @Override
        public String getName() {
            return "Demo_Filter";
        }
     
        @Override
        public String getDefaultConfig() {
            return "remove last col";
        }
    }


    package com.tptj.plugin.hg.tabledata.factory;
     
    import com.tptj.plugin.hg.impl.AbstractResolver;
    import com.tptj.plugin.hg.stable.SimpleDataModel;
     
    public class DemoResolver extends AbstractResolver {
     
        @Override
        public SimpleDataModel parse(Object jsonStr, String others) {
            return new SimpleDataModel();
        }
     
        public static final String KEY = "Demo";
        @Override
        public String getName() {
            return KEY;
        }
     
        @Override
        public String getDefaultConfig() {
     
            return "Is a demo";
        }
     
    }


    package com.tptj.plugin.hg.tabledata.factory.core.loader;
     
    import com.fr.json.JSONObject;
    import com.fr.script.Calculator;
    import com.fr.stable.ParameterProvider;
    import com.tptj.plugin.hg.impl.AbstractLoader;
     
    public class SingleParamLoader extends AbstractLoader {
     
        @Override
        public Object load( Calculator calculator, ParameterProvider[] parameters, String others ) {
            try{
                JSONObject obj = new JSONObject(others);
                if( obj.has("data") ){
                    return obj.optString("data", "{}");
                }
            }catch(Exception e){
                e.printStackTrace();
            }
            return "";
        }
        public static final String KEY = "Plugin-Factory_Data_Set_Loader_Type_Single_Parameter";
        @Override
        public String getName() {
            return KEY;
        }
     
        @Override
        public String getDefaultConfig() {
            StringBuilder sb = new StringBuilder();
            sb.append("{\r\n")
            .append("    data:\"待解析的json字符串,支持${p1}这样的参数和公式\",\r\n")
            .append("}\r\n");
            return sb.toString();
        }
     
    }



    SimpleDataModel继承的标准数据集格式。负责存储数据的结构为一个二维表datas和一个一维表cols,分别是具体内容和列名。调用对应的set,add方法即可向数据集写入数据
    
    
    
    
    自定义面板接口,很多时候,默认的文本框对于配置来说过于简陋了。如果想要更丰富的UI可以使用这个接口替换默认的文本框
    package com.tptj.plugin.hg.fun;
     
    import com.fr.stable.fun.mark.Mutable;
     
    import javax.swing.*;
    import java.awt.event.FocusListener;
     
    public interface ConfigTable<T extends Configuration> extends Mutable {
      
        String XML_TAG = "TableDataConfigTable";
     
        int CURRENT_LEVEL = 1;
     
        /**
         * 与组件名字相同就可以绑定了
         * @return
         */
        String getName();
     
        /**
         * 写入数据到JPanal
         * @param config
         */
        void setValue(String config);
     
        /**
         * 读取数据到
         * @return
         */
        String getValue();
     
        JPanel getTable(FocusListener listener);
    }


    使用时继承抽象类

    package com.tptj.plugin.hg.tabledata.factory.core.filter;
     
    import com.fr.design.layout.TableLayout;
    import com.tptj.plugin.hg.impl.AbstractConfigTable;
     
    import javax.swing.*;
    import java.awt.event.FocusListener;
     
    public class DefaultFilterTextTable extends AbstractConfigTable<DefaultFilter> {
     
        private final static double P = TableLayout.PREFERRED;
        private final static double F = TableLayout.FILL;
     
        JTextArea textArea;
        String value;
     
        @Override
        public JPanel getTable(FocusListener listener) {
     
            return new JPanel();
        }
     
    /*
        public TextTable(String text) {
            super();
            textArea = new JTextArea(text);
            //textArea.setPreferredSize(new Dimension(300, 300));
            this.add(textArea);
        }
    */
       
        @Override
        public void setValue(String text) {
            value = text;
        }
        @Override
        public String getValue() {
            return value;
        }
     
    }
    功能点注册
    <extra-designer>
          <TableDataConfigTable class="com.tptj.plugin.hg.tabledata.factory.core.filter.DefaultFilterTextTable"/>
      </extra-designer>


    完整开发demo见 数据工厂二次开发demo示例

    附件列表


    主题: 数据准备
    • 有帮助
    • 没帮助
    • 只是浏览

    售前咨询电话

    400-811-8890转1

    在线技术支持

    在线QQ:800049425

    热线电话:400-811-8890转2

    总裁办24H投诉

    热线电话:173-1278-1526

    文 档反 馈

    鼠标选中内容,快速反馈问题

    鼠标选中存在疑惑的内容,即可快速反馈问题,我们将会跟进处理。

    不再提示

    10s后关闭