在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

posted @ 10-02-09 10:06 青色烟雨 阅读(1297) 评论(0) 编辑 所属分类: 开源方案

发表评论 请[登录]后发表

评论内容:  

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