前面我定义了
type TPerson = class FirstName: string; LastName: string; Age: Integer; end; TPersonArray = array of TPerson;然后写了服务方法
function TServerMethods1.GetPersons: TJSONArray;这样写没问题,如果直接写成
function TServerMethods1.GetPersons: TPersonArray;是不可以的,因为TPersonArray不是类,它的TTypeInfo的TypeKind不是tkClass而是tkDynArray,目前是不datasnap支持的。
于是可以写一个集合类
TPersonCollection = class private FPersons: TArray然后写服务方法; public destructor Destroy; override; //别忘了free掉元素 property Persons: TArray read FPersons write FPersons; end;
function TServerMethods1.GetPersons: TPersonCollection;这样就可以了,服务器端可以直接写,客户端可以直接读,不用自己去marshal和unmarshal了。
那是不是说,我们的Field只要封到类里就一定ok呢,不是的。
将上面的类修改为如下
TPerson = class FirstName: string; LastName: string; Age: Integer; Birthday: TDateTime; Memo: TStringList; end;
TDateTime其实是一个double类型,在datasnap里面是被支持的,TStringList却不行了。但是如果客户端是其他语言REST来的,TDataTime在客户端就难被解释了。怎么办呢
其实Datasnap里,我们可以自己定义marshal的规则。
XE2里面,有两个类TConverterEvent给编码,和TReverterEvent来解码。给EMBT封装后,用法也很简单。
var DateTimeDecodeFunc: TStringReverter; DateTimeEncodeFunc: TStringConverter; procedure RegisterReverterConverters; var decode: TReverterEvent; encode: TConverterEvent; begin DateTimeEncodeFunc := function(Data: TObject; Field: string): string var ctx: TRttiContext; date: TDateTime; begin date := ctx.GetType(Data.ClassType).GetField(Field).GetValue(Data).AsType简单的说,就是定义转换规则后,加给TJSONConverters,让TJSONConverters知道要这么转换来转换回去。 至于TStringList的转换,道理明白了,所以也一样可以写了。Delphi2010的DataSnap可以看这里。 转换的一些普通的函数,EMBT已经提供得有。在Data.DBXJSONReflect单元里,能找到; Result := FormatDateTime('yyyy-mm-dd hh:nn:ss', date); end; DateTimeDecodeFunc := procedure(Data: TObject; Field: string; Arg: string) var ctx: TRttiContext; datetime: TDateTime; begin datetime := EncodeDateTime(StrToInt(Copy(Arg, 1, 4)), //yyyy StrToInt(Copy(Arg, 6, 2)), //mm StrToInt(Copy(Arg, 9, 2)), //dd StrToInt(Copy(Arg, 12, 2)),//hh StrToInt(Copy(Arg, 15, 2)),//nn StrToInt(Copy(Arg, 18, 2)),//ss 0); ctx.GetType(Data.ClassType).GetField(Field).SetValue(Data, datetime); end; decode := TReverterEvent.Create(TPerson, 'Birthday'); decode.StringReverter := DateTimeDecodeFunc; TJSONConverters.AddReverter(R); encode := TConverterEvent.Create(TPerson, 'Birthday'); encode.StringConverter := DateTimeEncodeFunc; TJSONConverters.AddConverter(encode); end;
///除了这个方法,XE2里面另外还用到了描述类,来自动告诉JSON怎么转换。Converts a TStringList into a TSerStringList function StringListConverter(Data: TObject): TObject; ///Reverts a TSerStringList into a TStringList function StringListReverter(Ser: TObject): TObject; /// converts the pair list of a JSON Object into a serializable structure function JSONObjectPairListConverter(Data: TObject; Field: String): TListOfObjects; function JSONArrayElementsConverter(Data: TObject; Field: String): TListOfObjects; procedure JSONObjectPairListReverter(Data: TObject; Field: String; Args: TListOfObjects); procedure JSONArrayElementsReverter(Data: TObject; Field: String; Args: TListOfObjects);
将上面的TPerson修改为
TPerson = class FirstName: string; LastName: string; Age: Integer; [JSONReflect(ctString, rtString, TDateTimeInterceptor, nil, True)] Birthday: TDateTime; Memo: TStringList; end;给Birthday增加描述,JSONReflect是个描述类,继承自TCustomAttribute。
看JSONReflect的代码
constructor Create(ConverterType: TConverterType; ReverterType: TReverterType; InterceptorType: TClass = nil; PopulationCustomizerType: TClass = nil; IsMarshalOwned: boolean = false); overload; TConverterType = (ctObjects, ctStrings, ctTypeObjects, ctTypeStrings, ctObject, ctString, ctTypeObject, ctTypeString); TReverterType = (rtObjects, rtStrings, rtTypeObjects, rtTypeStrings, rtObject, rtString, rtTypeObject, rtTypeString);这几种类型
顾名思义,
第一个参数是表示进去的数据类型,
第二个是出来的类型,
第三个是执行转换的类,必须从TJSONInterceptor继承
第四个先不管,必须从TJSONPopulationCustomizer继承
第五个表示了是否拥有创建出来的类
目前只管写第3个执行转换的类。由于我们只是要转字符串,所以只覆盖字符的转换就行。
TDateTimeInterceptor = class(TJSONInterceptor) public function StringConverter(Data: TObject; Field: string): string; override; procedure StringReverter(Data: TObject; Field: string; Arg: string); override; end;怎么转换,和上面的一样的了。我是觉得这个方法比上面的法子好。
没有评论:
发表评论