文档章节

扩展Pentaho Report Designer报表工具

灯下黑鬼吹灯
 灯下黑鬼吹灯
发布于 2017/03/08 10:26
字数 2716
阅读 951
收藏 14

前言:这里以一个例子来说明PRD报表工具强大的扩展功能。 我们用4种不同的方式来实现一个REGE()函数,其目的用来来提取想要的内容。需要传入两个参数,一个是原始字符串,一个是包含一个分组的正则表达式,表达式运算结果是正则表达式匹配的第一个分组。

相关说明:

        a)、示例数据库:Pentaho自带的SampleData

        b)、示例的SQL脚本:

SELECT
	"ORDERFACT"."PRODUCTCODE",
	"PRODUCTS"."PRODUCTNAME",
	"PRODUCTS"."PRODUCTLINE",
	SUM("ORDERFACT"."QUANTITYORDERED") AS QUANTITYORDERED,
	SUM("ORDERFACT"."TOTALPRICE") AS TOTALPRICE
FROM "ORDERFACT" INNER JOIN "PRODUCTS" ON "ORDERFACT"."PRODUCTCODE" ="PRODUCTS"."PRODUCTCODE"
GROUP BY 
	"PRODUCTS"."PRODUCTLINE","ORDERFACT"."PRODUCTCODE",
	"PRODUCTS"."PRODUCTNAME"
ORDER BY 
	"PRODUCTS"."PRODUCTLINE","ORDERFACT"."PRODUCTCODE",
	"PRODUCTS"."PRODUCTNAME"

     c)、关于如何创建一个PRD报表文件请参考链接文档

                             http://www.jianshu.com/p/e9b1762061fa

一、内置JAVA脚本

        这里用 BeanShell(BSH)来实现一个表达式。打开函数对话框,展开 Script 分组,选
择BeanShell(BSH)。

按下面设置 Expression 属性:

import java.util.regex.*;

Object getValue() {
	try{
		// 创建一个基于正则表达式的输入模式
		final Pattern pattern = Pattern.compile("S(\\d+)_.*");
		//final Matcher matcher = pattern.matcher(dataRow.get("PRODUCTCODE"));

		// 查找的字段,如果不为空,创建一个匹配
		final  Object object = dataRow.get("PRODUCTCODE");
		if( object == null ){
			return null;
		}
		final Matcher matcher = pattern.matcher(object.toString());
		// 在字符串中找到第一个匹配项
		matcher.find();
		// 返回第一组内找到匹配
		return matcher.group(1);
	}catch(Exception e){
		return e.getMessage();
	}
}

将上述代码添加到下图箭头所指处:

把函数拖入报表即可:

展示样式:

二、内置JavaScript脚本

用 Javascript 来 实 现 。 选 择 Script 下 面 的 JavaScript 函 数 , 或 者 选 择 Bean-Scripting
Framework(BSF)并把表达式编程语言属性设置为 javascript。
Expression 属性按如下设置:

dataRow.get("PRODUCTCODE").match(/S(\d+)_.*/)[1]

方式一:

方式二:

把函数拖入报表即可:

展示样式:

三、本地构建PRD源码的目录结构

        以上的2种方式为PRD报表工具内置的扩展功能的脚本化方式,不过通过这种方式实现的表达式仅限于当前报表有效,如果用户想要定义一套全局都有效的表达式该如何操作喃?辛运的是,Pentaho Reporting 有一套扩展系统的方式,能够无侵入性地增加功能。这主要是通过定义模块、加载模块的方式来实现的。

        接下来我们将PRD的源码从GitHub上Maven到本地,利用JAVA语言编写相应的功能模块,并将其update到报表工具中,进而扩展PRD的功能!

1、Maven项目到本地

    官方github地址:https://github.com/pentaho/pentaho-reporting

    小编github地址:https://github.com/TaoPengFei/pentaho-reporting

     (1)、 如果你使用IDEA自导的Maven的项目管理,请将settings.xml放置在你本地C盘/.m2目录下

     (2)、 如果你本地创建了Maven构件库,请将settings.xml放置在你Maven安装目录下

                    我的安装目录是:D:\Maven\apache-maven-3.3.9\conf

  • 用IDEA打开Maven项目 File Open -> pom.xml

