Как использовать JasperReports с Spring MVC?


Я исследовал использование JasperReports (6.0.0) с Spring MVC (4.1.3) для создания отчетов в формате PDF. Spring изобилует" специфичными для Spring " способами интеграции с JasperReports для создания PDF-файлов:

Я изо всех сил пытался найти хорошие, полные примеры в интернете и хотел поделиться своими находками (см. мой ответ ниже ).

Не стесняйтесь добавлять дополнительные методы и / или улучшения, связанные с "как я могу интегрировать JasperReports с Spring4"?

1 34

1 ответ:

Основываясь на своих исследованиях, я нашел следующие методы использования. Методы начинаются с самого прямого (наивного) подхода, предполагающего меньшую первоначальную сложность / конфигурацию,и развиваются, чтобы стать более абстрактными, но с большим количеством зависимостей от Spring / более сложной конфигурации Spring.

Метод 1: используйте API JasperReports непосредственно в контроллере

Просто запишите содержимое в выходной поток сервлета.

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

Метод 2: Ввести Представление JasperReportPdf в контроллер

С учетом Боба JasperReportsPdfView:

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

Это представление может быть введено или подключено к контроллеру для использования:

@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;
}
Обратите внимание, что использование JasperReportsPdfView (или более универсальной JasperReportsMultiFormatView) требует зависимости от spring-context-support:
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-support</artifactId>
  <version>4.1.3</version>
</dependency>

Метод 3: Используйте XML или ResourceBundle view resolver для сопоставления логических имен представлений с представлениями JasperReport

Настройте новый распознаватель представлений, в этом случае ResourceBundleViewResolver будет выполняться перед InternalResourceViewResolver. Это основано на заданных значениях порядка (0 происходит до 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;
}

Тогда в корне нашего пути к классу файл jasperreport-views.properties может содержать логическое имя представления в паре со значениями класса и свойства (например, url и reportDataKey), относящимися к рендингу JasperReport:

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

Код контроллера выглядит следующим образом:

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

Мне нравится такой подход. Контроллеры остаются "немыми" и имеют дело только со строковыми значениями, А отображение имен в представления может происходить все в одном местоположение.


Метод 4: Используйте JasperReportsViewResolver

Сконфигурируйте нулевой порядок JasperReportViewResolver, и трюк заключается в том, чтобы использовать setViewNames, чтобы сказать Spring, с какими логическими именами представлений вы хотите иметь дело с этим решателем (в противном случае вы получите "не удалось загрузить отчет JasperReports из класса path resource [jasperreports/index.jasper] " тип ошибки):

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

И внутри контроллера:

@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;
}
Это мой предпочтительный подход. Контроллеры разрешают Джаспер сообщает в очень аналогично тому, как представления jsp разрешаются с помощью InternalResourceViewResolver , и поэтому нет необходимости в явном файле сопоставления, как при подходе xml или файла свойств в методе #3 выше.

EDIT

The javadocs for JasperReportsPdfView упомяните, что он использует устаревший API JRExporter. Есть ли лучший (более новый) вид JasperReports для использования? Возможно, выбор в пользу JasperReportsMultiFormatView это лучший вариант, так как он, по-видимому, не используется JRExporter.