GENERAR REPORTE .XLS CON IREPORT EN JSP

Para generar reportes en .xls usando ireport debemos tener en cuenta que necesitamos un archivo en blanco .xls creado en alguna carpeta pues este sera el archivo que llamaremos desde jsp para que nuestro reporte.jasper sea generado alli.

Primero incluimos las librerias

<%@page import = "net.sf.jasperreports.engine.JRException"%>
<%@page import = "net.sf.jasperreports.engine.JRExporterParameter"%>
<%@page import = "net.sf.jasperreports.engine.JasperFillManager"%>
<%@page import = "net.sf.jasperreports.engine.JasperPrint"%>
<%@page import = "net.sf.jasperreports.engine.JasperReport"%>
<%@page import = "net.sf.jasperreports.engine.export.JRXlsAbstractExporterParameter"%>
<%@page import = "net.sf.jasperreports.engine.export.JRXlsExporter"%>
<%@page import = "net.sf.jasperreports.engine.export.JRXlsExporterParameter"%>
<%@page import = "net.sf.jasperreports.engine.util.JRLoader"%>
<%@page import = "net.sf.jasperreports.engine.export.JRPdfExporter"%>
<%@page import = "net.sf.jasperreports.engine.export.JRPdfExporterParameter"%>

luego de declarar las variables que vayamos a tener en cuenta para nuestro reporte debemos adicionar la siguiente linea:
<%
String var="";
String ca="";
String cam="";
int a=0;
.....
JasperReport reporte = null;

en esta parte empezamos a hacer las consultas sql, que generan los parametros que necesitemos para enviarlos luego a nuestro reporte

try{
Statement comando11 = con.createStatement();
ResultSet v1 = comando11.executeQuery("SELECT * FROM \"Nuestra tabla\" a1 WHERE a1.\"campo1\"='"+vart+"' and a3.\"campo2\"='"+a+"' ORDER BY a1.\"campo1\"");
//out.println("Consulta: "+v1+"");

while (v1.next()){
ca= v1.getString("campo1");
cam= v1.getString("campo2");
}
}catch (Exception e){}

luego de hacer nuestra consulta adicionamos lo siguiente:

try {
reporte = (JasperReport) JRLoader.loadObject("C:\aqui especificamos la ruta en donde esta nuestro reporte\\mireporte.jasper");
} catch (JRException e) {
e.printStackTrace();
}

luego ponemos los parametros que necesitamos:

HashMap parametros = new HashMap();
parametros.put("careporte",ca);
parametros.put("camreporte",cam);

JasperPrint print = null;

Luego especificamos la conexion con nuestra base de datos:(en este caso uso postgress)
try {
DriverManager.registerDriver(new org.postgresql.Driver());
} catch (SQLException e3) {
e3.printStackTrace();
}

Connection conexion = null;

try {
conexion = DriverManager.getConnection(
"jdbc:postgresql://localhost:5432/NOMBRE_DE_MI_BD",
"NOMBRE_DEL_USUARIO_DE_MI_BD", "CONTRASEÑA_DE_MI_BD");
} catch (SQLException e2) {
e2.printStackTrace();
}

try {
//print = JasperFillManager.fillReport(reporte, null, conexion);
print = JasperFillManager.fillReport(reporte, parametros, conexion);
} catch (JRException e1) {
e1.printStackTrace();
}

////REPORTE EN EXCELLLLLLLLLLLLL////////////////////

JRXlsExporter exportador = new JRXlsExporter();
exportador.setParameter(JRExporterParameter.JASPER_PRINT, print);
exportador.setParameter(JRExporterParameter.OUTPUT_FILE_NAME,
"C:\\especificamos la ruta en donde esta el archivo de excel en blanco que mostrara lo que mi reporte hecho en ireport genera\\PruebaExcel.xls");
exportador.setParameter(JRExporterParameter.IGNORE_PAGE_MARGINS, true);
exportador.setParameter(
JRXlsAbstractExporterParameter.IS_WHITE_PAGE_BACKGROUND, false);
exportador.setParameter(
JRXlsAbstractExporterParameter.IS_IGNORE_CELL_BORDER, false);
exportador
.setParameter(
JRXlsAbstractExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_COLUMNS,
true);
exportador
.setParameter(
JRXlsAbstractExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS,
true);
exportador
.setParameter(
JRXlsAbstractExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS,
true);
exportador.setParameter(JRXlsExporterParameter.IS_DETECT_CELL_TYPE,
true);

