配色: 字号:
Struts2-Json-Plugin 的使用
2016-10-26 | 阅:  转:  |  分享 
  
Struts2-Json-Plugin的使用



在Struts2中要使用Ajax获得Json数据我认为目前还是struts2-json-plugin了。当然你你可以用手工用像XStream、GoogleGson、Jackson这样的工具手工把Java对象转换成Json字符串再写往Response去,要写的代码自然多不了,还得留心字符集与contenttype。而struts2-json-plugin毫无疑问是与Struts2最亲近了,只需你配置一些属性就能得到你想的结果。



本想分几篇逐步介绍如何使用struts2-json-plugin的,然而就在现在发现官方的struts2-json-plugin指南已经很详细了,所以干脆翻译一下http://struts.apache.org/2.2.1.1/docs/json-plugin.html,同时自己加深对它的理解。



JSON插件提供了一个"json"结果类型来把action序列化成JSON.这一序列化的过程是递归的,意即整个对象图,从action类开始(未包括基类)将会被序列化(可以用"root"属性来指定自己的根对象).如果使用了json拦截器,action将可通过请求中的JSON内容组装出来,该拦截器遵循以下几条规则:



"content-type"必须为"application/json"

JSON内容必须是格式良好的,参考json.org中的语法.

Action里必须有欲获取值的属性的相应public的"setter"方法.

所支持的类型有:原始类型(int,long...String),Date,List,Map,原始类型数组,其他的类(将会支持更多),和其他类型的数组.

JSON中的任何将要被填入到list或map中的对象会是Map类型(属性映射到值),任何整数都是Long类型,任何小数会是Double类型,任何数组会是List类型.

给定下面的JSON字符串:

{

"doubleValue":10.10,

"nestedBean":{

"name":"MrBean"

},

"list":["A",10,20.20,{

"firstName":"ElZorro"

}],

"array":[10,20]

}

action中必须有一个"setDoubleValue"方法,参数为"float"或者"double"(拦截器将会把值转换为相应的类型).还必须有一个"setNestedBean"方法,它的参数类型可以为任何类类型,其中含有参数为"String"的"setName"方法.还必须有一个参数为"List"的"setList"方法,这个List中将会包含:"A"(String),10(Long),20.20(Double),Map("firstName"->"ElZorro")."setArray"方法可以是"List",或任何数字类型数组作参数的.

序列化你的对象成javascript的JSON,参考json2

安装

本插件可通过把插件jar包到你的应用的/WEB-INF/lib目录来完成安装.没有别的文件需要拷贝或被创建.



使用maven的话,加入下列到你的pom中:



...



org.apache.struts

struts2-json-plugin

STRUTS_VERSION



...





定制化序列化和反序列化

使用JSON注解来达到定制序列化和反序列化过程.可用的JSON注解如下:



名称 描述 默认值 序列化 反序列化

name 定制字段名 empty yes no

serialize 标识为可被序列化 true yes no

deserialize 标识为可被反序列化 true no yes

format 用于格式化或解析Date字段的格式 "yyyy-MM-dd''T''HH:mm:ss" yes yes

排除属性



逗号分隔的正则表达式列表可传递给JSONResult和Interceptor(拦截器),被任何一个正则表达式匹配的属性将会在序列化过程时忽略掉:







login.password,

studentList.\.sin











true



login.password,

studentList.\.sin





包含属性

逗号分隔的正则表达式列表可被传递给JSONResult,用于限制哪些属性可用于序列化.只有当能够匹配任何一个正则表达式的属性才会包含在序列化输出中.



注:

排除属性表达式优先于包含属性的表达式.那就是说,如果包含和排除表达式应用于同一个结果,包含表达式对于被排除表达式匹配到的属性是不起作用的.







^entries\[\d+\]\.clientNumber,

^entries\[\d+\]\.scheduleNumber,

^entries\[\d+\]\.createUserId





根对象

使用"root"属性(OGNL表达式)指定被用于序列化的根对象.





person.job





"root"属性(OGNL表达式)也可以用于拦截器来指定被组装的对象,确保这个对象不会是null.



bean1.bean2



包装

可能会有某些原因,你想要用些文本对JSON输出包装一下,像用注释包裹,加上前缀,或使用文件上载让结果显示在textarea之中.用wrapPrefix在开始处加上内容,wrapPostfix添加内容在尾端.这两个参数优先使用,而"wrapWithComments"和"prefix"自从0.34后就不推荐使用.例子:



