java - modelandview - spring jasperreports maven
¿Cómo usar JasperReports con Spring MVC? (1)
He estado investigando el uso de JasperReports (6.0.0) con Spring MVC (4.1.3) para generar informes en PDF. La primavera está plagada de formas "específicas de Spring" para integrarse con JasperReports para generar archivos PDF:
- Use
JasperReportsPdfView
basa en las características de JasperReport ahora en desuso - Use
JasperReportsMultiFormatView
- Use
JasperReportsViewResolver
Luché para encontrar buenos ejemplos completos en línea y quería compartir mis hallazgos (ver mi respuesta a continuación ).
Siéntase libre de agregar métodos adicionales y / o mejoras relacionadas con "¿Cómo puedo integrar JasperReports con Spring4"?
Basado en mi investigación, he encontrado los siguientes métodos de uso. Los métodos comienzan con el enfoque más directo (ingenuo) que implica una complejidad / configuración menos avanzada y evolucionan para volverse más abstractos pero con más dependencias en Spring / configuración de Spring más compleja.
Método 1: use la API JasperReports directamente en el controlador
Simplemente escriba el contenido en la secuencia de salida del servlet.
@RequestMapping(value = "helloReport1", method = RequestMethod.GET)
@ResponseBody
public void getRpt1(HttpServletResponse response) throws JRException, IOException {
InputStream jasperStream = this.getClass().getResourceAsStream("/jasperreports/HelloWorld1.jasper");
Map<String,Object> params = new HashMap<>();
JasperReport jasperReport = (JasperReport) JRLoader.loadObject(jasperStream);
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, params, new JREmptyDataSource());
response.setContentType("application/x-pdf");
response.setHeader("Content-disposition", "inline; filename=helloWorldReport.pdf");
final OutputStream outStream = response.getOutputStream();
JasperExportManager.exportReportToPdfStream(jasperPrint, outStream);
}
Método 2: inyecte la vista JasperReportPdf en el controlador
Dado el JasperReportsPdfView bean:
@Bean @Qualifier("helloWorldReport2")
public JasperReportsPdfView getHelloWorldReport() {
JasperReportsPdfView v = new JasperReportsPdfView();
v.setUrl("classpath:jasperreports/HelloWorld2.jasper");
v.setReportDataKey("datasource");
return v;
}
Esta vista se puede inyectar o conectar en el controlador para su uso:
@Autowired @Qualifier("helloWorldReport2")
private JasperReportsPdfView helloReport;
@RequestMapping(value = "helloReport2", method = RequestMethod.GET)
public ModelAndView getRpt2(ModelAndView modelAndView) {
Map<String, Object> parameterMap = new HashMap<>();
parameterMap.put("datasource", new JREmptyDataSource());
modelAndView = new ModelAndView(helloReport, parameterMap);
return modelAndView;
}
Tenga en cuenta que el uso de JasperReportsPdfView
(o el más versátil JasperReportsMultiFormatView
) requiere una dependencia en spring-context-support:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.3</version>
</dependency>
Método 3: Use XML o ResourceBundle view resolver para asignar nombres de vista lógica a las vistas de JasperReport
Configure una nueva resolución de vista, en este caso ResourceBundleViewResolver
para ejecutar antes de InternalResourceViewResolver
. Esto se basa en los valores de orden establecidos (0 ocurre antes de 1):
@Bean
public ResourceBundleViewResolver getResourceBundleViewResolver() {
ResourceBundleViewResolver resolver = new ResourceBundleViewResolver();
resolver.setBasename("jasperreport-views");
resolver.setOrder(0);
return resolver;
}
@Bean
public InternalResourceViewResolver getInternalResourceViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setOrder(1);
return resolver;
}
Luego, en la raíz de nuestro classpath, el archivo jasperreport-views.properties
puede contener el nombre de vista lógica emparejado con la clase y los valores de propiedad (es decir, url y reportDataKey) pertinentes para rasgar un JasperReport:
helloReport3.(class)=org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
helloReport3.url=classpath:/jasperreports/HelloWorld3.jasper
helloReport3.reportDataKey=myDataSourceKey
El código del controlador se ve así:
@RequestMapping(value = "helloReport3", method = RequestMethod.GET)
public ModelAndView getRpt3(ModelMap modelMap, ModelAndView modelAndView) {
modelMap.put("myDataSourceKey", new JREmptyDataSource());
return new ModelAndView("helloReport3", modelMap);
}
Me gusta este enfoque. Los controladores se mantienen "tontos" y solo se ocupan de los valores de cadena y la asignación de nombres a las vistas puede realizarse en un solo lugar.
Método 4: utilice JasperReportsViewResolver
Configura un JasperReportViewResolver
ordenado por cero y el truco es usar setViewNames
para decirle a Spring qué nombres de vista lógica quieres que setViewNames
este resolvedor (de lo contrario terminarás con "No se pudo cargar el informe JasperReports del recurso de ruta de clase [jasperreports / index.jasper]" tipo de errores):
@Bean
public JasperReportsViewResolver getJasperReportsViewResolver() {
JasperReportsViewResolver resolver = new JasperReportsViewResolver();
resolver.setPrefix("classpath:/jasperreports/");
resolver.setSuffix(".jasper");
resolver.setReportDataKey("datasource");
resolver.setViewNames("rpt_*");
resolver.setViewClass(JasperReportsMultiFormatView.class);
resolver.setOrder(0);
return resolver;
}
@Bean
public InternalResourceViewResolver getInternalResourceViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setOrder(1);
return resolver;
}
Y dentro del controlador:
@RequestMapping(value = "helloReport4", method = RequestMethod.GET)
public ModelAndView getRpt4(ModelMap modelMap, ModelAndView modelAndView) {
modelMap.put("datasource", getWidgets());
modelMap.put("format", "pdf");
modelAndView = new ModelAndView("rpt_HelloWorld", modelMap);
return modelAndView;
}
Este es mi enfoque preferido. Los controladores resuelven los informes de jaspe de forma muy similar a cómo se resuelven las vistas de jsp utilizando InternalResourceViewResolver
y, por lo tanto, no es necesario un archivo de mapeo explícito como con el enfoque de archivo xml o de propiedades en el método n.º 3 anterior.
EDITAR
Los JasperReportsPdfView mencionan que usa la API JRExporter
desuso. ¿Hay una mejor (más reciente) vista de JasperReports para usar? Tal vez optar por JasperReportsMultiFormatView
es una mejor opción, ya que no parece usar JRExporter
.