从源代码角度看Struts2返回JSON数据的原理
来源:互联网 发布:网站数据统计 编辑:程序博客网 时间:2024/04/30 00:12
转载自http://yshjava.iteye.com/blog/1333602
用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插件执行的流程:
下面重点说说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中配置对应参数以改变默认值来满足我们的需要。
接下来看看它的两个核心方法:
public void execute(ActionInvocation invocation) throws Exception { ActionContext actionContext = invocation.getInvocationContext(); HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST); HttpServletResponse response = (HttpServletResponse) actionContext.get(StrutsStatics.HTTP_RESPONSE); try { String json; Object rootObject; //查找指定的需要序列化的对象,否则序列化整个action(上文包括前一篇文章中一提到过多次) if (this.enableSMD) { // generate SMD rootObject = this.writeSMD(invocation); } else { // generate JSON if (this.root != null) { ValueStack stack = invocation.getStack(); rootObject = stack.findValue(this.root); } else { rootObject = invocation.getAction(); } } //这是最核心的一行代码,包括了如何从rootObject抽取"可以"被序列化的属性的值,然后包装称JSON字符串并返回 json = JSONUtil.serialize(rootObject, excludeProperties, includeProperties, ignoreHierarchy, enumAsBean, excludeNullProperties); //针对JSONP的一个成员方法 json = addCallbackIfApplicable(request, json); boolean writeGzip = enableGZIP && JSONUtil.isGzipInRequest(request); //该方法是org.apache.struts2.json.JSONResult的一个成员方法,用于将JSON字符串根据指定参数包装后发送到客户端 writeToResponse(response, json, writeGzip); } catch (IOException exception) { LOG.error(exception.getMessage(), exception); throw exception; } } /** * 负责根据相关参数配置,将制定JSON字符串发送到客户端 * @param response * @param json * @param gzip * @throws IOException */ protected void writeToResponse(HttpServletResponse response, String json, boolean gzip) throws IOException { JSONUtil.writeJSONToResponse(new SerializationParams(response, getEncoding(), isWrapWithComments(), json, false, gzip, noCache, statusCode, errorCode, prefix, contentType, wrapPrefix, wrapSuffix)); }
恕笔者愚钝,找了好多资料,始终不明白这里的"SMD"是个什么意思,所在这里包括下文,都将忽略"SMD"。
可以看到,Struts2序列化对象为JSON字符串的整个过程都被JSONUtil的serialize方法包办了,所以有必要跟入这个方法一探究竟:
/** * Serializes an object into JSON, excluding any properties matching any of * the regular expressions in the given collection. * * @param object * to be serialized * @param excludeProperties * Patterns matching properties to exclude * @param ignoreHierarchy * whether to ignore properties defined on base classes of the * root object * @param enumAsBean * whether to serialized enums a Bean or name=value pair * @return JSON string * @throws JSONException */ public static String serialize(Object object, Collection<Pattern> excludeProperties, Collection<Pattern> includeProperties, boolean ignoreHierarchy, boolean enumAsBean, boolean excludeNullProperties) throws JSONException { JSONWriter writer = new JSONWriter(); writer.setIgnoreHierarchy(ignoreHierarchy); writer.setEnumAsBean(enumAsBean); return writer.write(object, excludeProperties, includeProperties, excludeNullProperties); }
- 从源代码角度看Struts2返回JSON数据的原理
- 从源代码角度看Struts2返回JSON数据的原理
- 从源代码角度看Struts2返回JSON数据的原理
- 从源代码角度看Struts2返回JSON数据的原理
- 从源码分析struts2中返回json数据的原理
- Struts2返回JSON数据的原理
- 深入了解Struts2返回JSON数据的原理及具体应用范例,从servlet 说起
- Struts2返回JSON数据的原理及具体应用
- 深入了解Struts2返回JSON数据的原理
- struts2返回json原理
- struts2 返回json数据
- Struts2返回JSON数据
- Struts2返回JSON数据
- struts2返回json数据
- struts2返回json数据
- Struts2返回JSON数据
- struts2 返回json数据
- struts2 返回json数据
- 多线程之11-------线程之间有关协作的方法:wait()与notifyAll()
- 第十四周 项目2.3 带姓名的成绩单(从文件中读取数据然后经过成绩排序姓名排序处理)
- sed
- Hungarian algorithm 匈牙利算法
- 变量以及初始化的理解
- 从源代码角度看Struts2返回JSON数据的原理
- xml结构总结
- 第十四周项目五:体会棋盘游戏中的数据存储
- PYTHON 爬虫简单的认识
- grub2修改开机默认启动项
- 引入js文件时出现中文乱码
- iOS Core Animation 简明系列教程
- 有关CPU与内存的那些事
- 并查集(转)