尽管AJAX是Asynchronous Javascript and XML,但事实证明,在异步请求中传输XML格式的数据总让人觉得很麻烦。尽管在服务端XML的报文解析有广泛的工具支持,如JDOM, DOM4J等。但在客户端,用户需使用DOM来解析XML报文,才能获取需要的数据,并且由于XML报文在数据之外存在许多节点信息,因此传输的数据量相 对较大。如果仅使用普通文本的格式传输数据,又缺乏必要的数据结构。
  JSON是Javascript Object Notation, 它是一种轻量级的数据结构。由于具有易于阅读,易于机器解析的特点,它非常适合于作为数据传输的格式,特别是对于客户端使用Javascript来解析的Web应用。
   AJAX应用实现大体上分为服务端和客户端两部门,客户端若使用prototype的js库,能非常简单地实现AJAX请求和响应的获取。 prototype中的Form.serialize方法更能将表单中的所有字段序列化,作为发送给服务端的数据异步发送。在服务端,需要有一定的机制来 返回稳定格式的报文给客户端,并且这个响应的格式必须是易于客户端来解析的,JSON格式的报文是不错的选择。
  在这里,我实现了一个基于JSON的服务端响应类,以满足上述的需求,服务端代码如下: 
package cn.ih.util.web; 
import java.util.HashMap; 
import java.util.LinkedHashMap; 
import java.util.Map; 
import javax.servlet.http.HttpServletResponse; 
import net.sf.json.JSONObject; 
import org.apache.commons.lang.StringUtils; 
/** *//**
 * 
 * @author ih
 *
 */
public class JsonResponseUtils ...{
    
    private static final String NODE_RESULT="result"; 
    private static final String NODE_MESSAGE="message"; 
    private static final String NODE_REASON="reason"; 
    private static final String NODE_EXTRA_CONTENT="extraContent"; 
    
    public static final String REASON_UNLOGON="unlogon"; 
    public static final String REASON_ACCESS_DENY="accessDeny"; 
    public static final String REASON_BIZ_CONSTRAINT="bizConstraint"; 
    public static final String REASON_EXCEPTION="error"; 
    /** *//**
     * 通过response返回到客户端
     * @param response
     * @param responseContent
     * @throws Exception
     */
    public static void outputResponse(HttpServletResponse response,String responseContent)throws Exception...{
        response.getWriter().write(responseContent); 
    }
    
    /** *//**
     * 返回json格式的报文
     * @param result
     * @param message
     * @param reason
     * @param customerizedContent
     * @return
     */
    @SuppressWarnings("unchecked")
    public static String generateResponse(boolean result,String message,String reason,Map customerizedContent)...{
        Map map=new LinkedHashMap(); 
        map.put(NODE_RESULT,result); 
        if(StringUtils.isNotEmpty(message))
            map.put(NODE_MESSAGE, message); 
        if(StringUtils.isNotEmpty(reason))
            map.put(NODE_REASON,reason); 
        if(customerizedContent!=null)
            map.put(NODE_EXTRA_CONTENT, customerizedContent); 
        return generateJsonObjectString(map); 
    }
    
    /** *//**
     * 返回处理成功的报文
     * @return
     */
    public static String generateSuccessResponse()...{
        return generateResponse(true, null, null, null); 
    }
    
    /** *//**
     * 返回处理成功的报文,含成功提示信息和用户自定义内容
     * @param message
     * @param customerizedContent
     * @return
     */
    @SuppressWarnings("unchecked")
    public static String generateSuccessResponse(String message,Map customerizedContent)...{
        return generateResponse(true, message, null, customerizedContent); 
    }
    
    /** *//**
     * 返回处理成功的报文,含成功提示信息
     * @param message
     * @return
     */
    public static String generateSuccessResponse(String message)...{
        return generateResponse(true, message, null, null); 
    }
    
    /** *//**
     * 返回处理失败的报文, 原因为未登陆
     * @param message
     * @return
     */
    public static String generateUnlogonResponse(String message)...{
        return generateResponse(false, message, REASON_UNLOGON, null); 
    }
    
    /** *//**
     * 返回处理失败的报文, 原因为无权限
     * @param message
     * @return
     */
    public static String generateAccessDenyResponse(String message)...{
        return generateResponse(false, message, REASON_ACCESS_DENY, null); 
    }
    
    /** *//**
     * 返回处理失败的报文, 原因为业务限制
     * @param message
     * @return
     */
    public static String generateBizConstraintResponse(String message)...{
        return generateResponse(false, message, REASON_BIZ_CONSTRAINT, null); 
    }
    
    /** *//**
     * 返回处理失败的报文, 原因为系统异常
     * @param message
     * @return
     */
    public static String generateExceptionResponse(String message)...{
        return generateResponse(false, message, REASON_EXCEPTION, null); 
    }
    
    
    private static String generateJsonObjectString(Map map)...{
        JSONObject jObj=new JSONObject(); 
        jObj.putAll(map); 
        return jObj.toString(); 
    }
    
    
    public static void main(String[] args) ...{
        System.out.println(generateSuccessResponse()); 
        System.out.println(generateSuccessResponse("保存成功")); 
        
        Map customerizedContent=new HashMap(); 
        customerizedContent.put("newid", "101"); 
        System.out.println(generateSuccessResponse("保存成功", customerizedContent)); 
        
        System.out.println(generateUnlogonResponse("您尚未登陆")); 
        System.out.println(generateAccessDenyResponse("您没有权限访问")); 
        System.out.println(generateBizConstraintResponse("用户名不可重复")); 
        System.out.println(generateExceptionResponse("数据库异常,请稍后再试")); 
    }
} 
  运行main后,将打印如下几种相同格式的报文,代表响应的不同种情况:
{"result":true}
{"message":"保存成功","result":true}
{"extraContent":{"newid":"101"},"message":"保存成功","result":true}
{"reason":"unlogon","message":"您尚未登陆","result":false}
{"reason":"accessDeny","message":"您没有权限访问","result":false}
{"reason":"bizConstraint","message":"用户名不可重复","result":false}
{"reason":"error","message":"数据库异常,请稍后再试","result":false} 
 
  Result属性代表这次处理的结果,只有true代表成功,false代表失败。
  Message属性代表输出到客户端的打印信息。
  Reason熟悉是对处理结果的解释,一般的业务系统有的情况基本上是unlogon未登陆,accessDeny访问拒绝,bizConstraint业务限制, error系统错误或异常。
  extraContent用于输出额外的信息,比如在处理成功后客户端需要新生成纪录的主键,这时可以通过这个节点输出。
 
  至于客户端的解析,由于是json格式的数据,非常简单地就能获取到报文中的数据。客户端代码如下:
 
function submitForm(form)...{
               var    elemStr=Form.serialize(form); 
            alert(elemStr); 
            var url = "<c:url value="/multiActController.spr?action=jsonResponseSuccess"/>"; 
            var mailAjax = new Ajax.Request(url,...{method: 'post',parameters:elemStr,
            onComplete: function(response)...{
                var responseText=response.responseText; 
                alert(responseText); 
                var jobj=responseText.parseJSON(); 
 alert(jobj.result+","+jobj.message+","+jobj.extraContent.name+","+jobj.extraContent.address+","+jobj.extraContent.sex); 
                }
            }
            ); 
            return false; 
               
           } 
  附:服务端需要引入jsonlib;客户端需引入json.js和prototype1.5。