进行注释:





/

/



添加前缀:



{}&&



包裹上传的文件内容:



]]>



包裹以注释

wrapWithComments自0.34不推荐使用,建议用wrapPrefix和wrapSuffix.

wrapWithComments可使得安全的JSON文本变得不安全.例如,

["/alert(''XSS'');/"]



谢谢DouglasCrockford的提示!应考虑用prefix.



假如被序列化的JSON是{name:''ElZorro''}.那么此时输出就会是:{}&&({name:''ElZorro''}



假如"wrapWithComments"(默认为false)属性被设为true,生成的被包裹上注释的JSON就如下:

/{

"doubleVal":10.10,

"nestedBean":{

"name":"MrBean"

},

"list":["A",10,20.20,{

"firstName":"ElZorro"

}],

"array":[10,20]

}/

欲取消上面的注释,可用:

varresponseObject=eval("("+data.substring(data.indexOf("\/\")+2,data.lastIndexOf("\\/"))+")");

前缀

prefix从0.34后不建议用,请用wrapPrefix和wrapSuffix.

假如参数prefix被设置为true,生成的JSON将被附上前缀"{}&&".这有助于防止被劫持.详细内容请看thisDojoTicket:



true



基类

默认时,定义在"root"对象的基类中的属性不会被序列化,要序列化来自于所有基类(直到Object)中的属性,需在JSONresult里设置"ignoreHierarchy"为false:



false



枚举类型

默认的,Enum被序列化为name=value对,这里的value=name().

publicenumAnEnum{

ValueA,

ValueB

}

JSON:"myEnum":"ValueA"



使用result的参数"enumAsBean"可使得Enum像一个bean一样的被序列化,特定的属性为_name,值为name().所有的枚举属性都会被序列化.

publicenumAnEnum{

ValueA("A"),

ValueB("B");



privateStringval;



publicAnEnum(val){this.val=val;}publicgetVal(){

returnval;

}

}

JSON:myEnum:{"_name":"ValueA","val":"A"}

在struts.xml中启用该参数:



true



压缩输出.

设置enableGZIP属性为true可用gzip压缩响应输出.在请求后"Accept-Encoding"头中必须包含"gzip"才能正常工作.



true



防止浏览器缓存响应数据

noCache设置为true(默认为false)会设置如下响应头:



Cache-Control:no-cache

Expires:0

Pragma:No-cache



true



排除值为null的属性

默认的,为null的字段也被序列化,生成像{property_name:null}.这能够通过设置excludeNullProperties为true来防止.



true



状态和错误代码

使用statusCode来设置响应状态代码:



304



同时可用errorCode来发送一个错误(theservermightendupsendingsomethingtotheclientwhichisnottheserializedJSON):



404



JSONP

ToenableJSONP,settheparametercallbackParameterineithertheJSONResultortheInterceptor.Aparameterwiththatnamewillbereadfromtherequest,anditvaluewillbeusedastheJSONPfunction.Assumingthatarequestismadewiththeparameter"callback"="exec":



callback



AndthattheserializedJSONis{name:''ElZorro''}.Thentheoutputwillbe:exec({name:''ElZorro''})



ContentType

Contenttypewillbesettoapplication/json-rpcbydefaultifSMDisbeingused,orapplication/jsonotherwise.Sometimesitisnecessarytosetthecontenttypetosomethingelse,likewhenuploadingfileswithDojoandYUI.UsethecontentTypeparameterinthosecases.



text/html



Example

SetupAction

Thissimpleactionhassomefields:



Example:

importjava.util.HashMap;

importjava.util.Map;



importcom.opensymphony.xwork2.Action;



publicclassJSONExample{

privateStringfield1="str";

privateint[]ints={10,20};

privateMapmap=newHashMap();

privateStringcustomName="custom";



//''transient''fieldsarenotserialized

privatetransientStringfield2;



//fieldswithoutgettermethodarenotserialized

privateStringfield3;



publicStringexecute(){

map.put("John","Galt");

returnAction.SUCCESS;

}



publicStringgetField1(){

returnfield1;

}



publicvoidsetField1(Stringfield1){

this.field1=field1;

}



publicint[]getInts(){

returnints;

}



publicvoidsetInts(int[]ints){

this.ints=ints;

}



publicMapgetMap(){

returnmap;

}



publicvoidsetMap(Mapmap){

this.map=map;

}



@JSON(name="newName")

publicStringgetCustomName(){

returnthis.customName;

}

}

Writethemappingfortheaction

Addthemapinsideapackagethatextends"json-default"

Addaresultoftype"json"

Example:




"-//ApacheSoftwareFoundation//DTDStrutsConfiguration2.0//EN"

"http://struts.apache.org/dtds/struts-2.0.dtd">





















JSONexampleoutput

{

"field1":"str",

"ints":[10,20],

"map":{

"John":"Galt"

},

"newName":"custom"

}

JSONRPC

ThejsonplugincanbeusedtoexecuteactionmethodsfromJavaScriptandreturntheoutput.ThisfeaturewasdevelopedwithDojoinmind,soitusesSimpleMethodDefinitiontoadvertisetheremoteservice.Let''sworkitoutwithanexample(uselessasmostexamples).



Firstwritetheaction:

packagesmd;



importcom.googlecode.jsonplugin.annotations.SMDMethod;

importcom.opensymphony.xwork2.Action;



publicclassSMDAction{

publicStringsmd(){

returnAction.SUCCESS;

}



@SMDMethod

publicBeandoSomething(Beanbean,intquantity){

bean.setPrice(quantity10);

returnbean;

}

}

MethodsthatwillbecalledremotelymustbeannotatedwiththeSMDMethodannotation,forsecurityreasons.Themethodwilltakeabeanobject,modifyitspriceandreturnit.TheactioncanbeannotatedwiththeSMDannotationtocustomizethegeneratedSMD(moreonthatsoon),andparameterscanbeannotatedwithSMDMewww.baiyuewang.netthodParameter.Asyoucansee,wehavea"dummy",smdmethod.ThismethodwillbeusedtogeneratetheSimpleMethodDefinition(adefinitionofalltheservicesprovidedbythisclass),usingthe"json"result.



Thebeanclass:

packagesmd;



publicclassBean{

privateStringtype;

privateintprice;



publicStringgetType(){

returntype;

}



publicvoidsetType(Stringtype){

this.type=type;

}



publicintgetPrice(){

returnprice;

}



publicvoidsetPrice(intprice){

this.price=price;

}



}

Themapping:







true





true







Nothingspecialhere,exceptthatboththeinterceptorandtheresultmustbeappliedtotheaction,and"enableSMD"mustbeenabledforboth.



Nowthejavascriptcode:





//loaddojoRPC

dojo.require("dojo.rpc.");



//createserviceobject(proxy)usingSMD(generatedbythejsonresult)

varservice=newdojo.rpc.JsonService("${smdUrl}");



//functioncalledwhenremotemethodreturns

varcallback=function(bean){

alert("Pricefor"+bean.type+"is"+bean.price);

};



//parameter

varbean={type:"Mocca"};



//executeremotemethod

vardefered=service.doSomething(bean,5);



//attachcallbacktodeferedobject

defered.addCallback(callback);



Dojo''sJsonServicewillmakearequesttotheactiontoloadtheSMD,whichwillreturnaJSONobjectwiththedefinitionoftheavailableremotemethods,usingthatinformationDojocreatesa"proxy"forthosemethods.Becauseoftheasyncwww.wang027.comhronousnatureoftherequest,whenthemethodisexecuted,adeferredobjectisreturned,towhichacallbackfunctioncanbeattached.Thecallbackfunctionwillreceiveasaparametertheobjectreturnedfromyouraction.That''sit.



Proxiedobjects

AsannotationsarenotinheritedinJava,someusermightexperienceproblemswhiletryingtoserializeobjectsthatareproxied.eg.whenyouhaveattachedAOPinterceptorstoyouraction.



Inthissituation,thepluginwillnotdetecttheannotationsonmethodsinyouraction.



Toovercomethis,setthe"ignoreInterfaces"resultparametertofalse(truebydefault)torequestthattheplugininspectsallinterfacesandsuperclassesoftheactionforannotationsontheaction''smethods.



NOTE:Thisparametershouldonlybesettofalseifyouractioncouldbeaproxyasthereisaperformancecostcausedbyrecursionthroughtheinterfaces.







true

false





true

false







献花(0)
+1
(本文系thedust79首藏)