2、报表引擎

Pentaho Reporting 包含几大部分:
 基础库(libraries)
 报表引擎核心(engine core)
        其依赖于基础库。代码是 org.pentaho.reporting.engine.classic.core.**
 报表扩展(extentions),包括各种数据源适配器,脚本支持等
 报表设计器(designer)

3、Libraries基础库

主要基础库的解释

3.1、libformula

        libformula是一个提供公式支持的基础库,包括:公式解析、公式运算以及一批预定义的表
达式和函数。公式的语法基于 OpenFormula 标准。

  • Function接口

        接口 Function 是 libformula 中所有预定义的函数实现的接口。 一个函数是一个任意的运算,
返回的值类型只有在函数运算完成后才可用。函数必须是无状态的,这意味着,使用完全相
同的参数调用相同的函数必须总是返回相同的计算结果。当需要自定义函数时,如果函数跟报表状态无关,并且内部不需要访问报表的当前数据行,那么可以选择实现 libformula 的 Function 接口。

Function 接口只有两个方法:


package org.pentaho.reporting.libraries.formula.function;

import org.pentaho.reporting.libraries.formula.EvaluationException;
import org.pentaho.reporting.libraries.formula.FormulaContext;
import org.pentaho.reporting.libraries.formula.lvalues.TypeValuePair;

import java.io.Serializable;

public interface Function extends Serializable {
  public String getCanonicalName();

  public TypeValuePair evaluate( FormulaContext context,
                                 ParameterCallback parameters )
    throws EvaluationException;
}
  • Expression 接口

        在报表引擎核心模块的 function 包有一个 Expression 接口,表示一个表达式。表达式不维护
状态,因此是轻量级的函数。表达式用于在报表的一行内计算值,可以用一个 dataRow 变
量来访问这个报表内当前行的其他字段、表达式或函数。

Expression 接口主要的方法有:

package org.pentaho.reporting.engine.classic.core.function;

import org.pentaho.reporting.engine.classic.core.DataRow;
import org.pentaho.reporting.engine.classic.core.ResourceBundleFactory;
import org.pentaho.reporting.libraries.base.config.Configuration;
import java.io.Serializable;

public interface Expression extends Cloneable, Serializable {

  public String getName();
  public void setName( String name );
  public Object getValue();
  public boolean isActive();
  public DataRow getDataRow();
  public Object clone() throws CloneNotSupportedException;
  public int getDependencyLevel();
  public void setDependencyLevel( int level );
  public Expression getInstance();
  public ResourceBundleFactory getResourceBundleFactory();
  public Configuration getReportConfiguration();
  public void setRuntime( ExpressionRuntime runtime );
  public ExpressionRuntime getRuntime();
  public boolean isDeepTraversing();
  public boolean isPreserve();
}

4、实现SLEEP()函数

        现在自定义一个SLEEP()的函数。可以通过实现 LibFormula 库 Function 接口的方式来自定义函数。

4.1、定义函数分类类

用于创建新的Others分类。

package org.pentaho.reporting.libraries.formula.function.others;

import org.pentaho.reporting.libraries.formula.function.AbstractFunctionCategory;
import org.pentaho.reporting.libraries.formula.function.FunctionCategory;

/**
 * Created by 陶鹏飞 on 2017/3/6.
 */
public final class OthersFunctionCategory extends AbstractFunctionCategory {
    public static final FunctionCategory CATEGORY = new OthersFunctionCategory();

    private OthersFunctionCategory(){
        super("org.pentaho.reporting.libraries.formula.function.others.category");
    }
}

4.2、定义函数类

重点是实现 evaluate 方法。

package org.pentaho.reporting.libraries.formula.function.others;

