【问题标题】:How to pass the db connection information and query parameters from controller to JasperReportsMultiFormatView如何将数据库连接信息和查询参数从控制器传递到 JasperReportsMultiFormatView
【发布时间】:2011-10-12 04:33:17
【问题描述】:

我正在使用带有 JasperReports 的 Spring MVC 3.0 对 Web 应用程序进行原型设计。 我已经使用 Spring + Jfreechart + iText + Apache POI 完成了报告应用程序,并且能够成功地使用 Spring 提供的相应视图类来流式传输 pdf、xls 和图像。

这次我想尝试使用 JasperReports,这样我就可以在应用程序之外设计我的 pdf,而不必担心了解底层 api(无论是 jfreechart、itext 还是 poi)。

问题

我有一个 report1.jrxml 文件,其中包含一个 queryString 标记,其中我的查询带有两个日期参数。当我通过 iReport 测试报告时,它编译并运行成功。这里没有问题。

现在我正在阅读以下 Spring 文档 http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#view-jasper-reports 中的 JasperReports 部分 我正在尝试让 JasperReportsMultiFormatView 正常工作,但有一件我不明白:

  1. JasperReportMultiFormatView 如何知道要连接的数据库(回想一下,我在报表本身中嵌入了查询)?

  2. 文档说明要在视图中使用 reportDataKey 属性,但我看不出这是如何解决我的问题的。

  3. 如何传递参数?

可以做什么

JaperReports 提供了一组 xxxManager 对象,负责编译、归档和导出报告。您可以创建一个实现 Spring View 接口的自定义类并执行以下操作:

Connection connection;
ServletOutputStream servletOutputStream = response .getOutputStream();
InputStream reportStream = getServlet().getServletConfig().getServletContext().getResourceAsStream("/reports/report1.jasper");
response.setContentType("application/pdf");
Class.forName("com.mysql.jdbc.Driver");
 connection = DriverManager.getConnection("jdbc:mysql://localhost: 
             3306/flightstats?user=user&password=secret");
JasperRunManager.runReportToPdfStream(reportStream,  
                 servletOutputStream, new HashMap(), connection);
connection.close();
servletOutputStream.flush();
servletOutputStream.close();

我需要什么

我需要完成上面那些利用 Spring 类的代码,例如 JasperReportsPdfView、JasperReportsXlsView,甚至更好的 JasperReportsMultiFormatView

因此,总而言之,我需要能够将以下内容从我的控制器传递到 jasper 报告:

  1. 参数
  2. Db 连接信息,以便 jasper 中的 queryString 知道要针对谁运行

这是我所拥有的,输出是一个空白的 PDF 文档,我假设是因为它不知道如何运行查询

@RequestMapping("/reports/**")
@Controller

public class ReportsController {

@RequestMapping(value ="/reports/usage/report", method = RequestMethod.GET)
public ModelAndView handleSimpleReportMulti(HttpServletRequest request, HttpServletResponse response) throws Exception {

    System.out.println("Made it here");

    Map model = new HashMap();
    //model.put("format", "pdf");
    model.put("START_DATE", new String("09-12-2011"));
    model.put("END_DATE", new String("09-17-2011"));

    return new ModelAndView("report1", model);
}
}

【问题讨论】:

    标签: spring-mvc jasper-reports


    【解决方案1】:

    我找到了我的问题的答案。我已将上面的控制器更改为:

    @RequestMapping(value ="/reports/usage/report/{format}", method = RequestMethod.GET)
    public ModelAndView handleSimpleReportMulti(ModelMap modelMap, @PathVariable("format") String format) throws Exception {
    
        //Map model = new HashMap();
        modelMap.put("format", format);
        modelMap.put("REPORT_CONNECTION", dataSource.getConnection());
        modelMap.put("START_DATE", new String("09-12-2011"));
        modelMap.put("END_DATE", new String("09-17-2011"));
    
        return new ModelAndView("report1", modelMap);       
    }
    

    我已将 view.properties 更改为:

    #report1(class)=org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
    report1(class)=org.springframework.web.servlet.view.jasperreports.JasperReportsMultiFormatView
    report1.url=/WEB-INF/reports/report1.jasper
    

    我希望这会有所帮助。

    谢谢

    【讨论】:

    • 你是怎么得到dataSource的,它是一个bean吗?
    【解决方案2】:

    我找到了另一种将连接作为参数传递,然后关闭它的方法。

    问题:
    我实现了上面的解决方案,问题是,每次我调用 PDF 时,都会创建一个新连接,因此当应用程序达到打开连接的最大限制时,它会崩溃。

        ReportesDAOJDBC reportes;
    
        public void setReportes(ReportesDAOJDBC reportes) {
                this.reportes = reportes;
        }
    
        public ModelAndView leoTest(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
    
        Map < String, Object > model = new HashMap < String, Object >();
        model.put("PARAMCONTRARECIBO", new Integer(1101));
        model.put("PARAMDOCTOS", new Integer(1101));
        model.put("REPORT_CONNECTION", reportes.getConexion());
    
        return new ModelAndView("leoTest",model);
        }
    

    将连接传递给JasperReport的参数是REPORT_CONNECTION,但正如我所说,这样做会引起很多麻烦。

    我的解决方案:

        ReportesDAOJDBC reportes;
    
        public void setReportes(ReportesDAOJDBC reportes) {
                this.reportes = reportes;
        }
    
        public ModelAndView leoTest(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
    
        Map < String, Object > model = new HashMap < String, Object >();
        model.put("PARAMCONTRARECIBO", new Integer(1101));
        model.put("PARAMDOCTOS", new Integer(1101));
        model.put("OBJETO_CONEXION", reportes);
    
        return new ModelAndView(new PdfView("leoTest"),model);
        }
    

    如您所见,我实现了自己的 PdfView,并在构造函数中传递了 view.properties 文件中定义的键名,还传递了对我的 DAO(报告)的引用作为 HashMap 的参数,参数名称为“OBJETO_CONEXION”。这是 ReportesDAOJDBC 的代码:

        public class ReportesDAOJDBC extends JdbcDaoSupport {
    
          public Connection getConexion() {
             Connection  con ;
             try {
                    con = getDataSource().getConnection();
             }
             catch (Exception e) {
               e.printStackTrace();
               return null;
             }
             return con;
          }
    
          public void closeConecction(Connection con) {
             try {
               if (con != null) {
                  con.close();
               }
             }
             catch (Exception e) {
                e.printStackTrace();
             }
           }
          }
    

    那么接下来就是给大家看下我自己的PdfView实现的代码了。

        import java.io.File;
        import java.io.OutputStream;
        import java.sql.Connection;
        import java.util.Map;
        import java.util.ResourceBundle;
    
        import javax.servlet.ServletContext;
        import javax.servlet.http.HttpServletRequest;
        import javax.servlet.http.HttpServletResponse;
    
        import mx.com.mexican.leinksy.dao.jdbc.ReportesDAOJDBC;
        import mx.com.mexican.leinksy.utils.Utils;
        import net.sf.jasperreports.engine.JasperExportManager;
        import net.sf.jasperreports.engine.JasperFillManager;
        import net.sf.jasperreports.engine.JasperPrint;
        import net.sf.jasperreports.engine.JasperReport;
        import net.sf.jasperreports.engine.util.JRLoader;
    
        import org.springframework.web.servlet.View;
        import org.springframework.web.servlet.view.ResourceBundleViewResolver;
    
        public class PdfView implements View {
    
            private static final String CONTENT_TYPE = "application/pdf";
            private String JASPER_URL;
    
    
            public PdfView(String jasperUrl){
                this.JASPER_URL = jasperUrl+".url";
            }
    
            @Override
            public String getContentType() {
                return CONTENT_TYPE;
            }
    
            @Override
            public void render(Map model, HttpServletRequest request,
                    HttpServletResponse response) throws Exception {
    
                System.out.println(Utils.getRealPath(request));
    
    
                ResourceBundle rb       = ResourceBundle.getBundle("view");/* Se lee el archivo view.properties*/
                ReportesDAOJDBC reporte = (ReportesDAOJDBC)model.get("OBJETO_CONEXION");/* Se obtiene el objeto de conexion */
                Connection con          = reporte.getConexion();/* Se genera la conexion a la base de datos*/
    
    
                String jasperFilePath     = Utils.getRealPath(request) + rb.getString( JASPER_URL );/* Se obtiene la ruta fisica del archivo .jasper a ejectuar*/
                JasperReport jasperReport = (JasperReport)JRLoader.loadObject(new File(jasperFilePath));/* Se carga el reporte ya compilado*/
                JasperPrint  jasperPrint  = JasperFillManager.fillReport(jasperReport, model, con);/* Se llena el reporte con datos del modelo y con la conexion a la BD*/
    
    
                try{
    
                    OutputStream out = response.getOutputStream();
    
                    JasperExportManager.exportReportToPdfStream(jasperPrint, out);/* Se manda el contenido a la salida estandar*/
    
                    out.flush(); 
                    out.close();
    
                }catch(Exception e){
                    e.printStackTrace();
                }
    
                reporte.closeConecction(con);/* Cierro la conexion a la base de datos para liberar el pool*/
    
            }
    
        }
    

    如您所见,我使用 ResourceBoundle 类读取 view.properties 文件以获取要加载的 .jasper 文件的路径和名称,另外请注意,我没有编译 .jrxml 文件,我只是加载编译后的文件,我用 IREPORTS 编译 jrxml。我也有一个实用程序来获取我的 .jasper 文件的路径,如果你不知道怎么做,这里是代码。

    public static String getRealPath(HttpServletRequest req) {
        ServletContext context = req.getSession().getServletContext();
        String path = context.getRealPath("/");
    
        if (path != null) {
            if (!path.endsWith(File.separator)) {
                path += File.separator;
            }
        }
        return  path;
    }
    

    通过这个实现,我可以控制在哪里打开关闭连接,我也尊重 SPRING 的 MVC 模型,而且我仍然使用 view.properties。

    在这一点上,也许你在问如果我想要一个 EXCEL 文件该怎么办,好吧,我还实现了一个 XlsView,(Ajuuaaaa !!! )。代码如下:

       import java.io.File;
       import java.io.OutputStream;
       import java.sql.Connection;
       import java.util.Map;
       import java.util.ResourceBundle;
    
       import javax.servlet.ServletContext;
       import javax.servlet.http.HttpServletRequest;
       import javax.servlet.http.HttpServletResponse;
    
       import mx.com.mexican.leinsky.dao.jdbc.ReportesDAOJDBC;
       import mx.com.mexican.leinksy.utils.Utils;
       import net.sf.jasperreports.engine.JasperExportManager;
       import net.sf.jasperreports.engine.JasperFillManager;
       import net.sf.jasperreports.engine.JasperPrint;
       import net.sf.jasperreports.engine.JasperReport;
       import net.sf.jasperreports.engine.export.JRXlsExporter;
       import net.sf.jasperreports.engine.export.JRXlsExporterParameter;
       import net.sf.jasperreports.engine.util.JRLoader;
    
       import org.springframework.web.servlet.View;
       import org.springframework.web.servlet.view.ResourceBundleViewResolver;
    
       public class XlsView implements View {
    
        private static final String CONTENT_TYPE = "application/vnd.ms-excel";
        private String JASPER_URL;
        private String FILE_NAME = "XLSFile";
    
    
        public XlsView(String jasperUrl){
            this.JASPER_URL = jasperUrl+".url";
        }
    
        @Override
        public String getContentType() {
            return CONTENT_TYPE;
        }
    
        @Override
        public void render(Map model, HttpServletRequest request,
                HttpServletResponse response) throws Exception {
    
            if(model.get("FILE_NAME")!=null){
                this.FILE_NAME = model.get("FILE_NAME").toString();
            }
    
    
            ResourceBundle rb       = ResourceBundle.getBundle("view");/* Se lee el archivo view.properties*/
            ReportesDAOJDBC reporte = (ReportesDAOJDBC)model.get("OBJETO_CONEXION");/* Se obtiene el objeto de conexion */
            Connection con          = reporte.getConexion();/* Se genera la conexion a la base de datos*/
    
    
            String jasperFilePath     = Utils.getRealPath(request) + rb.getString( JASPER_URL );/* Se obtiene la ruta fisica del archivo .jasper a ejectuar*/
            JasperReport jasperReport = (JasperReport)JRLoader.loadObject(new File(jasperFilePath));/* Se carga el reporte ya compilado*/
            JasperPrint  jasperPrint  = JasperFillManager.fillReport(jasperReport, model, con);/* Se llena el reporte con datos del modelo y con la conexion a la BD*/
    
            response.setContentType("application/vnd.ms-excel");
            response.setHeader("Content-Disposition","attachment; filename=\""+FILE_NAME+".xls\"");
            response.setHeader("Pragma", "No-cache");
            response.setDateHeader("Expires", 1);
    
            try{
    
                OutputStream out = response.getOutputStream();
    
            JRXlsExporter exporterXLS = new JRXlsExporter();
            exporterXLS.setParameter(JRXlsExporterParameter.JASPER_PRINT,jasperPrint);
            exporterXLS.setParameter(JRXlsExporterParameter.OUTPUT_STREAM,out);
            exporterXLS.exportReport();
    
            out.flush(); 
            out.close();
    
        }catch(Exception e){
            e.printStackTrace();
        }
    
        reporte.closeConecction(con);/* Cierro la conexion a la base de datos para liberar el pool*/
    
    }
    

    }

    所以这是我的解决方案,希望它有所帮助!

    【讨论】:

      猜你喜欢
      • 2015-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-09
      • 1970-01-01
      • 1970-01-01
      • 2020-05-14
      • 1970-01-01
      相关资源
      最近更新 更多