try {
exportador.exportReport();
} catch (JRException e) {
e.printStackTrace();
}

FileInputStream entrada = new FileInputStream("C:especificamos la ruta en donde esta el archivo de excel en blanco que mostrara lo que mi reporte hecho en ireport genera\\PruebaExcel.xls");
byte[] lectura = new byte[entrada.available()];
entrada.read(lectura);
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition","attachment; filename=PruebaExcel.xls");
response.setContentLength(lectura.length);
response.getOutputStream().write(lectura);
response.getOutputStream().flush();
response.getOutputStream().close();
entrada.close();
%>

y listo.

Espero que haya servido de algo.

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de ezamudio

Algunas recomendaciones

Muy útil el ejemplo, realmente con Jasper se simplifica mucho la generación de reportes en Excel o PDF. Sin embargo quiero mencionar algunos detalles de este código, principalmente porque puede haber quienes copien y peguen el código tal cual lo pusiste y luego puedan tener problemas:

Se considera una mala práctica poner tanto código Java en un JSP. Para efectos de la ilustración está bien, aunque realmente el código puede ser parte de un componente o de un servlet o de cualquier otra cosa. Sería mejor que hicieras un componente o un tag o algo que contenga ese código y solamente invocarlo desde el JSP.

Otras malas prácticas en el ejemplo son crear conexiones a base de datos desde JSP, y construir sentencias SQL concatenando los parámetros en vez de usar PreparedStatements parametrizados. Si las variables vart o a vienen de valores que puso el usuario, estás vulnerable a un ataque de inyección de SQL.

El ResultSet v1 y el Statement comando11 no los cierras nunca, eso es un problema porque si luego no cierras la conexión se empiezan a desperdiciar muchos recursos en el servidor de base de datos. La conexion a PostgreSQL nunca la cierras; debes poner un try-finally aunque sea sin el catch para cerrar la conexión en el finally (siempre y cuando exista):

Connection conn = null;
try {
  conn = ...//obtener conexion
} finally {
  if (conn != null) {
    conn.close();
  }
}

Y la mejor manera de obtener conexiones a base de datos es usar un DataSource, que tengas como componente en tu aplicación, para no tener que creas conexiones independientes como estás haciendo. Esto te permite que posteriormente en producción se pueda poner un pool de conexiones a base de datos sin necesitas de modificar nada en tu código.

Otra mala práctica es cachar Exception y no hacer nada en el catch...

y por último, puede considerarse mala práctica leer completo un archivo a memoria para devolverlo en la respuesta al browser. Si el reporte es muy grande y el archivo llega a medir varios megabytes, la generación de ese reporte va a usar mucha memoria. Si esa página es parte de una aplicación que puede tener muchos usuarios concurrentes, suponiendo que el archivo de excel generado en promedio mide 5MB, con 20 usuarios que lo pidan más o menos al mismo tiempo, se van a ocupar 100MB de memoria en el server. Es mejor que hagas un buffer de unos pocos kilobytes (digamos unos 64 o 128KB) y hagas un ciclo en donde vas leyendo del archivo al buffer y luego escribes el buffer al stream de la respuesta.

Espero les sirvan estos tips, tanto a jenn (quien hizo favor de publicar este ejemplo de Jasper) como a quienes lo usen de guía.

muchas gracias por tus

muchas gracias por tus recomendaciones!!
puede que asi me este ffuncionando el codigo, pero por rendimiento y seguridad tendre en cuenta lo que dices. Gracias

generar archivos .txt desde jsp

Hola oye tengo una pregunta, me gustaria saber si podrias ayudarme con esto...

Necesito leer unas tablas en postgres y quelos datos que tengan esas tablas me los arroje en .txt, haciendo todo esto desde jsp
Sabes como lo puedo hacer.... ???