import org.pentaho.reporting.libraries.formula.EvaluationException;
import org.pentaho.reporting.libraries.formula.FormulaContext;
import org.pentaho.reporting.libraries.formula.LibFormulaErrorValue;
import org.pentaho.reporting.libraries.formula.function.Function;
import org.pentaho.reporting.libraries.formula.function.ParameterCallback;
import org.pentaho.reporting.libraries.formula.lvalues.TypeValuePair;
import org.pentaho.reporting.libraries.formula.typing.Type;
import org.pentaho.reporting.libraries.formula.typing.coretypes.LogicalType;

/**
 * Created by 陶鹏飞 on 2017/3/3.
 */
public class SleepFunction implements Function {

    private  static  final long serialVersionUID = 4984027687466610131L;
    private  static  final TypeValuePair RETURN_INTERRUPTED = new TypeValuePair( LogicalType.TYPE, Boolean.FALSE );
    private  static  final TypeValuePair RETURN_UNINTERRUPTED = new TypeValuePair(LogicalType.TYPE,Boolean.TRUE);

    public SleepFunction(){
        // Constructor
    }

    @Override
    /* (non-Javadoc)
   * @see org.pentaho.reporting.libraries.formula.function.Function#getCanonicalName()
   */
    public String getCanonicalName() {
        return "SLEEP";
    }

    @Override
    /* (non-Javadoc)
   * @see org.pentaho.reporting.libraries.formula.function.Function#evaluate(org.pentaho.reporting.libraries.formula.FormulaContext, org.pentaho.reporting.libraries.formula.function.ParameterCallback)
   */
    public TypeValuePair evaluate(FormulaContext context, ParameterCallback parameters) throws EvaluationException {
        final  int parameterCount = parameters.getParameterCount();
        if ( parameterCount < 1 ){
            throw new EvaluationException(LibFormulaErrorValue.ERROR_ARGUMENTS_VALUE);
        }
        final Type type1 = parameters.getType(0);
        final Object value1 = parameters.getValue(0);
        final Number result = context.getTypeRegistry().convertToNumber(type1,value1);
        if ( result == null || (result.intValue() < 0) ){
            throw new EvaluationException(LibFormulaErrorValue.ERROR_INVALID_ARGUMENT_VALUE);
        }
        Boolean  sleepInterrupted = false;
        // The number should be the number of milliseconds to sleep
        try {
            Thread.sleep(result.intValue());
        } catch (InterruptedException e) {
            //e.printStackTrace();
            sleepInterrupted = true;
        }
        // Whether the function was interrupted or completed.
        return sleepInterrupted ? RETURN_INTERRUPTED : RETURN_UNINTERRUPTED;
    }

}

4.3、定义函数描述类

需要为函数定义一个函数描述类。需要调用父构造函数的方法,以加载资源。

package org.pentaho.reporting.libraries.formula.function.others;

import org.pentaho.reporting.libraries.formula.function.AbstractFunctionDescription;
import org.pentaho.reporting.libraries.formula.function.FunctionCategory;
import org.pentaho.reporting.libraries.formula.function.information.InformationFunctionCategory;
import org.pentaho.reporting.libraries.formula.typing.Type;
import org.pentaho.reporting.libraries.formula.typing.coretypes.LogicalType;
import org.pentaho.reporting.libraries.formula.typing.coretypes.NumberType;

/**
 * Created by 陶鹏飞 on 2017/3/3.
 */
public class SleepFunctionDescription extends AbstractFunctionDescription {

    private static  final long serialVersionUID = 2368106667495213328L;

    public SleepFunctionDescription() {
        super("SLEEP", "org.pentaho.reporting.libraries.formula.function.others.Sleep-Function");
    }

    @Override
    public Type getValueType() {
        return LogicalType.TYPE;
    }

    @Override
    public FunctionCategory getCategory() {
        return OthersFunctionCategory.CATEGORY;
    }

    @Override
    public int getParameterCount() {
        return 1;       // 1 Parameter - number of milliseconds
    }

