使用REST API生成JasperServer报告时传入内容

时间:2012-01-09 22:17:43

标签: rest jasper-reports jasperserver

我正在开发一个旨在用JasperReports Server替换当前PDF生成器的项目。计划是使用REST / HTTP API在系统之间实现高级抽象。

最理想的是,我们不希望让JasperReports Server从数据库中提取数据,因为这会绕过调用应用程序架构中的现有日志记录和授权。相反,我们首先要在调用应用程序中提取内容,然后将该内容传递给JasperReports Server。

我们已经做了相当多的调查,缺乏相关结果表明这不是您通常使用JasperReports Server的方式。我们发现的教程中的输入参数通常是标量值(整数,布尔值或字符串),而不是复杂的结构或对象。此外,似乎每个样本或多或少都假设您希望让JasperReports Server连接到数据库。

如果可以传递复杂的结构(比如一组地图,其中一些地图元素是数组或地图本身),那么这样做的最佳做法是什么?我不知道如何在请求体中格式化这样的结构。 SOAP API更适合吗?

如果您根本不设计JasperReports Server解决方案,那么哪种替代产品/解决方案更合适?

提前感谢任何输入。

3 个答案:

答案 0 :(得分:8)

经过几个小时的研究,我想我已经准备好回答我自己的问题。

JasperReports Server(下面的“JRS”)基本上是为自己获取数据而设计的。虽然可以强制向JRS提供数据,但我决定不这样做。

不让JRS获取数据本身的一个最明显的缺点是,不再可能从JRS Web界面生成报告。如果客户端应用程序负责以预定义的格式提供数据,那么与其他系统的集成也变得不可能或困难。

在我正在开发的项目中,我们决定构建一个基于Remote XML DataSource的自定义JRS DataSource,它调用客户端应用程序的XML API。换句话说,客户端应用程序从JRS请求报告,然后JRS从客户端应用程序请求它的数据。我们必须扩展XML API以满足我们的所有报告需求,但在我看来这是一件好事。良好的API覆盖将在未来派上用场。

我希望这些想法可以帮助有类似问题的人。

答案 1 :(得分:0)

正如您所写,获取数据是JRS更自然的方式。但是,我需要采取相反的方式 - 我通过REST调用POST数据来报告坐在JRS回购中。

我在参数“xmlDocument”中传递XML数据,并且通过“技巧”,执行的报告可以使用此XML进行进一步的X路径查询。

xmlDocument只是一个简单的字符串:

struct stat {
    dev_t     st_dev;     /* ID of device containing file */
    ino_t     st_ino;     /* inode number */
    mode_t    st_mode;    /* protection */
    nlink_t   st_nlink;   /* number of hard links */
    uid_t     st_uid;     /* user ID of owner */
    gid_t     st_gid;     /* group ID of owner */
    dev_t     st_rdev;    /* device ID (if special file) */
    off_t     st_size;    /* total size, in bytes */
    blksize_t st_blksize; /* blocksize for file system I/O */
    blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
    time_t    st_atime;   /* time of last access */
    time_t    st_mtime;   /* time of last modification */
    time_t    st_ctime;   /* time of last status change */
};

在设计阶段,我使用我用于预览的XML文件创建XML数据适配器。请注意,选择XML适配器后会出现一个新参数XML_INPUT_STREAM。

然后我将报告发布到JRS。 在报告执行期间,当报告未链接到任何数据源时,它会读取XML_INPUT_STREAM参数(作为回退数据源),如下所示:

<parameter name="xmlDocument" class="java.lang.String">
    <defaultValueExpression><![CDATA["<?xml version=\"1.0\" encoding=\"UTF-8\"?><documentData></documentData>"]]></defaultValueExpression>
</parameter>

我将“xmlDocument”字符串包装到InputStream。

答案 2 :(得分:0)

即使我同意答案,但女巫指出JasperServer本身就是为了获取数据而构建的,我仍然必须通过其余API传递数据,因为这是我公司构建Jasper报告的传统方式,并且我们要使用自定义Java服务来获取数据。

我发现上述方法是最简单的方法。

具有要传递给报告槽Web API的简单自定义pojo:

public class CustomReport {

private String content;

public String getContent() {
    return content;
}

public void setContent(String content) {
    this.content = content;
}

public CustomReport() {
    super();
}

1)定义必须在服务器上部署的自定义jasper scriptlet,作为与报表相关的资源,女巫将使用GSON将字符串反序列化为自定义pojo对象:

public class CustomScriptlet
    extends JRDefaultScriptlet { public void afterReportInit()
        throws JRScriptletException
{
    Object customSerializedObj = getParameterValue("customSerialized");
    if (customSerializedObj != null)
    {
        String customSerializedStr = customSerializedObj.toString();
        if ((customSerializedStr != null) && (customSerializedStr.length() > 0))
        {
            CustomReport customReport = new Gson().fromJson(customSerializedStr,
                            CustomReport.class);

            setVariableValue("customReport", customReport);
        }
    }
}

2)在jasper服务器中的自定义scriptlet中使用参数/变量:

<scriptlet name="Scriptlet_1" class="eu.dedalus.jasper.api.scriptlet.CustomScriptlet">
    <scriptletDescription><![CDATA[CustomScriptlet]]></scriptletDescription>
</scriptlet>
<parameter name="customSerialized" class="java.lang.String"/>
<variable name="customReport" class="com.test.CustomReport" calculation="System"/>

3)像这样调用API @ jasperserver / rest_v2 / reportExecution:

    "reportUnitUri" : "/report/Custom_report",
"async":"false",
"outputFormat":"pdf",
"parameters" : {
    "reportParameter" : [
        {
            "name": "customReport",
            "value": ["{ \"content\" : \"test content\" } "]
        }
    ]
}