【问题标题】:How to use JasperReports with Spring MVC?如何在 Spring MVC 中使用 JasperReports?
【发布时间】:2015-02-16 09:44:42
【问题描述】:

我一直在研究使用 JasperReports (6.0.0) 和 Spring MVC (4.1.3) 来生成 PDF 报告。 Spring 充斥着与 JasperReports 集成以生成 PDF 的“Spring 特定”方式:

我努力在网上找到好的、完整的示例,并想分享我的发现(请参阅my answer below)。

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

【问题讨论】:

标签: java spring spring-mvc jasper-reports spring-4


【解决方案1】:

我的方法:

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

【讨论】:

    【解决方案2】:

    根据我的研究,我发现了以下使用方法。这些方法从最直接(简单)的方法开始,涉及较少的前期复杂性/配置,并演变为更加抽象,但对 Spring 的依赖更多/更复杂的 Spring 配置。

    方法一:直接在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);
      }
    

    方法二:将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;
    }
    

    这个视图可以注入或连接到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>
    

    方法 3:使用 XML 或 ResourceBundle 视图解析器将逻辑视图名称映射到 JasperReport 视图

    配置一个新的视图解析器,在这种情况下,ResourceBundleViewResolverInternalResourceViewResolver 之前运行。这是基于设置的顺序值(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);
    }
    

    我喜欢这种方法。控制器保持“愚蠢”,只处理字符串值,名称到视图的映射可以在一个位置发生。


    方法四:使用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;
    }
    

    在控制器内部:

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

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

    编辑

    javadocs for JasperReportsPdfView 提到它使用已弃用的JRExporter API。是否有更好(更新)的 JasperReports 视图可供使用?也许选择JasperReportsMultiFormatView 是一个更好的选择,因为它似乎没有使用JRExporter

    【讨论】:

    • 帮助了我很多我在这里使用相同的示例应用程序github.com/gauravbrills/jasperreportswithspringboot
    • 我已经为 XLS 尝试了方法 #4,它有效。但是,生成的文件没有扩展名。如何使用方法#4设置生成文件的文件名和扩展名?
    • @Brice Ronance:你能帮我吗?我被困在查看我的 jasperreport stackoverflow.com/q/38390723/2666368
    • @Brice 你能告诉我“REPORT_VIRTUALIZER”将如何在这里使用
    • 感谢@Brice Roncace 的精彩解释。我正在使用方法 3,而且我总是一个空的 pdf。检查日志似乎没有从 BeanNameViewResolver:74 中找到模型视图 - 没有为视图名称“蓝色”找到匹配的 bean。你有什么建议吗?谢谢
    猜你喜欢
    • 2017-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多