Show success message and then redirect to another page after a timeout using PageFlow

后端 未结 3 644
旧巷少年郎
旧巷少年郎 2021-02-14 19:46

How can I show a success message and then redirect the user to another page after a timeout of e.g. 5 seconds?

I need this for the login page after a successful login. I

3条回答
  •  既然无缘
    2021-02-14 20:40

    First of all, with the code you posted you won't see the FacesMessage before the redirect, you'll see it after the redirect. But also, in order to make that happen you'll need to add a filter, because messages are lost when you redirect. This is the code for the filter you need (don't forget to declare it in web.xml):

    public class MultiPageMessagesSupport implements PhaseListener {
    
    private static final long serialVersionUID = 1250469273857785274L;
    private static final String sessionToken = "MULTI_PAGE_MESSAGES_SUPPORT";
    
    @Override
    public PhaseId getPhaseId() {
        return PhaseId.ANY_PHASE;
    }
    
    /*
     * Check to see if we are "naturally" in the RENDER_RESPONSE phase. If we
     * have arrived here and the response is already complete, then the page is
     * not going to show up: don't display messages yet.
     */
    @Override
    public void beforePhase(final PhaseEvent event) {
        FacesContext facesContext = event.getFacesContext();
        int msg = this.saveMessages(facesContext);
    
        if (PhaseId.RENDER_RESPONSE.equals(event.getPhaseId())) {
            if (!facesContext.getResponseComplete()) {
                this.restoreMessages(facesContext);
            }
        }
    }
    
    /*
     * Save messages into the session after every phase.
     */
    @Override
    public void afterPhase(final PhaseEvent event) {
        if (event.getPhaseId() == PhaseId.APPLY_REQUEST_VALUES ||
                event.getPhaseId() == PhaseId.PROCESS_VALIDATIONS ||
                event.getPhaseId() == PhaseId.INVOKE_APPLICATION) {
            FacesContext facesContext = event.getFacesContext();
            int msg = this.saveMessages(facesContext);
        }
    }
    
    @SuppressWarnings("unchecked")
    private int saveMessages(final FacesContext facesContext) {
        List messages = new ArrayList();
        for (Iterator iter = facesContext.getMessages(null); iter.hasNext();) {
            messages.add(iter.next());
            iter.remove();
        }
    
        if (messages.isEmpty()) {
            return 0;
        }
    
        Map sessionMap = facesContext.getExternalContext().getSessionMap();
        List existingMessages = (List) sessionMap.get(sessionToken);
        if (existingMessages != null) {
            existingMessages.addAll(messages);
        } else {
            sessionMap.put(sessionToken, messages);
        }
        return messages.size();
    }
    
    @SuppressWarnings("unchecked")
    private int restoreMessages(final FacesContext facesContext) {
        Map sessionMap = facesContext.getExternalContext().getSessionMap();
        List messages = (List) sessionMap.remove(sessionToken);
    
        if (messages == null) {
            return 0;
        }
    
        int restoredCount = messages.size();
        for (Object element : messages) {
            facesContext.addMessage(null, (FacesMessage) element);
        }
        return restoredCount;
    }
    }
    

    If this doesn't work for you, and you need to show the message before, then you'll have to something like the following: make the method return void, invoke it through ajax, and after adding the success message invoke some javascript method that will wait a couple of seconds and then make the redirect (maybe by programmatically clicking a hidden button that redirects to next page). In my opinion this is not worth the trouble, you will just delay the login process. Anyway user will know tha tlogin succeeded because he will be redirect to home page (or whatever page you send him to)

    EDIT: the messages are displayed in the page when the method finishes, so waiting in the managed bean method won't work. after adding the FacesMessage, use

    RequestContext.getCurrentInstance().execute("waitAndRedirect()");
    

    And in your xhtml, you'll need to have a javascript function similar to this:

    function waitAndRedirect() {
        setTimeout(function() {
            hiddenButtonId.click();
        }, 2000);
    }
    

    where hiddenButtonId is the ID of a p:button which redirects to home page and is hidden (display:none)

    But again, this a nasty approach, in my opinion there's no need to do this, you will just delay the login process.

提交回复
热议问题