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


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

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

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

在使用cas之前的登錄頁面如果輸入用戶名和密碼錯誤的話,會彈出alert提示框,這個是使用ajax請求實現的。而ajax請求的一般都是那種spring mvc的controller,並且可以異步根據返回值回掉。但是cas的源碼里面使用的是表單提交,表單提交不是異步的,所以除非加iframe,否則沒法回調函數來刷新頁面。而加了iframe之后也存在許多的改動,后續的工作量也不可評估。(為什么一定要回調呢,因為cas的頁面表單里不只有用戶名和密碼輸入框,還有個討厭的隱藏元素:loginticket 和 flowExecutionKey,cas處理每次請求都需要重新生成一個 loginticket票據)。

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

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

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

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

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的方法:

在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驗證失敗的錯誤並且能成功登錄到系統中去了。

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

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM