Вопрос

Basically, I have a JSF page that displays a count and a "download" button. What I want to have happen is when the button is clicked a text file is created and downloaded and the page's count gets incremented.

When I click the CommandButton the bean.download method gets called, text gets written to a ByteArrayOutputStream and is downloaded. But the count does not refresh (page isn't reloaded).

If I don't call the method to write to the ByteArrayOutputStream, then the page does get updated and shows the new count value.

The JSF page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core">
<h:body>

    <h:form id="mainForm">
        <h:outputText id="countLbl" value="Download Count = #{bean.count}" />

        <br />

        <h:commandButton value="Do Download" action="#{bean.download}"/>
    </h:form>


</h:body>
</html>

The Session bean: Bean

import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

@Named
@SessionScoped
public class Bean implements Serializable {

    private int count;

    @PostConstruct
    private void init() {
        count = 0;
    }

    public String download() {
        count++;
        try {
            doDownload();
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } catch (ServletException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return "";
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public void doDownload() throws IOException, ServletException {

        final ByteArrayOutputStream baos = new ByteArrayOutputStream();

        try {
            String line = "dummy text";
            baos.write(line.getBytes());
            baos.close();

            sendReport(baos.toByteArray());

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

    }

    public static void sendReport(byte[] bs) throws IOException,
            ServletException {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ExternalContext externalContext = facesContext.getExternalContext();
        HttpServletResponse response = (HttpServletResponse) externalContext
                .getResponse();

        response.reset();
        response.setHeader("Expires", "0");
        response.setHeader("Cache-Control",
                "no-store, no-cache, post-check=0, pre-check=0");
        response.setHeader("Pragma", "no-cache");
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-disposition",
                "attachment; filename=\"down.csv\"");
        response.setContentLength(bs.length);

        ServletOutputStream os = response.getOutputStream();
        os.write(bs);

        os.close();

        facesContext.responseComplete();

    }

}

Thanks for the help.

Это было полезно?

Решение

I think the issue is the server can only send one response per request, try using ajax. I'm haven't used JSF very much but that might help. When you make a request the server can either send the download back, or the refreshed page. With ajax you can have a request be made to update the count, separate from the download request.

It looks like by saying response complete you cancel the page from being loaded, which you are correct by doing, because if you didn't the user would download part of the page with his file.

If you have a javascript function that makes an ajax call to refresh the counter when you click download, that might work.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top