简体   繁体   English

Jasper Reports:如何编译子报表

[英]Jasper Reports: How to compile subreports

I have a standalone application, and one of its duties is to take the path of a *.jrxml file and compile it.我有一个独立的应用程序,它的职责之一是获取 *.jrxml 文件的路径并编译它。

I can do this without problem until a report with a subreport comes up, where the compilation of the master does not compile any of its children, resulting in a subreport *.jasper file not found later down the track.在出现带有子报表的报表之前,我可以毫无问题地执行此操作,其中主报表的编译不编译其任何子报表,导致以后找不到子报表 *.jasper 文件。

Is there any way to有什么办法

1) Set the JasperCompileManager to automatically pick up subreports? 1) 将 JasperCompileManager 设置为自动获取子报表?

2) Get a list of paths to subreports contained within either a JasperDesign or JasperReport object? 2) 获取 JasperDesign 或 JasperReport object 中包含的子报表的路径列表?

I have no direct access to the jrxml files, so modifying the reports to suit the compile method is not an option, nor is applying any standard naming scheme to infer which subreports belong to which reports.我无法直接访问 jrxml 文件,因此修改报告以适应编译方法不是一种选择,也不是应用任何标准命名方案来推断哪些子报告属于哪些报告。

There is a similar problem here:这里有一个类似的问题:

http://jasperforge.org/plugins/espforum/view.php?group_id=102&forumid=103&topicid=40683 http://jasperforge.org/plugins/espforum/view.php?group_id=102&forumid=103&topicid=40683

where a JRVisitor is used to produce a list of JRSubreport objects, however there is no explanation of how to use this to get a path to the subreport in order to compile it and recursively look for subreports of subreports, and I cant figure it out.其中 JRVisitor 用于生成 JRSubreport 对象列表,但是没有解释如何使用它来获取子报表的路径以便编译它并递归查找子报表的子报表,我无法弄清楚。

Ok, so it required a bit of hackery, but I was able to figure something out...好的,所以它需要一点技巧,但我能够想出一些办法......

The subreport.getExpression().getText() returns the expression field of the subreport widget thing in the master report, and is a string that looks something like this subreport.getExpression().getText() 返回主报表中子报表小部件的表达式字段,是一个看起来像这样的字符串

$P{SUBREPORT_DIR} + "/report_sub1.jasper"

So I was able to pull it apart to get the name using the following.所以我能够使用以下内容将它拆开以获取名称。 Its not ideal, but it should hold up.它不理想,但它应该坚持下去。

JRElementsVisitor.visitReport(jasperReport, new JRVisitor(){

  // ** snip other overrides **

  @Override
  public void visitSubreport(JRSubreport subreport){
    String expression = subreport.getExpression().getText().replace(".jasper", ".jrxml");
    StringTokenizer st = new StringTokenizer(expression, "\"/");
    String subreportName = null;
    while(st.hasMoreTokens())
      subreportName = st.nextToken();
    compileReport(subreportName);
  }
}

EDIT:编辑:

Here is my whole compileReport method, demonstrating how to recursively compile subreports of subreports etc. Not perfect, but good enough for my app.这是我的整个 compileReport 方法,演示了如何递归编译子报表等的子报表。不完美,但对我的应用程序来说已经足够好了。 All compiled *.jasper files are saved back onto disk in the same location as the uncompiled *.jrxml files were picked up, but this wouldn't be hard to change.所有已编译的 *.jasper 文件都保存回磁盘上与未编译的 *.jrxml 文件相同的位置,但这并不难更改。 The compiled main report object is passed back incase you want to run it or whatever.编译后的主报告 object 会被传回,以防您想运行它或其他任何东西。

Remember that this code is 9 months old at the time of this edit, and newer versions of Jasper Reports may now have an inbuild functions for this kind of thing.请记住,此代码在进行此编辑时已有 9 个月的历史,较新版本的 Jasper Reports 现在可能具有针对此类内容的内置函数。

private static final String reportsPath = "someplace/nice/";
private ArrayList<String>   completedSubReports = new ArrayList<String>(30);
private Throwable           subReportException  = null;

/**
 * Recursively compile report and subreports
 */
public JasperReport compileReport(String reportName) throws Throwable{
  JasperDesign jasperDesign = JRXmlLoader.load(reportsPath + reportName + ".jrxml");
  JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
  JRSaver.saveObject(jasperReport, reportsPath + reportName + ".jasper");
  toLog("Saving compiled report to: " + reportsPath + reportName + ".jasper");
  //Compile sub reports
  JRElementsVisitor.visitReport(jasperReport, new JRVisitor(){
    @Override
    public void visitBreak(JRBreak breakElement){}

    @Override
    public void visitChart(JRChart chart){}

    @Override
    public void visitCrosstab(JRCrosstab crosstab){}

    @Override
    public void visitElementGroup(JRElementGroup elementGroup){}

    @Override
    public void visitEllipse(JREllipse ellipse){}

    @Override
    public void visitFrame(JRFrame frame){}

    @Override
    public void visitImage(JRImage image){}

    @Override
    public void visitLine(JRLine line){}

    @Override
    public void visitRectangle(JRRectangle rectangle){}

    @Override
    public void visitStaticText(JRStaticText staticText){}

    @Override
    public void visitSubreport(JRSubreport subreport){
      try{
        String expression = subreport.getExpression().getText().replace(".jasper", "");
        StringTokenizer st = new StringTokenizer(expression, "\"/");
        String subReportName = null;
        while(st.hasMoreTokens())
          subReportName = st.nextToken();
        //Sometimes the same subreport can be used multiple times, but
        //there is no need to compile multiple times
        if(completedSubReports.contains(subReportName)) return;
        completedSubReports.add(subReportName);
        compileReport(subReportName);
      }
      catch(Throwable e){
        subReportException = e;
      }
    }
    @Override
    public void visitTextField(JRTextField textField){}

    @Override
    public void visitComponentElement(JRComponentElement componentElement){}

    @Override
    public void visitGenericElement(JRGenericElement element){}
  });
  if(subReportException != null) throw new RuntimeException(subReportException);
  return jasperReport;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM