论坛首页 Web前端技术论坛

Ajax框架Buffalo深度研究

浏览 17927 次
精华帖 (4) :: 良好帖 (12) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-01-11   最后修改:2010-01-19

Buffalo深度研究

——2010.01.11IT进行时[MSN:zhengxianquan AT hotmail Dot com]

目录

1. BUFFALO概述 2
1.1. 主要产品特性 2
1.2. 初次印象 5
2. BUFFALO的关键序列图 5
3. BUFFALO的协议分析 6
3.1. 概述 6
3.2. 请求[BUFFALO.CALL]协议定义 8
3.3. 响应[BUFFALO.RESPONSE]协议定义 8
3.3.1. List-数组或列表 8
3.3.1.1. List 8
3.3.1.2. Array 9
3.3.2. Map & POJO 9
3.3.3. Ref对象引用 10
3.4. FAULT异常 11
3.5. 其他 12
3.5.1. java.sql.Date 12
3.5.2. java.math.BigDecimal/ java.math.BigInteger 12
3.5.3. 还不够? 13
4. 核心类分析 13
4.1. 概述 13
4.2. SERVICE 14
4.2.1. 服务注册与初始化 14
4.2.2. 服务的匹配与调用 18
4.3. PROTOCOL 21
4.3.1. converters(类型转换解析器) 21
4.3.2. io(协议marshal/unmarshal) 22
5. 协议可能需要完善的专题讨论 26
5.1. 深度分析 26
5.2. 可能的解决方案 27
5.2.1. 在ProtocalTag中加入新协议标签 27
5.2.2. 定义两个工具类 28
5.2.2.1. PrimitiveObjectWrapper 28
5.2.2.2. PrimitiveObjectUtil 28
5.2.3. 新增转换器PrimitiveDoubleConverter 29
5.2.4. 修改DoubleConverter的协议标签类型 30
5.2.5. 注册转换器到DefaultConverterLookup 30
5.2.6. 修订FastStreamReader 33
5.2.7. 完善BuffaloCall 33
5.2.8. 客户端buffalo.js 34
5.3. 测试结果 35
6. 参考 36

 

1.  Buffalo概述

Buffalo一个贯穿前后端的比较完整的Ajax框架,目前最新的版本是2.0.1,其主页是:

http://buffalo.sourceforge.net/,可通过该页面找到下载。

不过该版本自2007年来就没有更新了,有点遗憾,不管怎样,一出来就关注到了,早前通读过代码,是个好作品。

上周开始用了些零碎的时间,重新评估并进行了深入的研究,其目的在于通过深度掌握某个优秀的贯穿前后端的AJAX框架,以提高自己的整体认知感。

1.1.      主要产品特性

略,可参考:http://buffalo.sourceforge.net/features.html

1.2.      初次印象

Buffalo最有价值之处,个人感觉有两点:

1、  后端实现了较为完整的基于xmlxml<->object序列化反序列化协议;

2、  前端提供了适配协议的调用封装和响应解析机制,并基于回调机制提供编码API

 

另,作品受xstream影响颇深,如果看过xstream的代码大家的感觉会更明显,不知道这样说Michael是否有意见:buffalo后端转换器、IO部分的代码,是xstreamlightweight版本:)

   发表时间:2010-01-11  

2.  Buffalo的关键序列图

要了解buffalo,与其他开源框架一样,最好的实践在于“跑起来”,跟踪并分析其调用执行过程,即可串接其核心的代码组织、逻辑调用关系等细节。

其请求过程的序列图可大概绘制如下:

 

概要说明:

1、  整体提供了一个ServletApplicationServlet作为唯一的前后端通讯窗口;通过Servletinit过程初始化配置暴露给Buffalo远程调用的服务(支持内置的buffalo-service.properties配置及spring配置),置于ServiceRepository中;

2、  根据request.getPathInfo()所得到的URL规则,如“/buffalo/simpleService”,创建对应的Worker,目前仅实现了BuffaloWorker

