前不久刚做了个机遇web service的服务,老大一看,笑了,说是他的本意是就做个servlet,然后客户端直接调用,没必要用axis,不过都做完了,就没再改了,但自己处于好玩,就自己改写了下,确实是通讯两端比较固定时更方便,只不过之间的协议需要自己来定义,不像web service的协议是通用的。
首先是两端的协议,包括访问url,访问的具体类及该类的方法,该方法的参数。


public class ServerClientProtocol implements java.io.Serializable ...{
private String serverURL;


/** *//** 服务器端实例的类名 */
private String className;


/** *//** 方法返回的类型 */
private String methodName;


/** *//** 方法返回的类型 */
private String returnType;


/** *//** 参数列表 */
private Object[] parameter = null;
//用来添加参数

public void addParameter(String index, Object content) throws Exception...{
int element = 0;

try...{
element = Integer.parseInt(index);

}catch (Exception e)...{throw new Exception("输入的索引不正确");}

if (0 < element)...{

if (null == parameter)...{
parameter = new Object[element];
parameter[element - 1] = content;
return ;
}

else if (null != parameter)...{

if (element >= parameter.length)...{
Object[] temp = new Object[element];
System.arraycopy(parameter, 0, temp, 0, parameter.length);
temp[element - 1] = content;
parameter = temp;
}

else...{
parameter[element - 1] = content;
}
return ;
}
}
throw new Exception("参数索引从1开始");
}


public ServerClientProtocol(String serverURL, String className, String methodName) ...{
this.serverURL = serverURL;
this.className = className;
this.methodName = methodName;
}


public ServerClientProtocol(String serverURL, String className) ...{
this(serverURL, className, null);
}


/** *//**
set and get method ....................
*/
}
其实可以把协议做成xml配置的方式更好些。
服务器端就是一个servlet用来接受请求。

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.whty.protocol.ServerClientProtocol;


public class RemoteServlet extends HttpServlet ...{

@Override

protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException ...{
// TODO Auto-generated method stub
System.out.println("ok --------------");
ObjectInputStream in = new ObjectInputStream(request.getInputStream());

try ...{
response.setContentType("application/octest-stream");
//获取客户端的对象,遵守协议的规则。
ServerClientProtocol protocol = (ServerClientProtocol)in.readObject();
//根据类名来加载实例
Object service = Class.forName(protocol.getClassName()).newInstance();
//根据内省来获取需要调用的方法,很有用的东西,有空会研究下框架的内省
//第二个参数 object.class 表示不需获得父类的方法
BeanInfo beanInfo = Introspector.getBeanInfo(service.getClass(), Object.class);
MethodDescriptor[] methodDescriptor = beanInfo.getMethodDescriptors();
Method method = null;

for (int i = 0; i < methodDescriptor.length; i++)...{
MethodDescriptor descriptor = methodDescriptor[i];
method = descriptor.getMethod();
if (method.getName().equals(protocol.getMethodName()))
break ;
}
Object obj = null;
//invoke 来调用该方法,协议中还可以加个返回值类型来判断下,做完才想到。
if (method != null)
obj = method.invoke(service, protocol.getParameter());
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(obj);
out.flush();
//将值返回给客户端
byte buf[]= byteOut.toByteArray();
response.setContentLength(buf.length);
ServletOutputStream servletout = response.getOutputStream();
servletout.write(buf);
servletout.close();


} catch (Exception e) ...{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
在服务器端还需要客户端调用的具体类和方法,servlet里面是根据反射来实例化的对象,这个classname才是具体要调用的类,我一般都会做个接口或抽象类,调用时会调用具体的实现类。

public interface InterfaceService ...{
public String doSomeThing(Object s1, Object s2, Object s3);
}

实际的调用的在实现类的里面。

public class OperationService implements InterfaceService ...{


public String doSomeThing(Object s1, Object s2, Object s3) ...{
// TODO Auto-generated method stub
System.out.println("dosomething............");
System.out.println(s1 + " = " + s2 + " = " + s3);
return "something";
}

}
服务器端就这些了,客户端这边首先需要同样的一个协议,也就是ServerClientProtocol.java这个类。

import java.util.ArrayList;
import java.util.List;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URL;
import java.net.URLConnection;

import cn.whty.protocol.ServerClientProtocol;


public class ClientTest ...{


/** *//**
* @param args
* @throws Exception
*/

public static void main(String[] args) throws Exception ...{
// TODO Auto-generated method stub
InitParams.init();
String url = "http://localhost:8082/servletServer/servlet/RemoteServlet";
//我这里的packagename和classname都是通过属性文件加载进来的
ServerClientProtocol protocol = new ServerClientProtocol(url, InitParams.packageName + "." + InitParams.className, "doSomeThing");
List list = new ArrayList();
list.add("dddd");
protocol.addParameter("1", "I'm 11....");
protocol.addParameter("2", list);
protocol.addParameter("3", "I'm 33....");
Object returnObj = (Object) new ClientTest().process(protocol);
System.out.println(returnObj);
}


public Object process(ServerClientProtocol protocol) ...{
URLConnection con = null;
ObjectOutputStream dataout = null;
ObjectInputStream in = null;
Object obj = null;

try ...{
URL url = new URL(protocol.getServerURL());
con = url.openConnection();
con.setUseCaches(true);
con.setDoOutput(true);
con.setDoInput(true);
con.setRequestProperty("Content-type", "application/octest-stream");
con.setRequestProperty("Content-length", "" + -1);
dataout = new ObjectOutputStream(con.getOutputStream());
dataout.writeObject(protocol);
dataout.flush();
dataout.close();
in = new ObjectInputStream(con.getInputStream());
obj = in.readObject();
in.close();

} catch (Exception e) ...{
e.printStackTrace();
}
return obj;
}

}

自己定义协议虽然不通用,在一定范围的局部运用还是可以滴,不过不知道大量数据时会不会像web service那样慢。