Servlet做服务端来实现异地访问

本文介绍了一种自定义远程调用协议的实现方式,通过Servlet接收客户端请求,并利用反射机制调用指定方法。客户端和服务端通过序列化传递对象,实现了简单的远程过程调用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        前不久刚做了个机遇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那样慢。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值