al principio pense en sacar un reporte en .txt con ireport, pero necesito que dentro de un mismo formulario se ejecuten mas o menos 7 consultas a 7 tablas diferentes y que me genere un archivo por cada tabla, asi que creo que el reporte no me seria de utilidad y de verdad no tengo idea de como hacer esto.. no se como hacer que las consultas sql que hago dentro de jsp a las tablas de postgres me generen con algun comando que se yo los archivos, que luego guardare çen una ruta especifica que me de el usuario (la cual la estoy guardadndo o generando con mkdir).

alguna idea????

Gracias por tu tiempo. :)

Imagen de ezamudio

si entendí bien el

si entendí bien el problema, tienes que devolver los resultados de 7 tablas diferentes en una sola respuesta? Pues solamente que pongas todo en un archivo de texto mas o menos con este formato:

c1t1|c2t1|c3t1
------------------------------
r1c1t1|r1c2t1|r1c3t1
r2c1t1|r2c2t1|r2c3t1
etc

c1t2|c2t2
---------------
r1c1t2|r1c2t2
r2c1t2|r2c2t2
r3c1t2|r3c2t2
etc

c1t3|c2t3|c3t3|c4t3
etc

O sea los resultados de cada tabla uno tras otro en el mismo archivo. Todo depende de quién lo va a leer, de eso depende la solución.

Otra opción es devolver un ZIP con los resultados de cada tabla en un archivo por separado. Para eso tendrías que cambiar en la respuesta del JSP el tipo MIME y crear un ZipOutputStream sobre el OutputStream el socket para ir escribiendo cada archivo y cerrándolo, generando el zip al vuelo sin tener que almacenarlo primero en el servidor.

El ZipOutputStream maneja un ZipEntry por cada archivo; tendrías que crear el ZipOutputStream, luego para cada tabla creas un nuevo ZipEntry con el nombre del archivo que quieres que tenga los datos de esa tabla, abres el ResultSet, vas obteniendo datos y escribiendo al ZipOutputStream una linea de texto con los datos del renglón en cuestión y cuando terminas de leer el ResultSet lo cierras, luego cierras el ZipEntry... al final de que enviaste todas las tablas no recuerdo si nada más hay que cerrar el ZipOutputStream o hay que hacer otra cosa pero pues en el javadoc de la clase te indica cómo se usa.

YA LO HICEE!!!

Hola.. bueno siguiendo tus consejos y buscando un poco mas encontre la manera de que mi formulario haga la consulta en mis 11 tablas y saque un .txt diferente por cada tabla es decir 11 .txt :)

La cosa ahora es que necesito que no me genere estos archivos en caso tal de que la tabla se encuentre vacia...

puse una instrucion que busque por ahi leyendoi un poco que es miarchivo.delete();
PERO NO ME FUNCIONO!!!
Lo que estoy haciendo es basicamente lo siguiente:

<%

java.util.Calendar fecha2 = java.util.Calendar.getInstance();
int anio=(fecha2.get(java.util.Calendar.YEAR));
int mes=(fecha2.get(java.util.Calendar.MONTH))+1;
int dia=(fecha2.get(java.util.Calendar.DATE));

String filename=anio+"-"+mes+"-"+dia+".txt";
out.print("<br><br>fn"+filename);

FileWriter fichero = null;

// AQUI RECIBOS LOS COMO PARAMETRO LA RUTA QUE DIGITA EL USUARIO

String nruta=disco+ruta;
int i=ruta.length();
String val="";
String backslash=ruta.substring(ruta.length()-1,ruta.length());
out.print("<br><br>fn='"+backslash+"'");
String aux="";
if(!backslash.equals("\\"))
        aux="\\";
else
        aux="";

//HAGO LAS VALIDACIONES DE CARACTERES

for(int a=0;a<i;a++)
{
        val=ruta.substring(a,a+1);
        if((val.equals(":")) || (val.equals("/")) || (val.equals("<")) || (val.equals(">")) || (val.equals("*")) || (val.equals("?")) || (val.equals("\"")) || (val.equals("|")))
        {
                out.print("<script>window.alert('Una ruta no puede contener ninguno de los siguientes caracteres: /,<,>,*,?,:,\",|')</script>");
                out.print("<script>window.history.back();</script>");
                out.close();
        }
}

