Pergunta

Eu tenho um comandobutton que invocará uma função para baixar um arquivo (coisas padrão como InputStream, BufferedOutputStream ...) Após o sucesso do download, no final da função, altero alguns valores do objeto atual e o persisto no banco de dados. Tudo isso funciona corretamente. Agora, quando o arquivo é concluído, o conteúdo da página não é atualizado. Eu tenho que acertar a atualização para ver o conteúdo atualizado. Por favor ajude. Abaixo estão a estrutura básica do meu código

document: Bean gerenciado
getDrawings(): Método Retornar uma lista de desenho (classe de entidade)
CheckedOutBy: atributo da entidade Drawing

<p:dataTable id="drawing_table" value="#{document.drawings}" var="item" >                            
    <p:column>
        <f:facet name="header">
              <h:outputText value="CheckedOutBy"/>
        </f:facet>
        <h:outputText value="#{item.checkedOutBy}"/>
        ...
</p:dataTable>
<p:commandButton ajax="false" action="#{document.Download}" value="Download" />

Dentro do meu feijão gerenciado

public void Download(){
    Drawing drawing = getCurrentDrawing();
    //Download drawing
    drawing.setCheckedOutBy("Some Text");
    sBean.merge(drawing);  //Update "Some Text" into CheckedOutBy field
}
Foi útil?

Solução

Você basicamente gostaria de deixar o cliente disparar dois solicitações de. Um para recuperar o download e outro para atualizar a nova página. Eles não podem ser feitos em uma única solicitação HTTP. Como o download precisa ser realizado de maneira síncrona e não há como preencher o Download do lado do cliente, não há maneiras limpas de JSF/JS/AJAX de atualizar um componente no completo download.

Seu melhor JSF-bet com a ajuda de PrimeFaces é <p:poll>

<h:outputText id="checkedOutBy" value="#{item.checkedOutBy}"/>
...
<p:poll id="poll" interval="5" update="checkedOutBy" />

ou <p:push>

<p:push onpublish="javaScriptFunctionWhichUpdatesCheckedOutBy" />  

As pesquisas são fáceis, mas posso imaginar que adiciona sobrecarga desnecessária. Você não pode iniciá -lo usando componentes padrão JSF/PrimeFaces quando o download síncrono iniciar. Mas você pode parar para deixá-lo fazer uma verificação automática no rendered atributo. Empurrar é tecnicamente a melhor solução, mas mais difícil de começar. A Primefaces explica seu uso, no entanto, no capítulo 6 do Guia do Usuário.

Outras dicas

Bem, eu decidi ir com a resposta/recomendação de Balusc acima e decidi compartilhar meu código aqui para as pessoas que podem parar por aqui, 'mais tarde'. Para sua informação, meus detalhes do ambiente estão abaixo:

Tomee 1.6.0 Snapshot (Tomcat 7.0.39), PrimeFaces 3.5 (PrimeFaces Push), Atmosfera 1.0.13 Snapshot (1.0.12 é a versão estável mais recente)

Primeiro de tudo, estou usando p: arquivado com p: commandlink.

<p:commandLink value="Download" ajax="false"
               actionListener="#{pf_ordersController.refreshDriverWorksheetsToDownload()}">
    <p:fileDownload value="#{driverWorksheet.file}"/>
</p:commandLink>

Como eu tenho o XHTML acima, e como P: FilDownLoad não permite que oncomplete = "algumjavascript ()" seja executado, decidi usar os PrimeFaces Push para empurrar a mensagem para o cliente, para acionar o JavaScript necessário para desbloquear a interface do usuário, porque a interface do usuário, porque a interface do usuário Estava sendo bloqueado sempre que clico no comandlink para baixar o arquivo e, por muitos meses, não sabia como resolver isso.

Como já estou usando o PrimeFaces Push, tive que ajustar o seguinte no lado do cliente:

arquivo .js; contém método que lida com mensagens empurradas do servidor para o cliente

