前些天無意中發現了XML-RPC(不過笑我才發現啊
),總想找個機會擺弄擺弄。畢業論文基本上弄完了,所以決定今天把它弄明白。
XML-RPC的最大用處,我首先想到的是瀏覽器在不刷新頁面的情況下與服務器通信,請求數據。下面我就說一下我用XML-RPC是怎么實現的。
第一步:選擇XML-RPC實現。
XML-RPC的一個很大優勢就是 它是一個標準,并且各種開發環境下都有實現(酷),這是它能夠輕松跨平臺的原因。
javascript有3個實現。我看了一下最好的應該是jsolait(JavaScript o Lait)的實現了。因為他不僅僅是一個xml-rpc的實現,除此之外還有很多javascript庫,詳細內容請看這里(http://jsolait.net/)。
java的實現就更多了,我當然毫不猶豫地選擇apache的。詳細內容看這里(http://ws.apache.org/xmlrpc/)
第二步:建立服務。
用java建立xml-rpc有兩種方式,一種是單獨開個端口,一種是用servlet。我們客戶端是用javascript,那么服務端用servlet是再好不過的了。
如何使用apache的xml-rpc,請詳細看apache的資料。(大哥你不會連servlet也不會建吧,那你還是不要往下看了)。
代碼如下:
這是一個sayHello的服務類:

public class HelloService
{

public String sayHello(String name)
{
return "Hello: "+name+" !";
}

}


下面是一個Math服務類:

public class MathService
{

public double add(Vector v)
{
double a = Double.parseDouble((String)v.get(0));
double b = Double.parseDouble((String)v.get(1));
return a+b;
}

public double mult(Vector v)
{
double a = Double.parseDouble((String)v.get(0));
double b = Double.parseDouble((String)v.get(1));
return a*b;
}
}
接著是Servlet啦,作為RPC Server用的,這段代碼比較經典,很多資料上都有。

public class RpcServer extends HttpServlet
{
protected void doPost(HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException
{
XmlRpcServer xmlrpc = new XmlRpcServer();
xmlrpc.addHandler("HelloService", new HelloService());
xmlrpc.addHandler("MathService",new MathService());
byte[] result = xmlrpc.execute(request.getInputStream());
response.setContentType("text/xml");
response.setContentLength(result.length);
OutputStream out = response.getOutputStream();
out.write(result);
out.flush();
}
}
主要是這三句:
XmlRpcServer xmlrpc = new XmlRpcServer();
xmlrpc.addHandler("HelloService", new HelloService());
xmlrpc.addHandler("MathService",new MathService());
一定要記牢Handler的名字,就是第一個參數,因為客戶端就靠他來表示要調用的方法呢。
行了現在可以在web.xml中寫入配置了:
<servlet>
<servlet-name>RpcServer</servlet-name>
<servlet-class>org.mstar.rpc.RpcServer</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RpcServer</servlet-name>
<url-pattern>/RpcServer</url-pattern>
</servlet-mapping>
至此,服務端的工作已經完成,啟動應用服務器就行了。
下面是javacript的實現,這也是難點(其實不難理解,只是沒有中文材料)。
把jsolait的庫下來以后解壓縮,得到一些js文件,具體我就不說了。
建立一個html文件:
<html>
<head>
<title>XML-RPC</title>
<script type="text/javascript" src="./js/init.js"></script>
<script type="text/javascript" src="./js/lib/urllib.js"></script>
<script type="text/javascript" src="./js/lib/xml.js"></script>
<script type="text/javascript" src="./js/lib/xmlrpc.js"></script>
<script type="text/javascript" src="./js/hello.js"></script>
</head>
a:<input type="text" id="a" /><br>
b:<input type="text" id="b" /><br>
<input type="button" id="do1" value="a+b" onclick="add()"/>
<input type="button" id="do2" value="say" onclick="hello()"/>
<input type="text" id="result" />
</html>
注意到前面那一堆javascript的引用嗎?就這么寫吧??蓜e把hello.js當成solait的東西啦(看名字也知道啦),你是找不到的。這是我們自己寫的:
hello.js
hello = function(){
var xmlrpc=null;
try{
var xmlrpc = importModule("xmlrpc");
}catch(e){
reportException(e);
throw "importing of xmlrpc module failed.";
}
var addr = "http://localhost:8080/Rpc/RpcServer";
var methods = ["HelloService.sayHello"];
var rslt;
try{
var service = new xmlrpc.ServiceProxy(addr, methods);
rslt = service.HelloService.sayHello("MTY");
}catch(e){
var em;
if(e.toTraceString){
em = e.toTraceString();
}else{
em = e.message;
}
rslt = "Error trace: \n\n" + em;
}
document.getElementById("result").value=rslt;
}
add = function(){
var xmlrpc=null;
var a = document.getElementById("a").value;
var b = document.getElementById("b").value;
var params = new Array();
params[0] = a;
params[1] = b;
try{
var xmlrpc = importModule("xmlrpc");
}catch(e){
reportException(e);
throw "importing of xmlrpc module failed.";
}
var addr = "http://localhost:8080/Rpc/RpcServer";
var methods = ["HelloService.sayHello","MathService.add"];
var rslt;
try{
var service = new xmlrpc.ServiceProxy(addr, methods);
rslt = service.MathService.add(params);
}catch(e){
var em;
if(e.toTraceString){
em = e.toTraceString();
}else{
em = e.message;
}
rslt = "Error trace: \n\n" + em;
}
document.getElementById("result").value=rslt;
}


這個js文件中有兩個函數,一個負責從sayhello,一個負責加法運算。
這里需要一些解釋的地方:
1、
var xmlrpc=null;
try{
var xmlrpc = importModule("xmlrpc");
}catch(e){
reportException(e);
throw "importing of xmlrpc module failed.";
}
這里是把xmlrpc模塊引進來,你也就這么寫吧,我也不知道為什么。
2、
var addr = "http://localhost:8080/Rpc/RpcServer";
var methods = ["HelloService.sayHello"];
定義服務地址和要用的方法名。規則大概你也能看懂:Handler名.方法名。這里的Handler名就是你在xmlrpcServer中注冊名,就是我上面讓你記住的那個。方法名就是那個類自己的方法名。注意,methods是一個數組,所以可以寫多個方法,如第二個例子。var methods = ["HelloService.sayHello","MathService.add"];
3、
try{
var service = new xmlrpc.ServiceProxy(addr, methods);
rslt = service.HelloService.sayHello("MTY");
}catch(e){
var em;
if(e.toTraceString){
em = e.toTraceString();
}else{
em = e.message;
}
rslt = "Error trace: \n\n" + em;
}
通過new xmlrpc.ServiceProxy(addr, methods);得到服務代理。
然后調用服務的方法就行了,方法就是代理.Handler名.方法名(參數)。好像參數只能有一個,在第二個例子中我開始有兩個參數a,b會發生錯誤。怎么辦?沒辦法,在javascript用Array傳參數,在java用Vector接參數(為什么用Vector,因為xml-rpc規范中的Array,apache使用Vector實現的,為什么javascript不用Vector,因為js沒有Vector,且js的的Array是可變長的)。當然這就需要很多java端類型轉換工作,js是弱類型的就不用轉換了。

