您的位置:首页 > Web前端 > JavaScript

使用JSON进行数据传输的总结

2011-06-16 18:04 459 查看
一、选择的意义


在异步应用程序中发送和接收信息时,可以选择以纯文本和 XML
作为数据格式。为了更好的使用ajax,
我们将学习一种有用的数据格式 JavaScript Object
Notation
(JSON
),以及如何使用它更轻松地在应用程序中移动数据和对象。JSON
是一种简单的数据交换格式,在某些方面,它的作用与XML
非常类似,但比XML
更为简单,JSON
的语法简化了数据交换的难度,而且提供了一种
伪对象
的方式。

Java
的对象 <
- >JavaScript
对象(json
数据格式)

二、JSON

基础


简单地说,
JSON
可以将
JavaScript
对象中表示的一组数据转换为字符串(伪对象)
,然后就可以在函数之间轻松地传递这个字符串,或者
在异步应用程序中将字符串从 Web
客户端传递给服务器端程序
。这个字符串看起来有点儿古怪(稍后会看到几个示例),但是 JavaScript
很容易解释它,而且 JSON

可以表示比名称/
值对更复杂的结构。例如,可以表示数组和复杂的对象,而不仅仅是键和值的简单列表。

关于

JSON

对象


1

、使用JavaScript
语法创建对象


//
定义一个函数,作为构造函数

fucntion
person(name,sex)

{

this.name=name;

this.sex=sex;

}//
创建一个实例

var p=new
Person(‘
张三’,’
男’);

//
输出Person
实例

alert(p.name);

注意:通过该方式创建的对象是一般的脚本对象

2

、从JavaScript1.2
开始创建对象有了一种更快捷的语法(Json
的语法)


,如下:

var
obj=
{
name:
"
张三
"
,
"sex"
:
'

'
}
;

alert(obj.sex);

关于数组


1

、早期的JavaScript
数组


var arr=new
Array();

arr[0]=’a’;

arr[1]=’bbc’

我们也可以通过如下方式创建数组

var arr=new
Array(‘a’,’bbc’);

2

、使用JSON
语法,则可以通过如下方式创建数组


var
arr=[‘a’,’bbc’];

简单 JSON
示例


按照最简单的形式,可以用下面这样的 JSON
表示名称/
值对:

{ "firstName":"Brett" }

这个示例非常基本,而且实际上比等效的纯文本名称/
值对占用更多的空间:

firstName=Brett

但是,当将多个名称/
值对串在一起时,JSON

就会体现出它的价值了。首先,可以创建包含多个名称/
值对的记录
,比如:

{"firstName": "Brett", "lastName":"McLaughlin", "email": "brett@newInstance.com"}


从语法方面来看,这与名称/
值对相比并没有很大的优势,但是在这种情况下 JSON

更容易使用,而且可读性更好。例如,它明确地表示以上三个值都是同一记录的一部分;花括号使这些值有了某种联系。

值的数组

当需要表示一组值时,JSON
不但能够提高可读性,而且可以减少复杂性。例如,假设您希望表示一个人名列表。在
XML
中,需要许多开始标记和结束标记;如果使用典型的名称/
值对(就像在本系列前面文章中看到的那种名称/
值对),那么必须建立一种专有的数据格式,或者将键名称修改为
person1-firstName


这样的形式。

如果使用
JSON
,就只需将多个带花括号的记录分组在一起:

{ "people": [

{ "firstName": "Brett", "lastName":"McLaughlin", "email": "brett@newInstance.com" },

{ "firstName": "Jason", "lastName":"Hunter", "email": "jason@servlets.com" },

{ "firstName": "Elliotte", "lastName":"Harold", "email": "elharo@macfaq.com" }

]}

这不难理解。在这个示例中,只有一个名为

people


的变量,值是包含三个条目的数组,每个条目是一个人的记录,其中包含名、姓和电子邮件地址。上面的示例演示如何用括号将记录组合成一个值。当然,可以使用相同的语法表示多个值(每个值包含多个记录):

