Sisi002 Sisi002 - 3 months ago 27
Java Question

When I Download Excel file from Java not show "Save as" Window, but the file is correctly saved

I want to show to the user the "Save as" Windows when i click in the option "Export File" of my app, the file is an excel 2007 than i have created with Apache POI. The file is correctly saved in the Folder "D:\jboss-6.1.0.Final\bin" but indstead to show the window "Save as" it redirect to a page with strange symbols and characters .

The most strange is I have other button for download a excel file in other page of my app, and with tha same code y with POI also, the "Save as" appears normally.

Why does it happen???

Thank you.

I attach an image.enter image description here

The code of the function Export is :

public void exportarTabla(){

XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet("Hoja 1");
XSSFRow row;
XSSFCell cell;

for (int i = 0; i < getLstEtiquetasCol().size(); i++) {
row = sheet.createRow(i+3);
for (int j = 0; j < getLstEtiquetasCol().get(i).size(); j++) {
cell = row.createCell(j+3+getLstEtiquetasFil().get(0).size());
cell.setCellValue(getLstEtiquetasCol().get(i).get(j).getValor().getEtiqueta());
}
}


for (int i = 0; i < getLstEtiquetasFil().size(); i++) {
row = sheet.createRow( i+3+getLstEtiquetasCol().size());
for (int j = 0; j < getLstEtiquetasFil().get(i).size(); j++) {
cell = row.createCell(j+3);
cell.setCellValue(getLstEtiquetasFil().get(i).get(j).getValor().getEtiqueta());
}
}


for (int i = 0; i < getTableContact().size(); i++) {
row = sheet.getRow( i+3+getLstEtiquetasCol().size());
for (int j = 0; j < getTableContact().get(i).size(); j++) {
cell = row.createCell(j+3+getLstEtiquetasFil().get(0).size());
cell.setCellValue(Double.parseDouble(getTableContact().get(i).get(j).getEtiqueta()));
}
}


try {

this.archivo_salida = "D:/jboss-6.1.0.Final/bin/output2.xlsx";
FileOutputStream fileOut = new FileOutputStream(new File(archivo_salida));
workbook.write(fileOut);

if(fileOut != null){
try{
File ficheroXLS = new File(archivo_salida);
FacesContext ctx = FacesContext.getCurrentInstance();
FileInputStream fis = new FileInputStream(ficheroXLS);
byte[] bytes = new byte[1000];
int read = 0;

if (!ctx.getResponseComplete()) {
String fileName = ficheroXLS.getName();
String contentType = "application/vnd.ms-excel";
//String contentType = "application/pdf";
HttpServletResponse response =(HttpServletResponse) ctx.getExternalContext().getResponse();
response.setContentType(contentType);
response.setHeader("Content-Disposition","attachment;filename=\"" + fileName + "\"");
ServletOutputStream out = response.getOutputStream();

while ((read = fis.read(bytes)) != -1) {
out.write(bytes, 0, read);
}

out.flush();
out.close();
System.out.println("\nDescargado\n");
ctx.responseComplete();
}
}catch(IOException e){
e.printStackTrace();
} finally {
try {
if (fileOut != null) {
fileOut.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

} catch (IOException e) {
e.printStackTrace();
}
}


the WEB.xml

<?xml version="1.0" ?>


http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">

<!-- RichFaces -->

<context-param>
<param-name>org.richfaces.SKIN</param-name>
<param-value>blueSky</param-value>
</context-param>

<!-- Suppress spurious stylesheets -->

<context-param>
<param-name>org.richfaces.CONTROL_SKINNING</param-name>
<param-value>disable</param-value>
</context-param>

<context-param>
<param-name>org.richfaces.CONTROL_SKINNING_CLASSES</param-name>
<param-value>disable</param-value>
</context-param>

<!-- Change load strategy to DEFAULT to disable sending scripts/styles as
packs -->

<context-param>
<param-name>org.richfaces.LoadStyleStrategy</param-name>
<param-value>ALL</param-value>
</context-param>

<context-param>
<param-name>org.richfaces.LoadScriptStrategy</param-name>
<param-value>ALL</param-value>
</context-param>

<!-- Seam -->

<listener>
<listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
</listener>

<filter>
<filter-name>Seam Filter</filter-name>
<filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>

<init-param>
<param-name>maxRequestSize</param-name>
<param-value>1000000</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>Seam Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>
<servlet-name>Seam Resource Servlet</servlet-name>
<servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>Seam Resource Servlet</servlet-name>
<url-pattern>/seam/resource/*</url-pattern>
</servlet-mapping>

<!-- Facelets development mode (disable in production) -->

<context-param>
<param-name>facelets.DEVELOPMENT</param-name>
<param-value>@debug@</param-value>
</context-param>

<!-- JSF -->

<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>

<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.seam</url-pattern>
</servlet-mapping>

<security-constraint>
<display-name>Restrict raw XHTML Documents</display-name>
<web-resource-collection>
<web-resource-name>XHTML</web-resource-name>
<url-pattern>*.xhtml</url-pattern>
</web-resource-collection>
<auth-constraint />
</security-constraint>

<persistence-unit-ref>
<persistence-unit-ref-name>demoencuesta06/pu</persistence-unit-ref-name>
<persistence-unit-name>demoencuesta06</persistence-unit-name>
</persistence-unit-ref>



Answer

First : Unless you have only one person accessing this report you do know that using a fixed path like you have means that if there are two requests at the same time - the results are not known - most probably one will not get a file or will see the other's data. In some cases the file can be corrupted.

You need to save the data with a random name on the server (you can use the java.io.File.createTempFile(String "3-char-min", String ".xls", File directoryOnServer)

Now after making a new file, in the page after button click you need to set the content type in the page to application excel BEFORE any output, and the only output should be the binary data. I do not know about rich faces but in jsps have seen people insert new lines in the header between the jsp tags.

Example

<%@ page import="sel2in.prjx.conf.*, sel2in.urlShorten.data.*, sel2in.prjx.common.*"%>
<%  
///this is bad : new line after %>
        response.setHeader("pragma","No-cache");

Correct way

 <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <% response.setContentType("application/vnd.ms-excel"); %><%@ page import="sel2in.prjx.conf.*, sel2in.urlShorten.data.*, sel2in.prjx.common.*"%><%    
///this is okay : No new line after %>
        response.setHeader("pragma","No-cache");    

For rich faces see File download using RichFaces

(below copied from there)

<h:commandLink value="Download" action="#{appController.downloadFile}" 
rendered="#{!file.directory}">
 <f:param name="file" value="#{file.absoluteFilename}" />
</h:commandLink>

As to setting the content type, if you have a file name with extension at your hands, you could use ServletContext#getMimeType() to resolve it based on in web.xml (either the server's default one or your webapp's one).

ServletContext servletContext = (ServletContext) externalContext.getContext();
String contentType = servletContext.getMimeType(file.getName());

if (contentType == null) {
    contentType = "application/octet-stream";
}

response.setContentType(contentType);
// ...

(note this is for JSF 1.x, you could since JSF 2.x otherwise also use ExternalContext#getMimeType())

Comments