如何在Spring MVC中使用JasperReports?

Bri*_*ace 37 java spring spring-mvc jasper-reports spring-4

我一直在调查使用JasperReports(6.0.0)和Spring MVC(4.1.3)来生成PDF报告.Spring充斥着"Spring特定"方式与JasperReports集成以生成PDF:

我努力在网上找到好的,完整的例子,并想分享我的发现(见下面的答案).

随意添加与"如何将JasperReports与Spring4集成"相关的其他方法和/或改进?

Bri*_*ace 76

根据我的研究,我发现了以下使用方法.这些方法以最直接(天真)的方法开始,涉及较少的前端复杂性/配置,并逐渐演变为更抽象,但更多依赖于Spring /更复杂的Spring配置.

方法1:直接在Controller中使用JasperReports API

只需将内容写出到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);
  }
Run Code Online (Sandbox Code Playgroud)

方法2:将JasperReportPdf视图注入Controller

给定JasperReportsPdfView bean:

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

可以将此视图注入或连接到Controller中以供使用:

@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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,使用JasperReportsPdfView(或更通用JasperReportsMultiFormatView)需要依赖spring-context-support:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-support</artifactId>
  <version>4.1.3</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

方法3:使用XML或ResourceBundle视图解析程序将逻辑视图名称映射到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;
}
Run Code Online (Sandbox Code Playgroud)

然后,在我们的类路径的根目录下,该jasperreport-views.properties文件可以包含与重新绑定JasperReport相关的类和属性值(即url和reportDataKey)配对的逻辑视图名称:

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

控制器代码如下所示:

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

我喜欢这种方法.控制器保持"哑"并且仅处理字符串值,并且名称到视图的映射可以在一个位置发生.


方法4:使用JasperReportsViewResolver

配置零排序,JasperReportViewResolver然后使用技巧setViewNames告诉Spring您希望解析器处理哪些逻辑视图名称(否则最终会导致"无法从类路径资源加载JasperReports报告[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;
}
Run Code Online (Sandbox Code Playgroud)

在控制器内部:

@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;
}
Run Code Online (Sandbox Code Playgroud)

这是我的首选方法.控制器以非常类似的方式解析jasper报告,以及如何使用它来解析jsp视图,InternalResourceViewResolver因此不需要像上面方法#3中的xml或属性文件方法那样的显式映射文件.

编辑

提及它的javadocJasperReportsPdfView使用不推荐使用的JRExporterAPI.是否有更好的(更新的)JasperReports视图可供使用?也许选择它JasperReportsMultiFormatView是一个更好的选择,因为它似乎没有使用JRExporter.