Как передать информацию о соединении БД и параметры запроса из контроллера в JasperReportsMultiFormatView - PullRequest
6 голосов
/ 12 октября 2011

Я создаю прототип веб-приложения, используя Spring MVC 3.0 с JasperReports.Я уже сделал отчеты приложений, используя Spring + Jfreechart + iText + Apache POI и смог успешно использовать соответствующие классы представления, предоставляемые Spring для потоковой передачи PDF, XLS и изображений.

На этот раз я хочу попробовать использовать JasperReports, чтобы я мог создавать свои PDF-файлы вне приложения и не беспокоиться о знании базового API (будь то jfreechart, itext или poi).

Проблема

У меня есть файл report1.jrxml, который содержит тег queryString с моим запросом с двумя параметрами даты.Когда я тестирую отчет через iReport, он успешно компилируется и запускается.Здесь нет проблем.

Теперь я читаю раздел JasperReports из следующей документации Spring http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#view-jasper-reports и пытаюсь заставить 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. Информация о подключении к базе данных, так что 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);
}
}

Ответы [ 2 ]

8 голосов
/ 12 октября 2011

Я нашел ответ на свой вопрос. Я изменил свой контроллер выше на это:

@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

Надеюсь, это поможет.

Спасибо

4 голосов
/ 04 апреля 2012

Я нашел другой способ передать соединение в качестве параметра, а затем закрыть его.

ПРОБЛЕМА:
Я реализовал решение, описанное выше, и проблема заключалась в том, что каждый раз, когда я вызываю 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 (reportes) в качестве параметра 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*/

        }

    }

Как вы можете видеть, я прочитал файл view.properties, используя класс ResourceBoundle, чтобы получить путь и имя файла .jasper для загрузки. Также обратите внимание, что я не компилирую файл .jrxml, я просто загружаю скомпилированный файл, Я собираю JRXML с IREPORTS. Также у меня есть утилита для получения пути к моему файлу .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;
}

С этой реализацией я могу контролировать, где открывать закрытое соединение, также я уважаю модель MVC SPRING, а также я все еще использую view.properties.

И в этот момент, возможно, вы спрашиваете, ЧТО Я МОГУ ДЕЛАТЬ, ЕСЛИ ХОЧУ ФАКСОВЫЙ ФАЙЛ, ну, я также реализую 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*/

}

}

Так что это мое решение, надеюсь, это поможет !!!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...