fieldErrors是ActionContext裏的一個東西,使用Struts2的表單驗證框架時,會自動將驗證結果的錯誤信息放到裏面,非AJAX情況下,可以直接在頁面上方便地使用Struts2的標籤庫來讀取顯示這些錯誤信息,但是若是AJAX方式與服務器異步交互,則Struts2只會將Action中設置了getter方法的屬性打包成json格式的數據返回給前端。
若使用重載Action中validate方法的辦法,可以不使用addFieldError()方法而直接將錯誤信息放入到自定義的一個屬性中從而返回到前端頁面。但倘若使用xml方式來驗證就不行了。
想到Struts2的攔截器,但經過嘗試,在調用actionInvocation.invoke()的之後,不僅執行類Action,也執行類Result。因而,等退回到攔截器的調用代碼時,Result已經生成,View已經確定,這時你再修改模型(Action的屬性)或請求對象的屬性,對視圖不會有任何影響。即:struts2的interceptor並沒有完全地將action的執行和result的生成分離開。調用過程可以看下圖:
在查文檔,文檔中說道:
Keep in mind that invoke will return after the result has been called (eg. after you JSP has been rendered), making it perfect for things like open-session-in-view patterns. If you want to do something before the result gets called, you should implement a PreResultListener.
它說調用invoke方法後,獲得的是執行過result的(即JSP頁面已經渲染生成了),如果你想在result被調用之前做點什麼,那應該去實現PreResultListener這個接口。
文檔講得很簡單,不給例子,不講怎麼用PreResultListener。查文檔無果,在網上搜索了一下,很快就找到一種解決辦法了:
寫一個類實現PreResultListener接口,然後實現裏面的唯一的方法:public void beforeResult(ActionInvocation invocation, String arg1),ActionInvocation參數很熟悉了,後面這個String是指視圖。在Interceptor中將這個Listener添加 進去:
invocation.addPreResultListener(new PreResultHandle());
完整的代碼如下:
1: /**
2: * @Project IJSEFramework
3: * @FileName MyTInterceptor.java
4: * @Author ijse
5: * @DateTime 2011-1-17 下午03:24:36
6: * @Description
7: */
8: package cn.ijser.Framework.Util.Interceptors;
9:
10: import java.lang.reflect.Method;
11: import java.util.Iterator;
12: import java.util.List;
13: import java.util.Map;
14:
15: import cn.ijser.Framework.Model.Response;
16:
17: import com.opensymphony.xwork2.ActionInvocation;
18: import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
19: import com.opensymphony.xwork2.interceptor.PreResultListener;
20:
21: /**
22: * @Author ijse
23: */
24: public class MyTInterceptor extends AbstractInterceptor {
25: private static final long serialVersionUID = 1L;
26:
27: @Override
28: public String intercept(ActionInvocation invocation) throws Exception {
29: String result = null;
30: System.out.println(invocation.getAction().getClass().getName());
31: // Map map =
32: // invocation.getInvocationContext().getValueStack().getContext();
33: invocation.addPreResultListener(new PreResultHandle());
34: /*
35: * 貌似執行完這一句,返回到前臺的內容就都已經包裝好了 但是不執行這一句,fieldErrors裏又不會有東西,,糾結
36: */
37: try {
38: result = invocation.invoke();
39: } catch (Exception e) {
40: e.printStackTrace();
41: }
42: return result;
43: }
44: }
45:
46: class PreResultHandle implements PreResultListener {
47:
48: @SuppressWarnings("unchecked")
49: @Override
50: public void beforeResult(ActionInvocation invocation, String arg1) {
51:
52: System.out.println("Print field errors:");
53: // 得到fieldErrors>
54: Map fieldErrors = (Map) invocation
55: .getInvocationContext().getValueStack()
56: .findValue("fieldErrors");
57: Iterator it_key = fieldErrors.keySet().iterator();
58: while (it_key.hasNext()) {
59: String str = it_key.next();
60: System.out.println(str + ":"
61: + ((List) (fieldErrors.get(str))).get(0));
62: }
63: System.out.println("All fieldErrors print off!");
64: // 把fieldErrors放到結果集中,從而返回給前臺頁面
65: // ((JSONResult)(invocation.getResult())).
66: Object ac = invocation.getAction();
67: Class cls = ac.getClass();
68: try {
69: Method m = cls.getMethod("getResp");
70: Response resp = null;
71: resp = (Response) m.invoke(ac);
72: resp.setFieldErrors(fieldErrors);
73: m = cls.getMethod("setResp", Response.class);
74: m.invoke(ac, resp);
75: } catch (Exception e) {
76: e.printStackTrace();
77: }
78: }
79: }
使用了反射來將ActionContext中的fieldErrors注入到Action中,這樣在前端就可以獲得到,同時又可以使用Struts2的表單驗證框架了。