Skip to content

Instantly share code, notes, and snippets.

@rponte
Last active November 15, 2024 09:35
Show Gist options
  • Save rponte/3784718 to your computer and use it in GitHub Desktop.
Save rponte/3784718 to your computer and use it in GitHub Desktop.
Automatic compilation of subreports with JasperReports
package br.com.triadworks.controller.relatorios.jasper;
import java.io.ByteArrayOutputStream;
import java.sql.Connection;
import java.util.Map;
import javax.sql.DataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporter;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.util.JRElementsVisitor;
import org.springframework.jdbc.datasource.DataSourceUtils;
import br.com.syspdv.exceptions.RelatorioNaoGeradoException;
public class JasperReportBuilder {
private final DataSource dataSource;
public JasperReportBuilder(DataSource dataSource) {
this.dataSource = dataSource;
}
public byte[] build(String jrxmlFile, Map<String, Object> parameters) {
try {
JasperPrint print = compileAndFillReport(jrxmlFile, parameters);
byte[] content = exportToPdf(print);
return content;
} catch (Exception e) {
throw new RelatorioNaoGeradoException(e.getMessage(), e);
}
}
private JasperPrint compileAndFillReport(String jrxmlFile, Map<String, Object> parametros) throws JRException {
JasperReport report = JasperCompileManager.compileReport(jrxmlFile);
JRElementsVisitor.visitReport(report, new SubReportVisitor("/repositorio/de/jaspers/")); // the magic is here!
JasperPrint print = fillReport(parametros, report);
return print;
}
private byte[] exportToPdf(JasperPrint print) throws JRException {
JRExporter exporter = new JRPdfExporter();
ByteArrayOutputStream exported = new ByteArrayOutputStream();
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, exported);
exporter.setParameter(JRExporterParameter.JASPER_PRINT, print);
exporter.exportReport();
return exported.toByteArray();
}
private JasperPrint fillReport(Map<String, Object> parametros, JasperReport report) throws JRException {
Connection connection = null;
try {
connection = getConnection();
return JasperFillManager.fillReport(report, parametros, connection);
} finally {
DataSourceUtils.releaseConnection(connection, dataSource);
}
}
private Connection getConnection() {
try {
return DataSourceUtils.getConnection(dataSource);
} catch (Exception e) {
throw new IllegalStateException("Impossivel obter uma conexão com o banco de dados.", e);
}
}
}
package br.com.triadworks.controller.relatorios.jasper;
import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sf.jasperreports.engine.JRSubreport;
public class SubReportInfo {
private final static Pattern FILENAME_PATTERN = Pattern.compile("\"(.*?.jasper)");
private final File sourceSubreport;
private final File compiledSubreport;
public SubReportInfo(JRSubreport subreport, String jasperPath) {
String filename = extractFilename(subreport);
this.compiledSubreport = new File(jasperPath, filename);
this.sourceSubreport = new File(jasperPath, filename.replaceAll(".jasper", ".jrxml"));
}
public String getJRXMLFilename() {
return sourceSubreport.getName();
}
public String getJRXMLFilepath() {
return sourceSubreport.getAbsolutePath();
}
public boolean shouldCompile() {
if (!compiledSubreport.exists()) return true;
return (compiledSubreport.lastModified() < sourceSubreport.lastModified());
}
public String extractFilename(JRSubreport subreport) {
String expression = subreport.getExpression().getText();
Matcher matcher = FILENAME_PATTERN.matcher(expression);
if (matcher.find()) {
if (matcher.groupCount() > 0) {
return matcher.group(1);
}
}
throw new IllegalStateException("Não foi possível obter o nome do subrelatório da expressão '" + expression +"'." );
}
}
package br.com.triadworks.controller.relatorios.jasper;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRSubreport;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.util.JRVisitorSupport;
public class SubReportVisitor extends JRVisitorSupport {
private final String jasperPath;
public SubReportVisitor(String jasperPath) {
this.jasperPath = jasperPath;
}
@Override
public void visitSubreport(JRSubreport subreport) {
SubReportInfo subReportInfo = new SubReportInfo(subreport, jasperPath);
compile(subReportInfo);
}
private void compile(SubReportInfo subReportInfo) {
try {
if (subReportInfo.shouldCompile())
JasperCompileManager.compileReportToFile(subReportInfo.getJRXMLFilepath());
} catch (JRException e) {
throw new IllegalStateException("Não foi possível compilar o subrelatório '" + subReportInfo.getJRXMLFilename() + "'.", e);
}
}
}
public class TestingJasperReportBuilder {
public static void main(String[] args) {
DataSource dataSource = DataSourceFactory.default(); // your datasource
Map<String, Object> parameters = new HashMap<String, Object>();
JasperReportBuilder builder = new JasperReportBuilder(dataSource);
byte[] bytes = builder.build("report.jrxml", parameters);
}
}
@danilofd
Copy link

Eu tenho um relatorio com 2 niveis de sub, isso funcionaria? Report tem um sub e o sub tem outro sub.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment