web-dev-qa-db-fra.com

Comment utiliser JasperReports avec Spring MVC?

J'ai étudié l'utilisation de JasperReports (6.0.0) avec Spring MVC (4.1.3) pour générer des rapports PDF. Spring est en proie à des méthodes d'intégration "spécifiques à Spring" avec JasperReports dans générer des PDF:

J'ai eu du mal à trouver de bons exemples complets en ligne et je voulais partager mes découvertes (voir ma réponse ci-dessous ).

N'hésitez pas à ajouter des méthodes et/ou des améliorations supplémentaires liées à "Comment puis-je intégrer JasperReports avec Spring4"?

36
Brice Roncace

Sur la base de mes recherches, j'ai trouvé les méthodes d'utilisation suivantes. Les méthodes commencent par l'approche la plus directe (naïve) impliquant moins de complexité/configuration initiale et évoluent pour devenir plus abstraites, mais avec davantage de dépendances sur la configuration de Spring/plus complexe.

Méthode 1: Utiliser l'API JasperReports directement dans le contrôleur

Il suffit d'écrire le contenu dans le flux de sortie de la 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éthode 2: Injectez la vue JasperReportPdf dans le contrôleur

Étant donné le bean JasperReportsPdfView:

@Bean @Qualifier("helloWorldReport2")
public JasperReportsPdfView getHelloWorldReport() {
  JasperReportsPdfView v = new JasperReportsPdfView();
  v.setUrl("classpath:jasperreports/HelloWorld2.jasper");
  v.setReportDataKey("datasource");
  return v;
}

Cette vue peut être injectée ou câblée dans le contrôleur pour être utilisée:

@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;
}

Notez que l'utilisation de JasperReportsPdfView (ou du plus polyvalent JasperReportsMultiFormatView) nécessite une dépendance sur le support contextuel-ressort:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-support</artifactId>
  <version>4.1.3</version>
</dependency>

Méthode 3: Utiliser le résolveur de vues XML ou ResourceBundle pour mapper les noms de vues logiques aux vues JasperReport

Configurez un nouveau résolveur de vue, dans ce cas le ResourceBundleViewResolver à exécuter avant le InternalResourceViewResolver. Ceci est basé sur les valeurs d’ordre définies (0 avant 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;
}

Ensuite, à la racine de notre chemin de classe, le fichier jasperreport-views.properties Peut contenir le nom de la vue logique associé aux valeurs de classe et de propriété (c'est-à-dire url et reportDataKey) pertinentes pour le rendu d'un JasperReport:

helloReport3.(class)=org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
helloReport3.url=classpath:/jasperreports/HelloWorld3.jasper
helloReport3.reportDataKey=myDataSourceKey

Le code du contrôleur ressemble à ceci:

@RequestMapping(value = "helloReport3", method = RequestMethod.GET)
public ModelAndView getRpt3(ModelMap modelMap, ModelAndView modelAndView) {
  modelMap.put("myDataSourceKey", new JREmptyDataSource());
  return new ModelAndView("helloReport3", modelMap);
}

J'aime cette approche. Les contrôleurs restent "muets" et ne traitent que les valeurs de chaîne. Le mappage des noms sur les vues peut se dérouler au même endroit.


Méthode 4: utiliser JasperReportsViewResolver

Configurez un JasperReportViewResolver zéro-commandé et l'astuce consiste à utiliser setViewNames pour indiquer à Spring les noms de vues logiques que vous voulez que ce résolveur traite (sinon vous obtenez "Impossible de charger JasperReports report de la classe ressource de chemin [jasperreports/index.jasper] "erreurs de type):

@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;
}

Et à l'intérieur du contrôleur:

@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;
}

Ceci est mon approche préférée. Les contrôleurs résolvent les rapports jasper de manière très similaire à la façon dont les vues jsp sont résolues à l'aide de InternalResourceViewResolver et il n'est donc pas nécessaire de créer un fichier de mappage explicite, contrairement à l'approche XML ou au fichier de propriétés de la méthode n ° 3 ci-dessus.

[~ # ~] éditer [~ # ~]

Le javadocs for JasperReportsPdfView mentionne qu'il utilise l'API obsolète JRExporter. Existe-t-il une meilleure vue (plus récente) de JasperReports à utiliser? Peut-être que l’option JasperReportsMultiFormatView est une meilleure option car elle ne semble pas utiliser JRExporter.

75
Brice Roncace