    /**
     * Returns the parameter type at the given position using the function metadata. The first parameter is at the
     * position 0;
     *
     * @param position The parameter index.
     * @return The parameter type.
     */
    @Override
    public Type getParameterType(int position) {
        return NumberType.GENERIC_NUMBER;
    }

    /**
     * Defines, whether the parameter at the given position is mandatory. A mandatory parameter must be filled in, while
     * optional parameters need not to be filled in.
     *
     * @param position
     * @return
     */
    @Override
    public boolean isParameterMandatory(int position) {
        return true;
    }
}

4.4、定义资源文件

需要定义一个资源文件用于界面显示。

  • Others分类资源文件
#
# Created by 陶鹏飞 on 2017/3/6.
#
display-name=Others
description=Contains some user-defined statistical functions.
  • 说明函数资源文件(国际化)
#
# Created by 陶鹏飞 on 2017/3/6.
#
display-name=SLEEP
description=Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds.
parameter.0.display-name=Number
parameter.0.description=The number of milliseconds to sleep (positive number only).

 

#
# Created by 陶鹏飞 on 2017/3/6.
#
display-name=SLEEP
description=\u4f7f\u5f53\u524d\u6267\u884c\u7684\u7ebf\u7a0b\u4e3a\u6307\u5b9a\u7684\u6beb\u79d2\u6570\u4f11\u7720\uff08\u6682\u65f6\u505c\u6b62\u6267\u884c\uff09.
parameter.0.display-name=Number
parameter.0.description=\u7761\u7720\u7684\u6beb\u79d2\u6570\uff08\u4ec5\u6b63\u6570).

4.5、注册函数

为了把函数注册到 libformula 模块,需要增加一个名为 libformula.properties 的属性文件,内容如下:

##
# Others functions
org.pentaho.reporting.libraries.formula.functions.others.Sleep.class=org.pentaho.reporting.libraries.formula.function.others.SleepFunction
org.pentaho.reporting.libraries.formula.functions.others.Sleep.description=org.pentaho.reporting.libraries.formula.function.others.SleepFunctionDescription

4.6、使用及效果

利用IDEA将libformula文件夹编译成libformula-6.1.0.1-196.jar包,并替换PRD报表开发工具目录D:\prd-ce-6.1.0.1-196\report-designer\lib下的libformula-6.1.0.1-196.jar包,重启 PRD。

效果展示:

 

四、在步骤三的基础上实现REGE()函数

        现在根据步骤三自定义一个REGE()函数。因为不需要访问报表状态和数据行,所以可以通过
实现 LibFormula 库 Function 接口的方式来自定义函数。我们将REGE()放置在Others分类下,所以不需要在创建定义函数分类的JAVA类了。

4.1、定义函数类

首先要实现一个函数类,这里是 RegexFunction。重点是实现 evaluate 方法。

package org.pentaho.reporting.libraries.formula.function.others;

import org.pentaho.reporting.libraries.formula.EvaluationException;
import org.pentaho.reporting.libraries.formula.FormulaContext;
import org.pentaho.reporting.libraries.formula.LibFormulaErrorValue;
import org.pentaho.reporting.libraries.formula.function.Function;
import org.pentaho.reporting.libraries.formula.function.ParameterCallback;
import org.pentaho.reporting.libraries.formula.lvalues.TypeValuePair;
import org.pentaho.reporting.libraries.formula.typing.TypeRegistry;
import org.pentaho.reporting.libraries.formula.typing.coretypes.TextType;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by 陶鹏飞 on 2017/3/3.
 */
public class RegexFunction implements Function{
    @Override
    public String getCanonicalName() {
        return "REGEX";
    }

