我一直在调查使用JasperReports(6.0.0)和Spring MVC(4.1.3)来生成PDF报告。 Spring充斥着“Spring特定”方式与JasperReports集成以生成PDF:
JasperReportsPdfView
依赖于现已弃用的JasperReport功能 JasperReportsMultiFormatView
JasperReportsViewResolver
我努力在网上找到好的,完整的例子并希望分享我的发现(见my answer below)。
随意添加与“如何将JasperReports与Spring4集成”相关的其他方法和/或改进?
答案 0 :(得分:74)
根据我的研究,我发现了以下使用方法。这些方法以最直接(天真)的方法开始,涉及较少的前端复杂性/配置,并且演变为更抽象,但对Spring /更复杂的Spring配置有更多的依赖。
只需将内容写出到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);
}
鉴于JasperReportsPdfView bean:
@Bean @Qualifier("helloWorldReport2")
public JasperReportsPdfView getHelloWorldReport() {
JasperReportsPdfView v = new JasperReportsPdfView();
v.setUrl("classpath:jasperreports/HelloWorld2.jasper");
v.setReportDataKey("datasource");
return v;
}
可以将此视图注入或连接到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;
}
请注意,使用JasperReportsPdfView
(或更通用的JasperReportsMultiFormatView
)需要依赖spring-context-support:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.3</version>
</dependency>
配置新的视图解析程序,在这种情况下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
文件可以包含与重新绑定JasperReport相关的类和属性值(即url和reportDataKey)配对的逻辑视图名称:
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);
}
我喜欢这种方法。控制器保持愚蠢&#34;并且只处理String值,并且名称到视图的映射可以在一个位置发生。
配置一个零序的JasperReportViewResolver
,然后使用setViewNames
来告诉Spring你希望这个解析器处理哪些逻辑视图名称(否则你最终得到&#34;无法加载来自类路径资源的JasperReports报告[jasperreports / index.jasper]&#34;类型错误):
@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报告,因此不需要像上面方法#3中的xml或属性文件方法那样显式映射文件。
编辑
javadocs for JasperReportsPdfView
提到它使用已弃用的JRExporter
API。是否有更好的(更新的)JasperReports视图可供使用?也许选择JasperReportsMultiFormatView
是一个更好的选择,因为它似乎没有使用JRExporter
。
答案 1 :(得分:0)
我的方法:
@RequestMapping(value="getPDF", method=RequestMethod.GET)
public void generatePDF(int idPredstave, HttpServletResponse response) throws Exception{
Predstava p = pr.findById(idPredstave).get();
List<Uloga> uloge = ur.findByPredstava(p);
response.setContentType("text/html");
JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(uloge);
InputStream inputStream = this.getClass().getResourceAsStream("/jasperreports/Uloge.jrxml");
JasperReport jasperReport = JasperCompileManager.compileReport(inputStream);
Map<String, Object> params = new HashMap<String, Object>();
params.put("nazivPredstave", p.getNaziv());
params.put("trajanje", p.getTrajanje());
params.put("opis", p.getOpis());
params.put("zanr", p.getZanr().getNaziv());
params.put("reziser", p.getReziser().getIme()+" "+p.getReziser().getPrezime());
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, params, dataSource);
inputStream.close();
response.setContentType("application/x-download");
response.addHeader("Content-disposition", "attachment; filename=Uloge.pdf");
OutputStream out = response.getOutputStream();
JasperExportManager.exportReportToPdfStream(jasperPrint,out);
}