2012-04-04 33 views
8

Tengo una aplicación independiente, y uno de sus deberes es tomar la ruta de un archivo * .jrxml y compilarlo.Informes de Jasper: Cómo compilar subinformes

Puedo hacer esto sin problema hasta que aparezca un informe con un subinforme, donde la compilación del maestro no compila ninguno de sus elementos secundarios, lo que da como resultado un archivo * .jasper de subinforme que no se encuentra más adelante en la pista.

¿Hay alguna manera de

1) Establecer el JasperCompileManager para que conteste automáticamente informes integrados?

2) ¿Obtiene una lista de rutas a subinformes contenidos dentro de un objeto JasperDesign o JasperReport?

No tengo acceso directo a los archivos jrxml, por lo que modificar los informes para que se ajusten al método de compilación no es una opción, ni aplicar ningún esquema de nomenclatura estándar para inferir qué subinformes pertenecen a qué informes.

Hay un problema similar aquí:

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

donde se utiliza un JRVisitor para producir una lista de objetos JRSubreport, sin embargo no hay una explicación de cómo utilizar esto para conseguir una ruta de acceso al informe integrado para compilarlo y buscar recursivamente subinformes de subinformes, y no puedo entenderlo.

+0

Me gustaría escuchar la respuesta también. Terminé el enlace al archivo * .jasper del informe secundario directamente en lugar de compilarlo sobre la marcha. :( –

+0

Problema similar resuelto sin guardar archivos en el disco: http://stackoverflow.com/questions/9785451/generate-jasper-report-with-subreport-from-java –

Respuesta

8

Ok, por lo que requiere un poco de hackery, pero yo era capaz de encontrar algo mejor ...

El subreport.getExpression(). GetText() devuelve el campo de la expresión de la cosa widget de informe integrado en el informe principal, y es una cadena que se ve algo como esto

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

así que fue capaz de llevarlo a cabo, aparte de conseguir el nombre utilizando el siguiente. No es ideal, pero debería mantenerse.

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:

Aquí es mi método compileReport conjunto, demostrando cómo compilar de forma recursiva subinformes de informes integrados, etc. No es perfecto, pero lo suficientemente bueno para mi aplicación. Todos los archivos * .jasper compilados se guardan en el disco en la misma ubicación donde se recogieron los archivos * .jrxml sin compilar, pero esto no sería difícil de cambiar. El objeto de informe principal compilado se devuelve en caso de que desee ejecutarlo o lo que sea.

Recuerde que este código tiene 9 meses de antigüedad en el momento de esta edición, y las versiones más recientes de los Informes de Jasper ahora pueden tener funciones inbuild para este tipo de cosas.

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; 
} 
+0

¿Qué hace 'compileReport()' hacer? Donde los resultados de compilación de subinformes se almacenan? En el disco? – dzieciou

+0

@dzieciou Ver la respuesta editada arriba – Numeron

+0

Sé que tiene alrededor de 2 años. Pero esta respuesta funcionó como encanto para mí. Gracias –

Cuestiones relacionadas