    @Override
    public TypeValuePair evaluate(FormulaContext context, ParameterCallback parameters) throws EvaluationException {
        if ( parameters.getParameterCount() != 2 ){
            throw new EvaluationException(LibFormulaErrorValue.ERROR_ARGUMENTS_VALUE);
        }
        final TypeRegistry  typeRegistry = context.getTypeRegistry();
        final String param1 = typeRegistry.convertToText( parameters.getType(0), parameters.getValue(0) );
        final String param2 = typeRegistry.convertToText( parameters.getType(1), parameters.getValue(1) );
        try {
            final Pattern pattern = Pattern.compile(param1);
            final Matcher matcher = pattern.matcher(param2);
            matcher.find();
            return new TypeValuePair(TextType.TYPE, matcher.group(1));
        }catch (Exception e){
            return new TypeValuePair(TextType.TYPE,e.getMessage());
        }

    }
}

4.2、定义函数描述类

需要为函数定义一个函数描述类。需要调用父构造函数的方法,以加载资源。

package org.pentaho.reporting.libraries.formula.function.others;

import org.pentaho.reporting.libraries.formula.function.AbstractFunctionDescription;
import org.pentaho.reporting.libraries.formula.function.FunctionCategory;
import org.pentaho.reporting.libraries.formula.typing.Type;
import org.pentaho.reporting.libraries.formula.typing.coretypes.LogicalType;
import org.pentaho.reporting.libraries.formula.typing.coretypes.TextType;

/**
 * Created by 陶鹏飞 on 2017/3/3.
 */
public class RegexFunctionDescription extends AbstractFunctionDescription{

    public RegexFunctionDescription(){
        //确保调用父构造函数,带上函数名和函数的资源包名
        super("REGEX","org.pentaho.reporting.libraries.formula.function.others.Regex-Function");
    }

    //把函数放到Others分类中
    @Override
    public FunctionCategory getCategory() {
        return OthersFunctionCategory.CATEGORY;
    }

    //函数返回2个参数
    @Override
    public int getParameterCount() {
        return 2;
    }

    /**
     * Returns the parameter type at the given position using the function metadata. The first parameter is at the
     * position 0;
     *
     * @param position The parameter index.
     * @return The parameter type.
     */
    @Override
    public Type getParameterType(int position) {
        return TextType.TYPE;
    }

    @Override
    public Type getValueType() {
        return LogicalType.TYPE;
    }

    /**
     * Defines, whether the parameter at the given position is mandatory. A mandatory parameter must be filled in, while
     * optional parameters need not to be filled in.
     *
     * @param position
     * @return
     */
    @Override
    public boolean isParameterMandatory(int position) {
        return true;
    }
}

4.3、资源文件(国际化)

需要定义一个资源文件用于界面显示。这里叫 Regex-Function.properties。

#
# Created by 陶鹏飞 on 2017/3/6.
#
display-name=REGEX
description=Executes a regular expression on a string, returning the first found group
parameter.0.display-name=Regular Expression
parameter.0.description=A Java Regular Expression string, with a grouping defined within the string.
parameter.1.display-name=String Input
parameter.1.description=A string to parse.
#
# Created by 陶鹏飞 on 2017/3/6.
#
display-name=REGEX
description=\u5728\u5b57\u7b26\u4e32\u4e0a\u6267\u884c\u6b63\u5219\u8868\u8fbe\u5f0f\uff0c\u8fd4\u56de\u7b2c\u4e00\u4e2a\u5df2\u627e\u5230\u7684\u7ec4\u3002
parameter.0.display-name=Regular Expression
parameter.0.description=\u4e00\u4e2ajava\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u5b57\u7b26\u4e32\uff0c\u7528\u5b57\u7b26\u4e32\u4e2d\u5b9a\u4e49\u7684\u5206\u7ec4\u3002
parameter.1.display-name=String Input
parameter.1.description=\u89e3\u6790\u5b57\u7b26\u4e32\u3002

4.4、注册函数

为了把函数注册到 libformula 模块,需要增加一个名为 libformula.properties 的属性文件,内容如下:

##
# Others functions
org.pentaho.reporting.libraries.formula.functions.others.Sleep.class=org.pentaho.reporting.libraries.formula.function.others.SleepFunction
org.pentaho.reporting.libraries.formula.functions.others.Sleep.description=org.pentaho.reporting.libraries.formula.function.others.SleepFunctionDescription

