在Struts2中实现ajax
本文涉及技术:struts2、ajax、Struts2的ResultType、Struts2的json插件、JSONObject、JSONArray、jQuery
注:如果你不了解Struts2的json插件,可以直接阅读解决方案这一节。
最近在做框架整合遇到了一个问题:Struts2中的ajax如何实现。
于是开始查找一番,网上有很多中文资料说是用json插件,我看了下,还有例子,前后台例子很清晰。甚是高兴,有了轮子不用我亲自再发明轮子了,很好。
但是我亲自实验发现了问题:json插件默认会把Action里所有的属性序列化(Serializable),只有序列化后的属性才可以响应成json供前台处理。如果某些属性不需要被序列化,则只需在其getter声明前加入注解@JSON(serialize=false),针对这一做法我觉得不妥。
我的框架还采用Spring整合,这样Action只需要通过访问业务逻辑层(service)。要实现Action可以访问service,需要把 service作为成员变量引入Action中,也就是说每个Action里都需要至少一个service。我们根本不需要对该service属性进行序列化,这样serivce属性必须在其getter方法声明前@JSON(serialize=false),在我的实验中如果不加这一注解,前台会有异常。还有如果Action中有log属性(记录日志作用)同样不需要序列化,也要注解。这样看来,在企业开发中,如果我的Action有100个,则需要在这100个Action里逐个找出不需要序列化的属性(可能不止serivce和log两个属性),势必是浩大的体力工程(如果你觉得体力充沛也不要这样做,这种做法违背开发原则。比如以后你的需求可能要对log这个属性做序列化,这下你就要从这100个Action中逐一把注解去除)。
另外一个问题是在Action里可能会有多个方法是ajax请求的方法,这样根据插件的实现,多个不同的方法应该返回相同的json字符串,虽然到前台也能找到我的数据,总觉得别扭。
解决方案:要实现ajax方式,我从服务端和客户端两方面分别考虑,以降低耦合。
1.服务端实现:
服务端需要生成json或xml,目前大家都倾向用json,相比xml,json有更多优点,便于解析易于访问等等。Struts2是个开放的框架,我们可以根据需要自定义其每个组件,比如自定义拦截器(Interceptor),自定义验证器(Validator)、转换器(Convertor)、自定义Result类型。我们很容易写出一个响应返回为json的Result Type。其实我们也不需要自定义Result,在Struts2中自带的Result中有很多常用的ResultType已实现好了。这里我们使用stream类型来处理响应为json返回。
首先配置Action的result type为stream,该Type有很多附加属性contentType、inputName、bufferSize。在这里这些属性不需要配置,使用其默认值即可。这里注意inputName属性,其值为Action里对应的属性,比如默认值inputStream,这就意味Action里要有一个名为inputStream的属性,其类型定义为InputStream,处理后生成的json字符串转换成InputStream。完整配置如下:
现在来处理Action里的方法,Action里要定义inputStream:
private InputStream inputStream;
public InputStream getInputStream() {
return inputStream;
}
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
为了方便,定义一个辅助方法用来处理字符串转换成InputStream:
public void toInStream(String str) {
try {
inputStream = new ByteArrayInputStream(str.getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
业务方法queryAll():
public String queryAll() {
List<String> line4 = new ArrayList<String>();
line4.add("中山公园");
line4.add("曹杨路");
line4.add("海伦路");
line4.add("大连路");
line4.add("浦东大道");
line4.add("世纪大道");
line4.add("蓝村路");
line4.add("西藏南路");
line4.add("鲁班路");
line4.add("大木桥路");
JSONArray json = JSONArray.fromObject(line4);//List生成JSON对象
// JSONObject as = JSONObject.fromObject(map);
logger.info("List line4:" + json.toString());
toInStream(json.toString());//将生成的JSON对象转成InputStream
return SUCCESS;//Action继承ActionSupport可以直接写SUCCESS常量
}
这样结果就把 Line4这一List的数据以json形式传递至前台了。 使用json-lib可以很容易地把JAVA对象以及集合转换成json。
至此,服务端的工作就做好了。总结一下,就简单的两步:
首先, 配置文件中只需要在Action处指定result的type即可,
其次,在方法的return前调用toInputStream(String str);
还可以做进一步优化:做一个父类,里面有inputStream属性和转换方法toInputStream(),所有的Action继承此类,同时此类继承ActionSupport。
2.客户端解析
客户端解析json,处理ajax响应的方法太多了,这里以最常用的jQuery为例来处理ajax响应。jQuery有多个方法处理ajax请求和响应,这里我用$.getJSON(url, [data], [callback])这个方法。为什么不用$.get()呢?不知道你是否留意刚才服务端生成的json是字符串形式,还没有对象化,而使用$.getJSON(),把请求的url传进来后,函数会自动把响应返回的json字符串转为json对象,在回调函数callback里就可以直接操作json了。上面服务端响应的json是
["中山公园","曹杨路","海伦路","大连路","浦东大道","世纪大道","蓝村路","西藏南路","鲁班路","大木桥路"]
(这看上去像一条数组,实属巧合,也是标准的json数据)
客户端可以这样访问操作:
相关参考:
Struts2的json插件:http://code.google.com/p/jsonplugin/downloads/list
jQuery的$.getJSON()方法文档:http://api.jquery.com/jQuery.getJSON/
json-lib网站:http://json-lib.sourceforge.net

[使用ctrl+enter键快速提交]