问题描述
我一直在调查使用JasperReports(6.0.0)和Spring MVC(4.1.3)来生成PDF报告。 Spring充斥着Spring特定方式与JasperReports集成以生成PDF:
I've been investigating the use of JasperReports (6.0.0) with Spring MVC (4.1.3) to generate PDF reports. Spring is rife with "Spring specific" ways to integrate with JasperReports to generate PDFs:
- 使用 依赖于现已弃用的JasperReport功能
- 使用
- Use
JasperReportsPdfView
relies on now deprecated JasperReport features - Use
JasperReportsMultiFormatView
- Use
JasperReportsViewResolver
我努力在网上找到好的,完整的例子并希望分享我的发现ngs(参见)。
I struggled to find good, complete examples online and wanted to share my findings (see my answer below).
随意添加与如何将JasperReports与Spring4集成相关的其他方法和/或改进?
Feel free to add additional methods and/or improvements related to "How can I integrate JasperReports with Spring4"?
推荐答案
根据我的研究,我发现了以下使用方法。这些方法以最直接(天真)的方法开始,涉及较少的前端复杂性/配置,并演变为更抽象,但对Spring /更复杂的Spring配置具有更多依赖性。
Based on my research, I've found the following usage methods. The methods begin with the most direct (naive) approach involving less up front complexity / configuration and evolve to become more abstract but with more dependencies on Spring / more complex Spring configuration.
只需将内容写出到servlet输出流。
Just write out the content to the servlet output stream.
@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:
Method 2: Inject JasperReportPdf View into Controller
Given the JasperReportsPdfView bean:
@Bean @Qualifier("helloWorldReport2")
public JasperReportsPdfView getHelloWorldReport() {
JasperReportsPdfView v = new JasperReportsPdfView();
v.setUrl("classpath:jasperreports/HelloWorld2.jasper");
v.setReportDataKey("datasource");
return v;
}
此视图可以注入或连接到Controller中使用:
This view can be injected or wired into the Controller for use:
@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:
Note that using the JasperReportsPdfView
(or the more versatile JasperReportsMultiFormatView
) requires a dependency on spring-context-support:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.3</version>
</dependency>
方法3:使用XML或ResourceBundle视图解析器将逻辑视图名称映射到JasperReport视图
配置一个新的视图解析器,在这种情况下, ResourceBundleViewResolver
在之前运行的InternalResourceViewResolver
。这是基于设置的订单值(0发生在1之前):
Method 3: Use XML or ResourceBundle view resolver to map logical view names to JasperReport views
Configure a new view resolver, in this case the ResourceBundleViewResolver
to run before the InternalResourceViewResolver
. This is based on the order values being set (0 happens before 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
文件可以包含与重新绑定JasperReport相关的类和属性值(即url和reportDataKey)配对的逻辑视图名称:
Then, at the root of our classpath, the jasperreport-views.properties
file can contain the logical view name paired with the class and property values (i.e. url and reportDataKey) pertinent to rending a 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);
}
我喜欢这种方法。控制器保持哑并且只处理字符串值,并且名称到视图的映射可以在一个位置发生。
I like this approach. Controllers stay "dumb" and only deal with String values and the mapping of names to views can happen all in one location.
配置零 - 命令 JasperReportViewResolver
,诀窍是使用 setViewNames
告诉Spring你希望这个解析器处理哪些逻辑视图名称(否则你最终得到无法从类路径资源加载JasperReports报告[jasperreports / index.jasper]类型错误):
Configure a zero-ordered JasperReportViewResolver
and the trick is use setViewNames
to tell Spring which logical view names you want this resolver to deal with (otherwise you end up with "Could not load JasperReports report from class path resource [jasperreports/index.jasper]" type errors):
@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;
}
这是我的首选方法。控制器以与使用 InternalResourceViewResolver
解析jsp视图的方式非常类似的方式解析jasper报告,因此不需要像xml或属性文件方法那样的显式映射文件在上面的方法#3中。
This is my preferred approach. Controllers resolve jasper reports in a very similar fashion to how jsp views are resolved using the InternalResourceViewResolver
and there is therefore no need for an explicit mapping file as with the xml or properties file approach in method #3 above.
编辑
提及它使用已弃用的 JRExporter
API。是否有更好的(更新的)JasperReports视图可供使用?也许选择是一个更好的选择,因为它似乎没有使用 JRExporter
。
The javadocs for JasperReportsPdfView
mention it uses the deprecated JRExporter
API. Is there a better (newer) JasperReports view to use? Perhaps opting for the JasperReportsMultiFormatView
is a better option as it does not appear to use JRExporter
.
这篇关于如何在Spring MVC中使用JasperReports?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!