org.pentaho.reporting.libraries.formula.functions.others.Regex.class=org.pentaho.reporting.libraries.formula.function.others.RegexFunction
org.pentaho.reporting.libraries.formula.functions.others.Regex.description=org.pentaho.reporting.libraries.formula.function.others.RegexFunctionDescription

4.5、使用及效果

五、在步骤三的基础上实现REGE()表达式

、、、

六、相关资源下载

© 著作权归作者所有

灯下黑鬼吹灯
粉丝 29
博文 15
码字总数 29995
作品 0
闸北
前端工程师
私信 提问
加载中

评论(1)

贝宝明
贝宝明
谁还用这东西!
Stimulsoft Reports 2013.3(当前最新版本)功能详解

Stimulsoft Reports 2013.3(当前最新版本)功能特色详解。 一、新属性 新版本中报表可以展现更多数据。一些数据可以用文本文档表示。各种数据可以通过需求以不同方式展现。例如:日期、时间、...

咲晚杍
2013/12/16
692
0
songzhuozhuo/biplatform

biplatform 基于scala 、akka实现了一个简单的报表工具。该项目是个玩具项目,用于个人学习scala和akka。 核心功能 使用scala语言开发,基于akka-http, akka-stream,akka-cluster等新技术构建...

songzhuozhuo
2017/01/22
0
0
如何将IDAutomation条形码集成至iReport Designer

本教程主要介绍如何使用Dynamic Barcode Generator Service将线性条码集成到Jaspersoft iReport Designer中。iReport Designer是一款开源的报表设计器,可与JasperReports和JasperReports S...

flyingsnail
2014/05/05
124
0
Stimulsoft Reports.Net基础教程(二):创建简单的列表式报表②

StimulReport.Net是一个基于.NET框架的报表生成器,能够帮助你创建结构、功能丰富的报表。以下步骤将向您展示如何用Stimulsoft Reports.Net创建一个简单的列表式报表。 添加样式 1.返回到报表...

鸟栖沙岩
2016/07/27
24
0
2015年用户界面工具干货资源精选

| 更多干货资源请移步用户界面专题 | DevExpress 2015.1超详细更新说明文档中文版 历时两月吐血翻译整理的DevExpress 2015.1超详细更新说明文档 | 附PDF版下载地址>> DevExpress 15.2帮助文档...

百mumu
2015/12/25
292
0

没有更多内容

加载失败,请刷新页面

加载更多

CentOS7.6中安装使用fcitx框架

内容目录 一、为什么要使用fcitx?二、安装fcitx框架三、安装搜狗输入法 一、为什么要使用fcitx? Gnome3桌面自带的输入法框架为ibus,而在使用ibus时会时不时出现卡顿无法输入的现象。 搜狗和...

技术训练营
昨天
5
0
《Designing.Data-Intensive.Applications》笔记 四

第九章 一致性与共识 分布式系统最重要的的抽象之一是共识(consensus):让所有的节点对某件事达成一致。 最终一致性(eventual consistency)只提供较弱的保证,需要探索更高的一致性保证(stro...

丰田破产标志
昨天
8
0
docker 使用mysql

1, 进入容器 比如 myslq1 里面进行操作 docker exec -it mysql1 /bin/bash 2. 退出 容器 交互: exit 3. mysql 启动在容器里面,并且 可以本地连接mysql docker run --name mysql1 --env MY...

之渊
昨天
10
0
python数据结构

1、字符串及其方法(案例来自Python-100-Days) def main(): str1 = 'hello, world!' # 通过len函数计算字符串的长度 print(len(str1)) # 13 # 获得字符串首字母大写的...

huijue
昨天
6
0
PHP+Ajax微信手机端九宫格抽奖实例

PHP+Ajax结合lottery.js制作的一款微信手机端九宫格抽奖实例,抽奖完成后有收货地址添加表单出现。支持可以设置中奖概率等。 奖品列表 <div class="lottery_list clearfix" id="lottery"> ......

ymkjs1990
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部