// CREO EL ARCHIVO

File compruta=new File(nruta);
boolean directorio=compruta.mkdir();
if(directorio=false)
{
        out.print("<script>window.alert('Error al crear el directorio')</script>");
        out.close();
}

String rutacompleta=nruta+aux+filename;

// CREO LA INSTANCIA DEL FICHERO

fichero = new FileWriter(rutacompleta);
out.print("<br><br>RC"+rutacompleta);

//HAGO LA CONSULTA A UNA DE MIS TABLAS

String nomcom="";
String doc="";
try{
        Statement comando = con.createStatement();
        ResultSet v1 = comando.executeQuery("SELECT documento,nombrecompleto FROM terceros");
    while (v1.next()){
                        nomcom=v1.getString("nombrecompleto");
                        doc=v1.getString("documento");
                        if(nomcom==null) nomcom="";                    
                        nomcom=nomcom.trim();
                        if(doc==null) doc="";                  
                        doc=doc.trim();
                       
                        try
                        {
                                // El carácter \r\n es el que hace que salte una linia en el fichero después de escribir
                                fichero.write(""+doc+","+nomcom+"\r\n");
                                // Cierras el fichero
                        }
                        catch(IOException ioe){out.print(ioe);}
        }//while
        fichero.close();
}catch (Exception e){} 

// Y JUSTO AKI PONGO LA LINEA DE LA QUE LES HABLE Y NO ME FUNCIONAAA!!!!

                fichero.delete();

out.print("El proceso finalizo");
%>  

Podrian ayudarme con esto, por favorrr???

Imagen de ezamudio

File.delete()

El método delete() es de la clase File, no FileWriter. Por lo tanto debes hacer compruta.delete().

Un consejo y fuerte recomendación: LEE LAS EXCEPCIONES! El stack trace te dicen todo lo que necesitas saber, el error, la linea, etc. NoSuchMethodException es bastante claro.

reporte!!!!

HOLA!!!! MUY INTERESANTE TU REPORTE!! YO HICE UNA APLICACION CON IREPORT 3.0.0 Y NETBEANS 6.1 Y GENERE MI REPORTE!! PERO AHORA TENGO UN PROBLEMA , VOY A DESARROLLAR UNA APLICACION EN NETBEANS DONDE PONDRE UN SENTENCIA MYSQL (MI CONSULTA) Y A PARTIR DE LA SENTENCIA QUE PONGA EN UNA CAJA DE TEXTO!! AL DARLE CLIC EN UN BOTON QUE DIGA GENERAR REPORTE ME TIENE QUE ARROJAR MI REPORTE CON LA CONSULTA QUE YO LE DI ANTERIORMENTE, ESPERO Y ME PUEDAS AYUDAR U ORIENTAR PARA VER SI MI APLICACION ES FACTIBLE!!....... POR TU ATENCION GRACIAS!!

Re: reporte!!!!

Creo que no es factible, hasta donde yo me quedé hace algunos años JasperReports requiere establecer en tiempo de diseño el número de campos en el reporte. Además la manera en que planteas la aplicación sería un "honey pot" para ataques por inyección de SQL.

Saludos

Javier
PD. En Internet se considera de mala educación escribir todo con mayúsculas.

Urgente

Hola, tengo un problema y ojala me puedan ayudar. Uso el Ireport 3.5.3 para generar reportes con mi aplicacion que esta en NetBeans 6.8 uso jsp para llamar a los jrxml, y el Tomcat como contenedor de la aplicacion en algunas ocasiones genera los reportes en excel sin problema alguno pero en otras me sale un mensaje de error que dice " Excel ha encontrado contenido que no se puede leer en "PerdidaTx.xls" ¿Desea recuperar el contenido?, cuando le doy si me sale el reporte pero sin formato. Esto me ha traido varios problemas en el trabajo . ¿Que puedo hacer? Gracias por la ayuda de antemano.