{ "programmers": [

{ "firstName": "Brett", "lastName":"McLaughlin", "email": "brett@newInstance.com" },

{ "firstName": "Jason", "lastName":"Hunter", "email": "jason@servlets.com" },

{ "firstName": "Elliotte", "lastName":"Harold", "email": "elharo@macfaq.com" }

],

"authors": [

{ "firstName": "Isaac", "lastName": "Asimov", "genre": "science fiction" },

{ "firstName": "Tad", "lastName": "Williams", "genre": "fantasy" },

{ "firstName": "Frank", "lastName": "Peretti", "genre": "christian fiction" }

],

"musicians": [

{ "firstName": "Eric", "lastName": "Clapton", "instrument": "guitar" },

{ "firstName": "Sergei", "lastName": "Rachmaninoff", "instrument": "piano" }

]

}

这里最值得注意的是,能够表示多个值,每个值进而包含多个值。但是还应该注意,在不同的主条目(programmers、authors

musicians
)之间,记录中实际的名称/
值对可以不一样。JSON
是完全动态的,允许在 JSON

结构的中间改变表示数据的方式。甚至可以声明如下的Json
对象

var
obj2=
{
people:
{
name:
'
张三
'
,sex:
"

"
}}alert(obj2.people.name);

在处理 JSON

格式的数据时,没有需要遵守的预定义的约束。所以,在同样的数据结构中,可以改变表示数据的方式,甚至可以以不同方式表示同一事物。

{deptid:
'
1
'
,deptname:
'
开发部
'
,deptnum:
'
2
'
,deptdesc:
'
开发相关
',

emps:[{empid:1,empname:'
张三
',sex:’

’,age:’20’},{empid:2,empname:'
张三
',sex:’

’,age:’20’}

{empid:3,empname:'
张三
',sex:’

’,age:’20’}]
}三、在JavaScript
中使用JSON



掌握了 JSON

格式之后,在 JavaScript
中使用它就很简单了。JSON

是 JavaScript
原生格式,这意味着

JavaScript

中处理 JSON

数据不需要任何特殊的 API
或工具包。

将JSON
数据赋值给变量


例如,可以创建一个新的 JavaScript
变量,然后将 JSON

格式的数据字符串直接赋值给它:

var people =



{ "programmers": [


{ "firstName": "Brett", "lastName":"McLaughlin", "email": "brett@newInstance.com" },

{ "firstName": "Jason", "lastName":"Hunter", "email": "jason@servlets.com" },

{ "firstName": "Elliotte", "lastName":"Harold", "email": "elharo@macfaq.com" }


],



"authors": [


{ "firstName": "Isaac", "lastName": "Asimov", "genre": "science fiction" },

{ "firstName": "Tad", "lastName": "Williams", "genre": "fantasy" },

{ "firstName": "Frank", "lastName": "Peretti", "genre": "christian fiction" }


],



"musicians": [


{ "firstName": "Eric", "lastName": "Clapton", "instrument": "guitar" },

{ "firstName": "Sergei", "lastName": "Rachmaninoff", "instrument": "piano" }


]



}

这非常简单;现在
people


包含前面看到的
JSON
格式的数据。但是,这还不够,因为访问数据的方式似乎还不明显。

访问数据

尽管看起来不明显,但是上面的长字符串实际上只是一个数组;将这个数组放进 JavaScript
变量之后,就可以很轻松地访问它。实际上,只需用点号表示法来表示数组元素。所以,要想访问 programmers列表的第一个条目的姓氏,只需在 JavaScript

中使用下面这样的代码:

people.programmers[0].lastName;

注意,数组索引是从零开始的。所以,这行代码首先访问

people


变量中的数据;然后移动到称为

programmers


的条目,再移动到第一个记录(
[0]

);最后,访问
lastName


键的值。结果是字符串值 “McLaughlin”


下面是使用同一变量的几个示例。

people.authors[1].genre
// Value is "fantasy"

people.musicians[3].lastName

// Undefined. This refers to the fourth entry,and there isn't one

people.programmers[2].firstName
// Value is "Elliotte"

利用这样的语法,可以处理任何 JSON
格式的数据,而不需要使用任何额外的 JavaScript

工具包或 API


修改 JSON
数据


