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的表单验证框架了。