日期:2014-05-16  浏览次数:20447 次

从源代码角度看Struts2返回JSON数据的原理

前面一篇文章其实只是介绍了如何在Struts2中返回JSON数据到客户端的具体范例而无关其原理,内容与标题不符惹来标题党嫌疑确实是笔者发文不够严谨,目前已修改标题,与内容匹配。本文将从struts2-json插件的源码角度出发,结合之前的应用范例来说明struts2-json插件返回JSON数据的原理。

?

用winrar打开struts2-json-plugin-xx.jar(笔者使用版本为2.1.8.1),根目录下有一个struts-plugin.xml,这个文件想必大家都很了解,不做过多介绍了。打开该文件,内容非常简答,如下:

?

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <package name="json-default" extends="struts-default">
        <result-types>
            <result-type name="json" class="org.apache.struts2.json.JSONResult"/>
        </result-types>
        <interceptors>
            <interceptor name="json" class="org.apache.struts2.json.JSONInterceptor"/>
        </interceptors>
    </package>
</struts>

?

?

前文提到,如果要使用Struts2返回JSON数据到客户端,那么action所在的package必须继承自json-default包,原因就在上边的配置文件中:这里的配置文件指定了该插件的包名为json-default,所以要使用该插件的功能,就必须继承自该包——json-default。

?

上面的配置文件中,配置了两个类:org.apache.struts2.json.JSONResult和org.apache.struts2.json.JSONInterceptor,前者是结果类型,后者是一个拦截器。简单说一下,org.apache.struts2.json.JSONResult负责将action中的“某些”(通过相关参数可以指定,前文已有详述)或action中所有"可获取"(有getter方法的属性或一个有返回值的getter方法的返回值)数据序列化成JSON字符串,然后发送给客户端;org.apache.struts2.json.JSONInterceptor负责拦截客户端到json-default包下的所有请求,并检查客户端提交的数据是否是JSON类型,如果是则根据指定配置来反序列化JSON数据到action中的bean中(说的有点简单,其实该拦截器内部对数据做了很多判断),拦截器不是本文的重点,介绍到此为止。看一张图,或许能够更加清晰明了的说明JSON插件执行的流程:

?

?

JSON插件执行时序图

?

?

下面重点说说org.apache.struts2.json.JSONResult。

?

首先看一下org.apache.struts2.json.JSONResult源码的核心部分:

?

部分属性


?

private String defaultEncoding = "ISO-8859-1";//默认的编码
private List<Pattern> includeProperties;//被包含的属性的正则表达式,这些属性的值将被序列化为JSON字符串,传送到客户端
private List<Pattern> excludeProperties;//被排除的属性的正则表达式,这些属性的值在对象序列化时将被忽略
private String root;//根对象,即要被序列化的对象,如不指定,将序列化action中所有可被序列化的数据
private boolean wrapWithComments;//是否包装成注释
private boolean prefix;//前缀
private boolean enableGZIP = false;//是否压缩
private boolean ignoreHierarchy = true;//是否忽略层次关系,即是否序列化对象父类中的属性
private boolean ignoreInterfaces = true;//是否忽略接口
private boolean enumAsBean = false;//是否将枚举类型作为一个bean处理
private boolean excludeNullProperties = false;//是否排除空的属性,即是否不序列化空值属性
private int statusCode;//HTTP状态码
private int errorCode;//HTTP错误码
private String contentType;//内容类型,通常为application/json,在IE浏览器中会提示下载,可以通过参数配置<param name="contentType">text/html</param>,则不提示下载
private String wrapPrefix;//包装前缀
private String wrapSuffix;//包装后缀

?

?

看一下上一篇文章中的相关参数配置:

?

<package name="json" extends="json-default" namespace="/test">
	<action name="testByAction"
			class="cn.ysh.studio.struts2.json.demo.action.UserAction" method="testByAction">
		<result type="json">
				<!-- 这里指定将被Struts2序列化的属性,该属性在action中必须有对应的getter方法 -->
				<!-- 默认将会序列所有有返回值的getter方法的值,而无论该方法是否有对应属性 -->
				<param name="root">dataMap</param>
				<!-- 指定是否序列化空的属性 -->
				<param name="excludeNullProperties">true</param>
				<!-- 这里指定将序列化dataMap中的那些属性 -->
				<param name="includeProperties">
     				user.*
				</param>
				<!-- 指定内容类型,默认为application/json,IE浏览器会提示下载 -->
				<param name="contentType">text/html</param>
				<!-- 这里指定将要从dataMap中排除那些属性,这些排除的属性将不被序列化,一半不与上边的参数配置同时出现 -->
				<param name="excludeProperties">
     				SUCCESS
				</param>
		</result>
	</action>
</package>

?

配置中出现了JSONResult的部分属性名,是的,JSONResult中的属性都可以根据需要在struts.xml中配置对应参数以改变默认值来满足我们的需要。

?

?

接下来看看它的两个核心方法:

?

?