function handlePushedMessage(msg) {
    /* refer to primefaces.js, growl widget,
     * search for: show, renderMessage, e.detail
     * 
     * sample msg below:
     * 
     * {"data":{"summary":"","detail":"displayLoadingImage(false)","severity":"Info","rendered":false}}
     */
    if (msg.detail.indexOf("displayLoadingImage(false)") != -1) {
        displayLoadingImage(false);
    }
    else {
        msg.severity = 'info';
        growl.show([msg]);
    }
}

index.xhtml; Contém o componente P: Socket (PrimeFaces Push); Eu recomendo todos os seguintes, se você estiver implementando o exemplo do FacesMessage do PrimeFaces Push

<h:outputScript library="primefaces" name="push/push.js" target="head" />
<p:growl id="pushedNotifications" for="socketForNotifications"
         widgetVar="growl" globalOnly="false"
         life="30000" showDetail="true" showSummary="true" escape="false"/>
<p:socket id="socketForNotifications" onMessage="handlePushedMessage"
          widgetVar="socket"
          channel="/#{pf_usersController.userPushChannelId}" />

Meses (ou talvez um ano ou menos) atrás, achei necessário adicionar o seguinte ao comandolink que envolve P: FilDownload, que atualizará o arquivo/fluxo no servidor, para que você possa clicar no arquivo quantas vezes Você precisa e baixar o arquivo repetidamente sem atualizar a página via tecla F5/Atualizar no teclado (ou similar no dispositivo móvel)

actionListener="#{pf_ordersController.refreshDriverWorksheetsToDownload()}"

Esse método Bean é referenciado sempre que o EndUser clica no comandlink, para baixar o arquivo, então esse era o local perfeito para 'empurrar' uma mensagem do servidor para o cliente, para acionar o JavaScript no cliente, para desbloquear a interface do usuário.

Abaixo estão os métodos Bean no meu aplicativo que fazem o trabalho. :)

pf_orderscontroller.refreshdriverworksheetstodownload ()

public String refreshDriverWorksheetsToDownload() {
    String returnValue = prepareDriverWorksheetPrompt("download", false);
    usersController.pushNotificationToUser("displayLoadingImage(false)");
    return returnValue;
}

userScontroller.pushnotificationTouser (); Eu tive que adicionar este, hoje à noite.

public void pushNotificationToUser(String notification) {
    applicationScopeBean.pushNotificationToUser(notification, user);
}

ApplicationsCopeBean.pushnotificationTouser (); Isso já existia, nenhuma alteração nesse método.

public void pushNotificationToUser(String msg, Users userPushingMessage) {
    for (SessionInfo session : sessions) {
        if (userPushingMessage != null &&
            session.getUser().getUserName().equals(userPushingMessage.getUserName()) &&
            session.getUser().getLastLoginDt().equals(userPushingMessage.getLastLoginDt())) {
            PushContext pushContext = PushContextFactory.getDefault().getPushContext();
            pushContext.push("/" + session.getPushChannelId(),
                             new FacesMessage(FacesMessage.SEVERITY_INFO, "", msg));
            break;
        }
    }
}

Você poderia usar o update atributo do p:commandButton Componente para renderizar a área que você pretende atualizar após o download, neste caso o seu "drawing_table".

<p:commandButton update="drawing_table" action="#{document.Download}" value="Download" />

Como Balusc Respondido, não podemos obter resposta duas vezes em uma única solicitação.

Para atualizar uma página após o download, use melhor o seguinte script java no link de download (p:commandbutton) OnClick Tag.

Exemplo:

<p:commandButton ajax="false" icon="ui-icon-arrowstop-1-s" onclick="setTimeout('location.reload();', 1000);" action="#{managedBean.downloadMethod}" />

Isso atualizará automaticamente a página após 1 segundo, ao mesmo tempo em que antes da atualização, você receberá o arquivo de download, com base no seu tempo de resposta de download, aumentará os segundos nesse script. Segundos não devem menos do que o tempo de resposta do download.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top