正如可以用点号和括号访问数据,也可以按照同样的方式轻松地修改数据:

people.musicians[1].lastName = "Rachmaninov";

在将字符串转换为
JavaScript json
格式对象之后,就可以像这样修改变量中的数据。

注意:json
格式的对象和json
文本是不同的

var
obj={name:"
张三
","sex":'

'};
//json
格式的对象

var
str="
{
name:
"
张三
"
,
"sex"
:
'

'
}"
;

//json
格式的字符串(
json
格式的文本)

转换回字符串


当然,如果不能轻松地将对象转换回本文提到的文本格式,那么所有数据修改都没有太大的价值。在 JavaScript
中这种转换也很简单:

var newJSONtext = people.toJSONString();

这样就行了!现在就获得了一个可以在任何地方使用的文本字符串,例如,可以将它用作 Ajax
应用程序中的请求字符串。

更重要的是,可以将任何
JavaScript
对象转换为 JSON

文本。并非只能处理原来用 JSON
字符串赋值的变量。为了对名为
myObject


的对象进行转换,只需执行相同形式的命令:

<script
type="text/javascript">

function Car(make,model,year,color)

{

this.make=make;

this.model=model;

this.year=year;

this.color=color;

}function showCar()

{

var carr = new Car("Dodge","Coronet R/T",1968,"yellow");

alert(carr.toJSONString());

}</script>

这就是 JSON

与其他数据格式之间最大的差异。如果使用
JSON
,只需调用一个简单的函数,就可以获得经过格式化的数据,可以直接使用了。对于其他数据格式,需要在原始数据和格式化数据之间进行转换。即使使用 Document Object Model
这样的
API
(提供了将自己的数据结构转换为文本的函数),也需要学习这个 API
并使用 API
的对象,而不是使用原生的 JavaScript

对象和语法。

最终结论是,如果要处理大量 JavaScript
对象,那么 JSON

几乎肯定是一个好选择,这样就可以轻松地将数据转换为可以在请求中发送给服务器端程序的格式(Ajax)


四、Struts
2
中使用Json ajax
支持


JSON
插件提供了一种名为json
的ResultType
,一旦为某个Action
指定了一个类型为json
的Result
,则该Result
无需映射到任何视图资源。因为JSON
插件会负责将Action
里的状态信息序列化成JSON
格式的数据,并将该数据返回给客户端页面的
JavaScript


  简单地说,JSON
插件允许我们在JavaScript
中异步调用Action
,而且Action
不再需要使用视图资源来显示该Action
里的状态信息,而是由JSON
插件负责将Action
里的状态信息返回给调用页面——通过这种方式,就可以完成Ajax
交互。

  Struts2
提供了一种可插拔方式来管理插件,安装Struts2
的JSON
插件与安装普通插件并没有太大的区别,一样只需要将Struts2
插件的JAR
文件复制到Web
应用的WEB-INF/lib
路径下即可。

安装JSON
插件按如下步骤进行:

(1
)登陆http://code.google.com/p/jsonplugin/downloads/list
站点,下载Struts2
的JSON
插件的最新版本,当前最新版本是0.7
,我们可以下载该版本的JSON
插件。

(2
)将下载到的jsonplugin-0.7.jar
文件复制到Web
应用的WEB-INF
路径下,即可完成JSON
插件的安装。

  实现Action
逻辑

  假设deptnew.html
输入页面中包含了四个表单域,这四个表单域对于四个请求参数,因此应该使用Action
来的dept
对象封装这四个请求参数。四个表单域的name
分别为dept.deptid
、dept.deptname
、dept.deptnum
和dept.deptdesc


处理该请求的Action
类代码如下:

package org.wllt.ajax.actions;

import java.util.Date;

import java.util.HashMap;

import java.util.Map;

import org.wllt.ajax.beans.Dept;

import com.googlecode.jsonplugin.annotations.JSON;

import com.opensymphony.xwork2.Action;

public class JSONExample

{

//
封装请求参数的三个属性

private String field1;

private transient String field2;

private String field3;

//
封装处理结果的属性

private int[] ints ={10, 20};

private Map map = new HashMap();

private String customName = "custom";

//
日期格式的属性

private Date date;

private Dept dept;

//
三个请求参数对应的
setter

getter
方法

@JSON(serialize=false)

public String getField1(){

return field1;

}public void setField1(String field1)

{

this.field1 = field1;

}//
封装处理结果的属性的
setter

getter
方法

public int[] getInts()

{

return ints;

}public void setInts(int[] ints)

{

this.ints = ints;

}@JSON(format="yyyy-MM-dd")

public Map getMap()

{

return map;

}public void setMap(Map map)

{

this.map = map;

}public String getField2() {

return field2;

}public void setField2(String field2) {

this.field2 = field2;

}public String getField3() {

return field3;

}public void setField3(String field3) {

this.field3 = field3;

}public Dept getDept() {

return dept;

}public void setDept(Dept dept) {

this.dept = dept;

}//
使用注释语法来改变该属性序列化后的属性名

@JSON(name="newName")

public String getCustomName()

{

return this.customName;

}@JSON(format="yyyy-MM-dd")

public Date getDate() {

return date;

}public void setDate(Date date) {

this.date = date;

}public String execute()

{

map.put("name", "yeeku");

map.put("curdate",new Date());

return Action.SUCCESS;

}}在上面代码中,使用了JSON
注释,注释时指定了name
域,name
域指定Action
属性被序列化成JSON
对象的属性名。除此之外,JSON
注释还支持如下几个域:

Name

Action
属性被序列化成JSON
对象的属性名

serialize
:设置是否序列化该属性(
默认的action
的所有属性都会序列化成json
文本响应到原页面,也可以根据需要设定某些属性不序列化
)
。也可以通过在配置json
类型的结果的时候定义需要不序列化的属性:

<result name="success" type="json">

<param
name="excludeProperties">service,joindate,dept</param>

</result>

  deserialize
:设置是否反序列化该属性。

format
:设置用于格式化输出、解析日期表单域的格式。例如"yyyy-MM-dd'T'HH:mm:ss"


一般需要注释到需要转换日期格式属性的get
方法上面

配置该Action
与配置普通Action
存在小小的区别,为该Action
配置结果类型为json
的Result
。而这个Result
无需配置任何视图资源,
只需要把通过该结果把json
文本响应到原页面。

配置该Action
的struts.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
>

<
constant
name
=
"struts.locale"
value
=
"zh_CN"
/>

<
constant
name
=
"struts.action.extension"
value
=
"do,action"
/>

<
package
name
=
"json"
extends
=
"json-default"
>

<
action
name
=
"dept"
class
=
"org.wllt.ajax.actions.DeptAction"
>

<
result
type
=
"json"
/>

</
action
>

</
package
>

</
struts
>

  在上面配置文件中有两个值得注意的地方:

  第一个地方是配置struts.i18n.encoding
常量时,不再是使用GBK
编码,而是UTF-8
编码,这是因为Ajax
的POST
请求都是以UTF-8
的方式进行编码的。

  第二个地方是配置包时,自己的包继承了json-default
包,而不再继承默认的default
包,这是因为只有在该包下才有json
类型的Result


实现JSP
页面first.jsp


为了简单地访问DOM
节点,这里用了JavaScript
框架Prototype.js.

<
html
>

<
head
>

<
title
>
使用
JSON
插件
</
title
>

<
meta
http-equiv
=
"content-type"
content
=
"text/html; charset=UTF-8"
>

<
script
src
=
"./js/prototype.js"
type
=
"text/javascript"
>

</
script
>

<
script
language
=
"JavaScript"
>

function
gotClick()

{

//
请求的地址

var
url=
'./dept.do'
;

//

Form
中所有
Input
对象的值转化为一个
URL
String
,方便把
Form
转为用

URL Get
方式
//

Ajax
提交,常用
Ajax
提交
Form
的例子
:

var
params=Form.serialize(
'form1'
);

//
创建
Ajax.Request
对象,对应于发送请求

var
myAjax=
new
Ajax.Request(url,
{

//
请求方式:
POST

method:
'post'
,

//
请求参数

parameters:params,

//
指定回调函数

onComplete: processResponse,

//
是否异步发送请求

asynchronous:
true

}
);

}function
processResponse(request)

{

$(
"show"
).innerHTML=request.responseText;

}</
script
>

</
head
>

<
body
>

<
form
id
=
"form1"
name
=
"form1"
method
=
"post"
>

部门编号
<
INPUT
TYPE
=
"text"
name
=
"dept.deptid"
id
=
"deptid"
/><
br
>

部门名称
<
INPUT
TYPE
=
"text"
name
=
"dept.deptname"
id
=
"deptname"
/><
br
>

部门编制
<
INPUT
TYPE
=
"text"
name
=
"dept.deptnum"
id
=
"deptnum"
/><
br
>

部门描述
<
INPUT
TYPE
=
"text"
name
=
"dept.deptdesc"
id
=
"deptdesc"
/><
br
>

<
INPUT
TYPE
=
"button"
value
=
"
提交
"
onClick
=
"gotClick();"
/>

</
form
>

<
div
id
=
"show"
>

</
div
>

</
body
>

</
html
>

五、当json
碰到hibernate
延时加载


在开发Struts2.0+hibernate3.2+spring2.0
项目过程中,遇到了
failed to lazily initialize a collection of role:
org.wllt.www.pojo.Dept.emps, no session or session was closed

这个异常的出现,通过以下方法可以解决这个问题:

1
、是把对应一对多的那两个列lazy=true
改为lazy
=false
即可;

2
、对于查询中如果用的是xxx.load
(class
,id
)则改为xxx,get(class
,id)


3
、在web.xml
文件中加入:

<filter>

<filter-name>hibernateFilter</filter-name>

<filter-class>

org.springframework.orm.hibernate3.support.OpenSessionInViewFilter

</filter-class>

<init-param>

<param-name>singleSession</param-name>

<param-value>false</param-value>

</init-param>

<!--
这个
--
<init-param>
一定要加不然很可能会报错


org.springframework.dao.InvalidDataAccessApiUsageException:Write
operations are not allowed in read-only mode (FlushMode.NEVER) - turn your
Session into FlushMode.AUTO or remove 'readOnly' marker from transaction
definition

-->

</filter>

<filter-mapping>

<filter-name>hibernateFilter</filter-name>

<url-pattern>*.wllt</url-pattern>

</filter-mapping>

对以上方法进行一一测试,到后来结果都是一样,出现同样的异常,其实spring
能很好地解决这个问题,Spring
框架为Hibernate
延迟加载与DAO
模式的整合提供了一种方便的解决方法。以一个Web
应用为例,Spring
提供了OpenSessionInViewFilter
和OpenSessionInViewInterceptor
。我们可以随意选择一个类来实现相同的功能。两种方法唯一的不同就在于interceptor
在Spring
容器中运行并被配置在web
应用的上下文中,而Filter
在Spring
之前运行并被配置在web.xml
中。不管用哪个,他们都在请求将当前会话与当前(数据库)线程绑定时打开Hibernate
会话。一旦已绑定到线程,这个打开了的Hibernate
会话可以在DAO
实现类中透明地使用。这个会话会为延迟加载数据库中值对象的视图保持打开状态。一旦这个逻辑视图完成了,Hibernate
会话会在Filter
的doFilter
方法或者Interceptor
的postHandle
方法中被关闭。用spring
解决这个问题而且不用把lazy
设置为false
,提高性能。

方法是:在web.xml
中加入以下配置:

<filter>

<filter-name>hibernateFilter</filter-name>

<filter-class>

org.springframework.orm.hibernate3.support.OpenSessionInViewFilter

</filter-class>

</filter>

<filter-mapping>

<filter-name>hibernateFilter</filter-name>

<url-pattern>*.action</url-pattern>

</filter-mapping>

如果把这个配置随意地加到web.xml
的最后,会出现相应的错误,其实该过滤器和Struts2
的过滤器有顺序的问题,应该是:

OpenSessionInViewFilter

FilterDispatcher

的顺序,最后调整过滤器的顺序,问题解决。

注意:有些时候会出现一些页面或者一些其他的action
过滤不到,可以修改如下:

<url-pattern>/*</url-pattern>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: