0

基本上,我有一个显示计数和“下载”按钮的 JSF 页面。我想要发生的是当单击按钮时创建和下载文本文件并且页面的计数增加。

当我单击 CommandButton 调用 bean.download 方法时,文本被写入 ByteArrayOutputStream 并被下载。但计数不会刷新(页面不会重新加载)。

如果我不调用写入 ByteArrayOutputStream 的方法,那么页面会更新并显示新的计数值。

JSF 页面:

<!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>

会话 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();

    }

}

谢谢您的帮助。

4

1 回答 1

0

我认为问题是服务器每个请求只能发送一个响应,尝试使用 ajax。我没有太多使用JSF,但这可能会有所帮助。当您发出请求时,服务器可以将下载或刷新的页面发回。使用 ajax,您可以请求更新计数,与下载请求分开。

看起来通过说响应完成您取消加载页面,您这样做是正确的,因为如果您不这样做,用户将使用他的文件下载页面的一部分。

如果您有一个 javascript 函数,该函数在您单击下载时进行 ajax 调用以刷新计数器,那可能会起作用。

于 2013-04-13T06:31:42.520 回答