使用spring webflow,在前臺頁面中如何顯示後端返回的錯誤信息

剛剛接觸spring webflow,相關的資料並非不少,而且大都是那種入門的 .xml文件的配置。html

用到的CAS 最新的4.0版本用的就是web-flow流,前臺頁面使用的是表單提交。因而我就碰到了一個問題,問題描述以下:前端

第一次輸入錯誤的用戶名密碼提示用戶名密碼錯誤,第二次輸入了正確的用戶名和密碼仍然報錯,校驗不經過。web

在使用cas以前的登陸頁面若是輸入用戶名和密碼錯誤的話,會彈出alert提示框,這個是使用ajax請求實現的。而ajax請求的通常都是那種spring mvc的controller,而且能夠異步根據返回值回掉。可是cas的源碼裏面使用的是表單提交,表單提交不是異步的,因此除非加iframe,不然無法回調函數來刷新頁面。而加了iframe以後也存在許多的改動,後續的工做量也不可評估。(爲何必定要回調呢,由於cas的頁面表單裏不僅有用戶名和密碼輸入框,還有個討厭的隱藏元素:loginticket 和 flowExecutionKey,cas處理每次請求都須要從新生成一個 loginticket票據)。ajax

想過幾種解決方案,剛開始都是想webflow和mvc整合,兩種方式:spring

1. 將login-webflow.xml中的end-state標籤中的externalRedirect修改爲個人某個controller並在參數裏面帶上錯誤信息,controller返回一個對象給到前端(通常是code:-1;msg:"";date:****這樣的json串的形式)。那麼前端ajax調用login這個webflow的時候,就會重定向到我定義的這個controller,而且拿到這個controller的返回值進行回調。express

<end-state id="redirectView" view="externalRedirect:http://user/res?code=-1&msg="error"" />json

可是這樣有一個問題,彈出alert框以後點擊肯定,alert框消失了,再從新輸入正確的用戶名和密碼,仍然會報錯,緣由是loginticket驗證失敗。關於loginticket校驗的,能夠從cas的源碼中看到:mvc

AuthenticationViaFormAction:
public final Event submit(final RequestContext context, final Credential credential,
            final MessageContext messageContext) throws Exception {
        // Validate login ticket
        final String authoritativeLoginTicket = WebUtils.getLoginTicketFromFlowScope(context);
        final String providedLoginTicket = WebUtils.getLoginTicketFromRequest(context);
        if (!authoritativeLoginTicket.equals(providedLoginTicket)) {
            logger.warn("Invalid login ticket {}", providedLoginTicket);
            messageContext.addMessage(new MessageBuilder().code("error.invalid.loginticket").build());
            return newEvent(ERROR);
        }
……

是去拿flow流中的lt和請求中的票據lt進行比較的。然而表單中的票據沒有更新成最新的,個人webflow結束以後才返回的錯誤信息,那天然拿不到webflow裏面生成的票據了。異步

先拋開這個問題不談,說第二種整合mvc的方法:ide

在end-state標籤中加入output,output中輸出一個對像;

第三種:繼承AbstractFlowHandler方法,

public class OcLoginFlowEndHandler extends AbstractFlowHandler {
    public String handleExecutionOutcome(FlowExecutionOutcome outcome, HttpServletRequest request,
            HttpServletResponse response) {
        if (outcome.getId().equals("redirectView")) {
            return "/user/loginRes?code=" + outcome.getOutput().get("bookingId");
        } else {
            return "/hotels/index";
        }
    }
}

然而這都沒有解決個人問題。由於出了那個webflow容器拿到的lt老是不對的。

那怎麼在login-webflow這個閉環中返回錯誤信息給前臺頁面呢?

查到有一種方式:http://docs.spring.io/spring-webflow/docs/2.3.x/reference/htmlsingle/#end-state-element

使用一個viewstate,來展現popup 對話框:

<view-state id="changeSearchCriteria" view="enterSearchCriteria.xhtml" popup="true">

不過這個加了這個viewstate以後也得從新定向到login的viewstate才行。

最後我採用的方案:

修改login的viewstate:

    <view-state id="viewLoginForm" view="/platform/login" model="credential">
        <binder>
            <binding property="username" />
            <binding property="password" />
        </binder>
        <on-entry>
            <set name="requestScope.messages" value="messageContext.allMessages" />
            <set name="viewScope.commandName" value="'credential'" />
        </on-entry>
        <transition on="submit"  bind="true" validate="true" to="realSubmit">
            <evaluate
                expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credential)" />
        </transition>
    </view-state>

添加綠色的那一行,這個view在render到velocity頁面的時候,直接把requestScope裏的messages給放進去,前端控制,若是messages爲空,就不展現,若是不爲空,就展現出來。

<label style="float: left; display: inline-block; font-size: 12px; color: red; text-decoration: none; margin: 5px 0;">
                                    #foreach(${message} in ${messages} )
                                    #if(${message.text} == "Invalid credentials.")
                                        用戶名、密碼或驗證碼錯誤!
                                    #end
                                    #end
                                    </label>

done!

那麼看下效果:

再輸入正確的用戶名和密碼就不會報那個loginticket驗證失敗的錯誤而且能成功登陸到系統中去了。

不足的是,其實很明顯的看到頁面刷新了一下。

相關文章
相關標籤/搜索