3、  同样根据pageInfo解析服务名称(如simpleService),并从ServiceRepository中获取对应的服务实例;

4、  通过BuffaloProtocal实例unmarshall客户端发出的InputStream,并通过获取方法和参数,构建完整的BuffaloCall

5、  通过分析BuffaloCall对应业务服务各方法参数的匹配权重,获取最合适的调用方法,并调用,匹配过的方法,将置入缓存以提升性能;

6、  根据调用结果,需要通过BuffaloProtocal实例marshall结果,并通过StreamWriterwrapresponse.getOutputStream())写回调用客户端;

7、  客户端通过Buffalo.Reply解析返回的结果,并实现与UI的交互。


 

 

  • 大小: 14 KB
0 请登录后投票
   发表时间:2010-01-11  

3.  Buffalo的协议分析

3.1.      概述

协议就是前后端用以通信的约定,Buffalo提供的是XML的协议。

请求过程是协议unmarshal的过程,需要通过解析request.getInputStream();而把业务执行结果写回客户端的过程是协议的marshal过程。(说句题外话,Michael应该是笔误了,在BuffaloProtocal类中写成了unmarshall/marshall

显然Michael是主张测试驱动的开发,单元测试用例写的非常到位,应该说覆盖性是没问题。通过测试用例学习协议,是不错的办法。

当然了,也可直接参考官方网站的说明:http://buffalo.sourceforge.net/protocol.html

3.2.      请求[Buffalo.Call]协议定义

所有的请求,都通过如下格式发出:

buffalo.remoteCall({Service.Method}, {Params}, {CallBackFunction})

其中:

Service.Method——Service为在buffalo-service.propertiesSpring注册的服务标识;

Params——参数Array,没有参数则定义一个空的数组“[]”(建议对null进行保护);

CallBackFunction——回调函数,提供一个Buffalo.Reply参数

 

最终给服务器端发出的请求,是标准的基于UTF-8XML,格式举例如下:

例子

说明

<buffalo-call>

  <method>sum</method>

  <double>1</double>

  <double>2</double>

</buffalo-call>

 

->这是Service对应的方法

->之后的都是参数,这里表示有两个参数,均为double

 

0 请登录后投票
   发表时间:2010-01-11  

3.4.      fault异常

对于异常,我们经常需要关注三个东西:异常编码、异常信息和详细堆栈。

Buffalo关注业务服务所抛出的异常。

Buffalo通过捕捉java.lang.reflect.InvocationTargetException异常,使用ExceptionConverter转换器提供了类似于Map的三个属性,code, message, detail

其中:

code——异常名称,即ex.getClass().getName()

message——异常消息,即ex.getMessage()

detail——异常详细消息,如果有,则为ex.getCause().getMessage()

 

相关代码如下:

public void marshal(Object source, MarshallingContext marshallingContext, StreamWriter streamWriter) {

    Throwable ex = (Throwable) source;

    String detail = "";

    if (ex.getCause() != null) {

       detail = "caused by: " + ex.getCause().getMessage();

    }

    streamWriter.startNode(ProtocalTag.TAG_FAULT);

    node(streamWriter, ProtocalTag.TAG_STRING, "code");

    node(streamWriter, ProtocalTag.TAG_STRING, ex.getClass().getName());

    node(streamWriter, ProtocalTag.TAG_STRING, "message");

    node(streamWriter, ProtocalTag.TAG_STRING, ex.getMessage());

    node(streamWriter, ProtocalTag.TAG_STRING, "detail");

    node(streamWriter, ProtocalTag.TAG_STRING, detail);

    streamWriter.endNode();

}

 

3.5.      其他

Buffalo还实现了一些例外的对象的协议定义和转换。

3.5.1.         java.sql.Date

例子

说明

<map>

  <type>java.sql.Date</type>

  <string>value</string>

  <date>20061018T211400Z</date>

</map>

注意多了个value,且值是经过特定格式化的

 

3.5.2.         java.math.BigDecimal/ java.math.BigInteger

例子

说明

<map>

  <type>java.math.BigDecimal</type>

  <string>value</string>

  <string>1234567890</string>

</map>

注意多了个value

 

例子

说明

<map>

  <type> java.math.BigInteger</type>

  <string>value</string>

  <string>1234567890</string>

</map>

注意多了个value

You can use object.value to get the real value of those objects. When deserializing, it will use the constructor BigDecimal(String) or BigInteger(String) to create a new one.

3.5.3.         还不够?

那就自己写,实现Converter,但需要修改(目前只能这么干,BuffaloProtocal这个类应该要完善下,可方便实现配置/注入)如下注册类:

net.buffalo.protocal.converters.DefaultConverterLookup.java

 

Converter包括三个接口:

public interface Converter {  

boolean canConvert(Class type);

void marshal(Object source, MarshallingContext marshallingContext, StreamWriter streamWriter);

Object unmarshal(StreamReader reader, UnmarshallingContext unmarshallingContext);

}

 

提示:可以参考xstream进行扩展,但一般的WEB开发,这些转换器还是够了的。

0 请登录后投票
   发表时间:2010-01-11  

4.  核心类分析

4.1.      概述

先来看看代码结构,如下:



 

整体而言,与xstream有点像,但考虑到Buffalo是贯穿前后端的Ajax框架,还包括了web/view/request等部分。

代码的核心部分,主要包括了两个部分,分别为serviceprotocol,下面分别重点分析说明。

4.2.      service

此为Buffalo目前实现了的BuffaloWorker为核心的package,主要包括了业务服务Repository、业务服务方法适配定位和业务服务调用等部分。

4.2.1.         服务注册与初始化

核心类图如下:

  • 大小: 61.7 KB
  • 大小: 37.1 KB
  • 大小: 6.1 KB
  • 大小: 2.3 KB
  • 大小: 17.7 KB
0 请登录后投票
   发表时间:2010-01-11  

4.3.      protocol

协议在第三章节的“Buffalo的协议分析”中做了详细的描述,这章主要分析代码。

协议部分的代码,总体分为converters(转换器)、io(协议marshal/unmarshal)两个部分,。

从代码的结构和设计技巧可以看出,Michael深入研究过xstream的代码。

4.3.1.         converters(类型转换解析器)

转换器的代码实现了我们WEB开发常用的类型解析,从代码结构分为basiccollectionmap,还有一些exceptional(例外)的类型解析。

Converter的接口定义为:

public interface Converter {   

    boolean canConvert(Class type);

    void marshal(Object source, MarshallingContext marshallingContext, StreamWriter streamWriter);

    Object unmarshal(StreamReader reader, UnmarshallingContext unmarshallingContext);

}

类图罗列如下:



 

 

 

 

总而言之,这些代码质量都非常高,设计精巧,合理有效使用了各种设计模式,尤其是Template模式运用的非常精彩。

需要说明的是,转换器可对Array及实现了collection接口的对象进行处理,也可对Map结果的对象进行了完美的支持,而POJO其实在unmarshalMap是一样的而仅仅在marshal上有些特殊。

4.3.2.         io(协议marshal/unmarshal

io这块代码是最复杂的代码之一,涉及到协议解析的很多细节。代码由于解释过少,有些代码我需要反复调试多次才能明白具体意义——可能跟个人能力和资质有关,汗一个。

类图说明如下:



 

 

包括五个非常重要的接口,即MarshallingContextUnmarshallingContextMarshallingStrategyStreamReaderStreamWriter。分别如下:

MarshallingContext

public interface MarshallingContext {

 

    void convertAnother(Object value);

 

    List getObjects();

 

    void addObjectRef(Object object);

 

}

UnmarshallingContext

public interface UnmarshallingContext {

 

    Object convertAnother();

 

    void addObject(Object object);

 

    List getObjects();

 

}

MarshallingStrategy

public interface MarshallingStrategy {

 

    void marshal(Object obj, ConverterLookup converterLookup, StreamWriter streamWriter);

 

    BuffaloCall unmarshal(StreamReader reader, ConverterLookup converterLookup);

   

}

 

StreamReader

public interface StreamReader {

 

    boolean hasMoreChildren();

 

    void moveDown();

 

    void moveUp();

 

    String getNodeName();

 

    String getValue();

 

    void close();

 

}

 

StreamWriter

public interface StreamWriter {

   

    void startNode(String name);

 

    void setValue(String text);

 

    void endNode();

 

    void flush();

 

    void close();

 

}

从客户端读入的流(request.getInputStream()),将使用实现了MarshallingStrategy接口的DefaultMarshallingStrategyunmarshal方法,并通过实现了StreamReaderFastStreamReader解析输入流(为XML),获得必要的目标业务服务的方法和参数,以最终构建BuffaloCall对象,并最终得以调用(可参见“服务的匹配与调用”章节)。

业务服务调用完毕后,将使用实现了MarshallingStrategy接口的DefaultMarshallingStrategymarshal方法,并通过实现了StreamWriterFastStreamWriter输入协议流(为XML)到客户端,实现了XML协议的解析与交换。

FastStreamReader那种一个字符一个字符读进来并解析的过程,我是在鼓足勇气后才通读完毕的,并通过多次调试才理解所有的细节,过程中还补了不少课,善哉善哉。(以后如果要通读xstream,只怕这种勇气得更大更多,^0*

解读过程得益于Buffalo提供的单元测试类,再次感受到TDD的好处咯。

 

  • 大小: 19 KB
  • 大小: 15 KB
  • 大小: 11.3 KB
  • 大小: 11.6 KB
  • 大小: 21.7 KB
  • 大小: 26.3 KB
0 请登录后投票
   发表时间:2010-01-11   最后修改:2010-01-11

5.  协议可能需要完善的专题讨论

5.1.      深度分析

首先声明:在未与Michael充分沟通交流前,一切都只是个人的想法,未必正确。

本人在“服务的匹配与调用”章节,曾经提出过服务方法匹配的问题,Michaelbuffalo.js310行提到过“Guess the type of an javascript object”,但光完善客户端,只怕于事无补。

就如我做的实验那样,客户端可以提供divide(double a, double b)的请求,此时的xml为:

<buffalo-call>
<method>divide</method>
<double>1.1</double>
<double>2.1</double>
</buffalo-call>

 

此时调用的是divide(Double a, Double b)而不是divide(double a, double b)

虽然已经相差无几,但依然无法到达准确制导,主要还是primitive及其Wrapper之间容易造成误会。

首先我们还是仔细来看看匹配权重的代码,在相同服务下,同名称同参数长度下,下一步就考虑到了参数的匹配权重问题(这里我加了注释):

private int parameterAssignable(Class targetType, Class sourceType) {
	if (targetType.equals(sourceType)) return 6;//如果类型相等,匹配度为6
	if (targetType.isAssignableFrom(sourceType)) return 5;//同源,为5
	if (targetType.isPrimitive()) {//如果是primitive,则获取Wrapper类
		targetType = ClassUtil.getWrapperClass(targetType);
	}		
	if (targetType.equals(sourceType)) {
		return 4; //此时肯定是经过处理的匹配,只能为4
	} else if (Number.class.isAssignableFrom(targetType) && 
			 Number.class.isAssignableFrom(sourceType)) {
		return 3; //如果两边都是Number型的,马虎匹配了,为3
	}
	return 0; //0就是没啥匹配度了
}

 

 

题外话:注意下后面的if/else代码稍微有些逻辑交待不清。

同时,需要结合所涉及到的Converter,此时为DoubleConverter。同样我们看看代码:

 

 

public class DoubleConverter extends AbstractBasicConverter implements Converter{
	public boolean canConvert(Class value) {
		if (value == null) return false;
		return value.equals(double.class) || 
				value.equals(Double.class) ||
				value.equals(float.class) ||
				value.equals(Float.class);
	}	
	protected String getType() {
		return ProtocalTag.TAG_DOUBLE;
	}	
	public Object fromString(String string) {
		return Double.valueOf(string);
	}
}

 

显然,在这个例子上,是这个转换器模糊了doubleDouble,统统变成了Double

5.2.      可能的解决方案

当然,这里的解决方案是以“需要这么干”为前提假设的。在很大程度上来说,这种“精确制导”没有必要。

我仅以解决上述例子为目标,做出修缮。

5.2.1.         ProtocalTag中加入新协议标签

位置:net.buffalo.protocal.ProtocalTag

需要加入新的标签定义:

package net.buffalo.protocal;

public interface ProtocalTag {
	public static final String TAG_BOOLEAN = "boolean";
	public static final String TAG_DATE = "date";
	public static final String TAG_INT = "int";
	public static final String TAG_LONG = "long";
	public static final String TAG_NULL = "null";
	public static final String TAG_STRING = "string";
	public static final String TAG_LENGTH = "length";
	public static final String TAG_TYPE = "type";
	public static final String TAG_LIST = "list";
	public static final String TAG_MAP = "map";
	public static final String TAG_DOUBLE = "double";
	public static final String TAG_REPLY = "buffalo-reply";
	public static final String TAG_REF = "ref";
	public static final String TAG_CALL = "buffalo-call";
	public static final String TAG_FAULT = "fault";
	public static final String TAG_METHOD = "method";
	
	//加入新的协议标签 by zhengxq
	//java.lang.Double
	public static final String TAG_DOUBLE_W = "java.lang.Double";
	//其他}

 

 

5.2.2.         定义两个工具类

5.2.2.1.      PrimitiveObjectWrapper

Primitive对象的包装类:

package net.buffalo.protocal.util;

public class PrimitiveObjectWrapper {
	private Class clazz;
	private Object value;
	public PrimitiveObjectWrapper(Object value){
		this.clazz = PrimitiveObjectUtil.getPrivitiveType(value);
		this.value = value;
	}
	public Class getClazz() {
		return clazz;
	}
	public void setClazz(Class clazz) {
		this.clazz = clazz;
	}
	public Object getValue() {
		return value;
	}
	public void setValue(Object value) {
		this.value = value;
	}	
}

 

 

5.2.2.2.      PrimitiveObjectUtil

一个获取primitive类型的工具:

package net.buffalo.protocal.util;

public class PrimitiveObjectUtil {
	public static Class getPrivitiveType(Object v){
		Class clazz = v instanceof Integer ? int.class :
			v instanceof Long ? long.class :
			v instanceof Short ? short.class :
			v instanceof Byte ? byte.class :
			v instanceof Float ? float.class :
			v instanceof Double ? double.class :
			v instanceof Boolean ? boolean.class :
			v.getClass();
		return clazz;
	}
}

 

 

5.2.3.         新增转换器PrimitiveDoubleConverter

位置:net.buffalo.protocal.converters.primitive

新增primitivepackage,并建立新的转换器PrimitiveDoubleConverter.java

 

 

package net.buffalo.protocal.converters.primitive;

import net.buffalo.protocal.ProtocalTag;
import net.buffalo.protocal.converters.Converter;
import net.buffalo.protocal.converters.basic.AbstractBasicConverter;
import net.buffalo.protocal.util.PrimitiveObjectWrapper;

public class PrimitiveDoubleConverter extends AbstractBasicConverter implements Converter{

	public boolean canConvert(Class value) {
		if (value == null) return false;
		return value.equals(double.class);
	}
	
	protected String getType() {
		return ProtocalTag.TAG_DOUBLE;
	}

	public Object fromString(String string) { 
		//get the custom Wrapper
		return new PrimitiveObjectWrapper(Double.valueOf(string));
	}	
}

 

5.2.4.         修改DoubleConverter的协议标签类型

位置:net.buffalo.protocal.converters.basic.DoubleConverter.java

不再是ProtocalTag.TAG_DOUBLE了:

protected String getType() {
		return ProtocalTag.TAG_DOUBLE_W;
	}

 

5.2.5.         注册转换器到DefaultConverterLookup

位置:net.buffalo.protocal.converters.DefaultConverterLookup.java

protected void registerDefaultConverters() {
	BooleanConverter booleanConverter = new BooleanConverter();
	DoubleConverter doubleConverter = new DoubleConverter();
	IntegerConverter integerConverter = new IntegerConverter();
	LongConverter longConverter = new LongConverter();
	StringConverter stringConverter = new StringConverter();
	DateConverter dateConverter = new DateConverter();
	CollectionConverter collectionConverter = new CollectionConverter();
	MapConverter mapConverter = new MapConverter();
	ArrayConverter arrayConverter = new ArrayConverter();
	SqlDateConverter sqlDateConverter = new SqlDateConverter();
	BigNumberConverter bigNumberConverter = new BigNumberConverter();
	ExceptionConverter exceptionConverter = new ExceptionConverter();
	ObjectConverter objectConverter = new ObjectConverter();
	
	//新增新的转换器定义
	PrimitiveDoubleConverter primitiveDoubleConverter = new PrimitiveDoubleConverter();

	converters.add(nullConverter);
	converters.add(booleanConverter);
	converters.add(doubleConverter);
	converters.add(integerConverter);
	converters.add(longConverter);
	converters.add(stringConverter);
	converters.add(dateConverter);
	converters.add(collectionConverter);
	converters.add(mapConverter);
	converters.add(arrayConverter);
	converters.add(sqlDateConverter);
	converters.add(bigNumberConverter);
	converters.add(exceptionConverter);
	// register new primitiveDoubleConverter
	converters.add(primitiveDoubleConverter);
	// Should be last one
	converters.add(objectConverter);
	
	tagNameConverterCache.put(ProtocalTag.TAG_BOOLEAN, booleanConverter);
	tagNameConverterCache.put(ProtocalTag.TAG_STRING, stringConverter);
	tagNameConverterCache.put(ProtocalTag.TAG_INT, integerConverter);
	tagNameConverterCache.put(ProtocalTag.TAG_LONG, longConverter);
	tagNameConverterCache.put(ProtocalTag.TAG_NULL, nullConverter);
	tagNameConverterCache.put(ProtocalTag.TAG_DATE, dateConverter);
	tagNameConverterCache.put(ProtocalTag.TAG_LIST, collectionConverter);
	tagNameConverterCache.put(ProtocalTag.TAG_MAP, mapConverter);
	tagNameConverterCache.put(ProtocalTag.TAG_REF, new ReferenceConverter());
	// edit the doubleConverter
	tagNameConverterCache.put(ProtocalTag.TAG_DOUBLE_W, doubleConverter);
	// register new primitiveDoubleConverter
	tagNameConverterCache.put(ProtocalTag.TAG_DOUBLE, primitiveDoubleConverter);
	
	converterCache.put(Boolean.class, booleanConverter);
	converterCache.put(boolean.class, booleanConverter);
	converterCache.put(String.class, stringConverter);
	converterCache.put(Integer.class, integerConverter);
	converterCache.put(int.class, integerConverter);
	converterCache.put(Long.class, longConverter);
	converterCache.put(long.class, longConverter);
	converterCache.put(Double.class, doubleConverter);
	// edit the double converter mapping
	//converterCache.put(double.class, doubleConverter);
	converterCache.put(double.class, primitiveDoubleConverter);
	converterCache.put(Date.class, dateConverter);
	converterCache.put(ArrayList.class, collectionConverter);
	converterCache.put(LinkedList.class, collectionConverter);
	converterCache.put(HashSet.class, collectionConverter);
	converterCache.put(Vector.class, collectionConverter);
	converterCache.put(TreeSet.class, collectionConverter);
	converterCache.put(HashMap.class, mapConverter);
	converterCache.put(TreeMap.class, mapConverter);
	converterCache.put(java.sql.Date.class, sqlDateConverter);
	converterCache.put(java.math.BigDecimal.class, bigNumberConverter);
	converterCache.put(java.math.BigInteger.class, bigNumberConverter);
}

 

 

5.2.6.         修订FastStreamReader

位置:net.buffalo.protocal.io.FastStreamReader

 

/* 判断是否有效的标签字符,必须是字母、数字和两个特定字符:':'、'-'
	 * 又新增了字符'.'
	 */
	private boolean isTagChar(int ch) {
		return (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0'
				&& ch <= '9' || ch == ':' || ch == '-' || ch == '.');
	}

 

5.2.7.         完善BuffaloCall

位置:net.buffalo.protocal.BuffaloCall

 

 

 

 

public BuffaloCall(String methodName, Object[] arguments) {		
	this.argumentTypes = new Class[arguments.length];
	this.arguments = new Object[arguments.length];
	for (int i = 0; i < arguments.length; i++) {
		// from code
		//types[i] = arguments[i].getClass();
		// to - begin
		if(arguments[i] instanceof PrimitiveObjectWrapper){
			PrimitiveObjectWrapper p = (PrimitiveObjectWrapper)arguments[i];
			//the type
			this.argumentTypes[i] = PrimitiveObjectUtil.getPrivitiveType(p.getValue());
			//the value
			this.arguments[i] = p.getValue();
		}else{
			this.argumentTypes[i] = arguments[i].getClass();
			this.arguments[i] = arguments[i];
		}
		//end
	}
	
	this.methodName = methodName;
}

 

5.2.8.         客户端buffalo.js

需要处理客户端对于java.lang.Double标签的处理,在Buffalo.Reply中(注意红色的部分):

deserialize: function(dataNode) {
		var ret;
		var type = this._getType(dataNode);
		switch (type) {			
			case "boolean": ret = this.doBoolean(dataNode); break;
			case "date": ret = this.doDate(dataNode); break;
			case "java.lang.double":;//new add
			case "double": ret = this.doDouble(dataNode); break;
			case "int": 
			case "long": 
				ret = this.doInt(dataNode);
				break;
			case "list": ret = this.doList(dataNode); break;
			case "map": ret = this.doMap(dataNode); break;
			case "null": ret = this.doNull(dataNode); break;
			case "ref": ret = this.doRef(dataNode); break;
			case "string": ret = this.doString(dataNode);break;
			case "xml": ret = this.doXML(dataNode); break;
			case "fault": ret = this.doFault(dataNode); break;
			default: ;
		}
		return ret;
	}

 

 

 

0 请登录后投票
   发表时间:2010-01-11  

5.3.      测试结果

输入:



 

提交:

<buffalo-call>

<method>divide</method>

<double>1.1</double>

<double>2.2</double>

</buffalo-call>

结果:

1)日志:

2010-1-11 13:25:40 net.buffalo.demo.simple.SimpleService divide

信息: Calling Divide in divide(double a, double b),a=1.1, b=2.2

2)界面:

 

 

 
 

OK,正是我们想要的。

当然了,还有两点需要说明:

1)其他的诸如FloatPrimitive类型的处理,照葫芦画瓢即可;

2)客户端buffalo.js还应该有少量的完善工作,重点在于类型的处理上,应该考虑的更周全些。

6.  参考

一、Buffalo官方网站:

http://buffalo.sourceforge.net

 

二、buffalo.jar 包分析:

http://blog.csdn.net/jianglike18/archive/2009/04/11/4062630.aspx

http://blog.csdn.net/jianglike18/archive/2009/05/05/4151558.aspx

  • 大小: 2.3 KB
  • 大小: 4.5 KB
0 请登录后投票
   发表时间:2010-01-11  
我们的应用中用到了buffalo,不错,国产的ajax框架,只是2.0之后就不再更新了
0 请登录后投票
   发表时间:2010-01-11  
第一次了解Buffalo,
跟我的rpcfx很像,不过我的还没有成型,
最近一次大的改动,已经跑不起来了
:)
http://code.google.com/p/rpcfx/

旧的版本 实现了java .net服务器、客户端的互相调用


都有dwr的影子。
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics