俊星的BLOG

我的DWR之简单实现

1、测试类:
package mydwr.test;

import java.util.Date;

public class Single {
    
public String printMsg(String msg, boolean bool, int i, byte b, double d) {
        String value 
= "msg:" + msg + ",bool:" + bool + ",int:" + i + ",byte:" + b + ",double:" + d
                
+ ",date:" + new Date();
        
return value;
    }
}

2、运行效果如下:


3、核心Servlet类:
public class MyDWRServlet extends HttpServlet {
    
private static final long serialVersionUID = 1L;
    
private Processor iface;
    
private Processor exec;

    
public void init(ServletConfig config) throws ServletException {
        
super.init(config);
        Map
<String, Class<?>> creators = new HashMap<String, Class<?>>();
        
try {
            
// 加载初始配置信息
            ClassLoader loader = Thread.currentThread().getContextClassLoader();
            creators.put(
"Single", loader.loadClass("mydwr.test.Single"));
        } 
catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        iface 
= new InterfaceProcessor();
        exec 
= new ExecProcessor();
        iface.setCreators(creators);
        exec.setCreators(creators);
    }

    
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException,
            ServletException {
        
this.doPost(req, resp);
    }

    
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException,
            ServletException {
        String pathInfo 
= req.getPathInfo();
        
if (pathInfo.startsWith("/interface/")) {
            iface.handle(req, resp);
        } 
else if (pathInfo.startsWith("/exec")) {
            exec.handle(req, resp);
        } 
else if (pathInfo.startsWith("/myengine.js")) {
            String output 
= null;
            StringBuffer buffer 
= new StringBuffer();
            InputStream raw 
= getClass().getResourceAsStream("/mydwr/myengine.js");
            BufferedReader in 
= new BufferedReader(new InputStreamReader(raw));
            String line 
= null;
            
while ((line = in.readLine()) != null) {
                buffer.append(line);
                buffer.append(
'\n');
            }
            output 
= buffer.toString();
            resp.setContentType(
"text/javascript");
            PrintWriter out 
= resp.getWriter();
            out.println(output);
            out.flush();
        }
    }
}

4、处理基类:
public abstract class Processor {
    
public abstract void handle(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
            IOException;

    
public void setCreators(Map<String, Class<?>> creators) {
        
this.creators = creators;
    }

    
public Map<String, Class<?>> getCreators() {
        
return creators;
    }

    
protected Map<String, Class<?>> creators;
}

5、接口处理类:
public class InterfaceProcessor extends Processor {
    
public void handle(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String pathInfo 
= req.getPathInfo();
        String servletPath 
= req.getServletPath();
        String script 
= pathInfo.replaceFirst("/interface/""");
        script 
= script.replaceFirst(".js""");
        Class
<?> cls = creators.get(script);
        String path 
= req.getContextPath() + servletPath;

        
// 输出接口
        PrintWriter out = resp.getWriter();
        out.println();
        out.println(
"function " + script + "() { }");
        out.println(script 
+ "._path = '" + path + "';");
        Method[] methods 
= cls.getDeclaredMethods();
        
for (int i = 0; i < methods.length; i++) {
            Method method 
= methods[i];
            String methodName 
= method.getName();
            out.print(
'\n');
            out.print(script 
+ '.' + methodName + " = function(");
            Class
<?>[] paramTypes = method.getParameterTypes();
            
for (int j = 0; j < paramTypes.length; j++) {
                out.print(
"p" + j + "");
            }
            out.println(
"callback) {    DWREngine._execute(");
            out.print(script 
+ "._path, '" + script + "', '" + methodName + "\', ");
            
for (int j = 0; j < paramTypes.length; j++) {
                out.print(
"p" + j + "");
            }
            out.println(
"callback);");
            out.println(
'}');
        }
        out.flush();
    }
}

6、调用处理类:
public class ExecProcessor extends Processor {
    
private int varIndex = 0;

    
public void handle(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
            IOException {
        Call call 
= this.getCall(req.getMethod().equals("GET"? parseGet(req) : parsePost(req));
        Method m 
= findMethod(call);
        Object[] params 
= new Object[m.getParameterTypes().length];
        
for (int j = 0; j < m.getParameterTypes().length; j++) {
            Class
<?> paramType = m.getParameterTypes()[j];
            Variable var 
= call.variables.get("c-param" + j);
            
try {
                params[j] 
= ConverterUtil.convertInbound(paramType, var);
            } 
catch (Exception e) {
                
throw new ServletException("参数转换出现异常", e);
            }
        }
        Class
<?> cls = creators.get(call.scriptName);
        
try {
            Object reply 
= m.invoke(cls.newInstance(), params);
            StringBuffer buffer 
= new StringBuffer();
            String code 
= "s" + varIndex++;
            buffer.append(ConverterUtil.convertOutbound(reply, code));
            buffer.append(
'\n');
            buffer.append(
"DWREngine._handleResponse('");
            buffer.append(call.id);
            buffer.append(
"', ");
            buffer.append(code);
            buffer.append(
");\n");
            resp.setContentType(
"text/plain");
            PrintWriter out 
= resp.getWriter();
            out.print(buffer.toString());
            out.flush();
        } 
catch (Exception e) {
            e.printStackTrace();
        }
    }

    
private Method findMethod(Call call) {
        Class
<?> cls = creators.get(call.scriptName);
        
for (Method m : cls.getMethods()) {
            
if (m.getName().equals(call.methodName)
                    
&& m.getParameterTypes().length == call.variables.size()) {
                
return m;
            }
        }
        
return null;
    }

    
private Call getCall(Map paramMap) {
        Call call 
= new Call();
        String prefix 
= "c-";
        call.id 
= (String) paramMap.remove(prefix + "id");
        call.scriptName 
= (String) paramMap.remove(prefix + "scriptName");
        call.methodName 
= (String) paramMap.remove(prefix + "methodName");

        
for (Iterator it = paramMap.entrySet().iterator(); it.hasNext();) {
            Map.Entry entry 
= (Map.Entry) it.next();
            String key 
= (String) entry.getKey();
            
if (key.startsWith(prefix)) {
                String data 
= (String) entry.getValue();
                String[] split 
= data.split(":");
                call.variables.put(key, 
new Variable(key, split[0], split[1]));
                it.remove();
            }
        }
        
return call;
    }

    
private Map parseGet(HttpServletRequest req) throws IOException {
        Map paramMap 
= new HashMap();
        Map reqMap 
= req.getParameterMap();

        
for (Iterator it = reqMap.keySet().iterator(); it.hasNext();) {
            String key 
= (String) it.next();
            String[] array 
= (String[]) reqMap.get(key);
            
if (array.length == 1) {
                paramMap.put(key, array[
0]);
            }
        }
        
return paramMap;
    }

    
private Map parsePost(HttpServletRequest req) throws IOException {
        Map paramMap 
= new HashMap();
        BufferedReader in 
= new BufferedReader(new InputStreamReader(req.getInputStream()));
        String line 
= null;
        
while ((line = in.readLine()) != null) {
            
for (String part : line.split("&")) {
                
int sep = part.indexOf("=");
                String key 
= part.substring(0, sep);
                String value 
= part.substring(sep + 1);
                paramMap.put(key, value);
            }
        }

        
return paramMap;
    }
}

7、类型转换工具类:
package mydwr;

import java.io.IOException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

public class ConverterUtil {
    
private static Map<String, Converter> converterMap = new HashMap<String, Converter>();

    
static {
        Converter stringConv 
= new StringConverter();
        Converter primConv 
= new PrimitiveConverter();
        converterMap.put(
"boolean", primConv);
        converterMap.put(
"byte", primConv);
        converterMap.put(
"int", primConv);
        converterMap.put(
"double", primConv);
        converterMap.put(
"char", primConv);
        converterMap.put(
"number", primConv);
        converterMap.put(
"java.lang.Boolean", primConv);
        converterMap.put(
"java.lang.Byte", primConv);
        converterMap.put(
"java.lang.Integer", primConv);
        converterMap.put(
"java.lang.Double", primConv);
        converterMap.put(
"java.lang.Character", primConv);
        converterMap.put(
"string", stringConv);
        converterMap.put(
"java.lang.String", stringConv);
    }

    
public static Object convertInbound(Class<?> paramType, Variable var) throws Exception {
        Converter conv 
= converterMap.get(var.type);
        
return conv.convertInbound(paramType, var);
    }

    
public static String convertOutbound(Object data, String varName) {
        Converter conv 
= converterMap.get(data.getClass().getName());
        
return conv.convertOutbound(data, varName);
    }

}

interface Converter {

    Object convertInbound(Class
<?> paramType, Variable var) throws Exception;

    String convertOutbound(Object data, String varName);
}

class StringConverter implements Converter {
    JSUtil jsUtil 
= JSUtil.getInstance();

    
public Object convertInbound(Class<?> paramType, Variable var) throws IOException {
        
return URLDecoder.decode(var.value, "UTF-8");
    }

    
public String convertOutbound(Object data, String varName) {
        
return "var " + varName + "=\"" + jsUtil.escapeJavaScript(data.toString()) + "\";";
    }

}

class PrimitiveConverter implements Converter {
    JSUtil jsUtil 
= JSUtil.getInstance();

    
public Object convertInbound(Class<?> paramType, Variable var) throws Exception {
        String value 
= var.value;
        
if (paramType == Boolean.TYPE || paramType == Boolean.class) {
            
return Boolean.valueOf(value.trim());
        }

        
if (paramType == Byte.TYPE || paramType == Byte.class) {
            
if (value.length() == 0) {
                
byte b = 0;
                
return new Byte(b);
            }
            
return new Byte(value.trim());
        }

        
if (paramType == Short.TYPE || paramType == Short.class) {
            
if (value.length() == 0) {
                
short s = 0;
                
return new Short(s);
            }
            
return new Short(value.trim());
        }

        
if (paramType == Character.TYPE || paramType == Character.class) {
            String decode 
= URLDecoder.decode(value.trim(), "UTF-8");
            
if (decode.length() == 1) {
                
return new Character(decode.charAt(0));
            }
        }

        
if (paramType == Integer.TYPE || paramType == Integer.class) {
            
if (value.length() == 0) {
                
return new Integer(0);
            }
            
return new Integer(value.trim());
        }

        
if (paramType == Long.TYPE || paramType == Long.class) {
            
if (value.length() == 0) {
                
return new Long(0);
            }
            
return new Long(value.trim());
        }

        
if (paramType == Float.TYPE || paramType == Float.class) {
            
if (value.length() == 0) {
                
return new Float(0);
            }
            
return new Float(URLDecoder.decode(value.trim(), "UTF-8"));
        }

        
if (paramType == Double.TYPE || paramType == Double.class) {
            
if (value.length() == 0) {
                
return new Double(0);
            }
            
return new Double(URLDecoder.decode(value.trim(), "UTF-8"));
        }
        
throw new Exception("找不到匹配的类型");
    }

    
public String convertOutbound(Object data, String varName) {
        Class
<?> paramType = data.getClass();
        
if (data.equals(Boolean.TRUE)) {
            
return "var " + varName + "=true;";
        } 
else if (data.equals(Boolean.FALSE)) {
            
return "var " + varName + "=false;";
        } 
else if (paramType == Character.class) {
            
return "var " + varName + "=\"" + jsUtil.escapeJavaScript(data.toString()) + "\";";
        } 
else {
            
return "var " + varName + '=' + data.toString() + ';';
        }
    }

}

8、调用实体类:
package mydwr;

import java.util.HashMap;
import java.util.Map;

public class Call {
    String id 
= null;
    String scriptName 
= null;
    String methodName 
= null;
    Map
<String, Variable> variables = new HashMap<String, Variable>();
}

class Variable {
    String key;
    String type;
    String value;

    
public Variable(String key, String type, String value) {
        
this.key = key;
        
this.type = type;
        
this.value = value;
    }

}

9、精简之后的引擎JS:
if (DWREngine == nullvar DWREngine = {};

DWREngine._errorHandler 
= DWREngine.defaultMessageHandler;
DWREngine._batch 
= null;
DWREngine._handlersMap 
= {};
DWREngine._batches 
= [];
DWREngine._method 
= DWREngine.XMLHttpRequest;
DWREngine._verb 
= "POST";
DWREngine._async 
= true;
DWREngine._timeout 
= 0;
DWREngine.XMLHttpRequest 
= 1;
DWREngine._XMLHTTP 
= ["Msxml2.XMLHTTP.6.0""Msxml2.XMLHTTP.5.0""Msxml2.XMLHTTP.4.0""MSXML2.XMLHTTP.3.0""MSXML2.XMLHTTP""Microsoft.XMLHTTP"];

DWREngine.defaultMessageHandler 
= function(message) {
  
if (typeof message == "object" && message.name == "Error" && message.description) {
    alert(
"Error: " + message.description);
  }

  
else {
    
if (message.toString().indexOf("0x80040111"== -1{
      alert(message);
    }

  }

}
;

DWREngine.beginBatch 
= function() {
  
if (DWREngine._batch) {
    DWREngine._errorHandler(
"Batch already started.");
    
return;
  }

  DWREngine._batch 
= {
      map:
{},
    paramCount:
0,
    ids:[]
  }
;
}
;

DWREngine._serializeAll 
= function(batch, referto, data, name) {
  
if (data == null{
    batch.map[name] 
= "null:null";
    
return;
  }


  
switch (typeof data) {
  
case "boolean":
    batch.map[name] 
= "boolean:" + data;
    
break;
  
case "number":
    batch.map[name] 
= "number:" + data;
    
break;
  
case "string":
    batch.map[name] 
= "string:" + encodeURIComponent(data);
    
break;
  
case "object":
    
if (data instanceof String) batch.map[name] = "String:" + encodeURIComponent(data);
    
else if (data instanceof Boolean) batch.map[name] = "Boolean:" + data;
    
else if (data instanceof Number) batch.map[name] = "Number:" + data;
    
else if (data instanceof Date) batch.map[name] = "Date:" + data.getTime();
    
break;
  
case "function":
    
// We just ignore functions.
    break;
  
default:
    batch.map[name] 
= "default:" + data;
    
break;
  }

}
;

DWREngine._execute 
= function(path, scriptName, methodName, vararg_params) {
  
var singleShot = false;
  
if (DWREngine._batch == null{
    DWREngine.beginBatch();
    singleShot 
= true;
  }

  
// To make them easy to manipulate we copy the arguments into an args array
  var args = [];
  
// arguments为内置对象
  for (var i = 0; i < arguments.length - 3; i++{
    args[i] 
= arguments[i + 3];
  }

  
// All the paths MUST be to the same servlet
  if (DWREngine._batch.path == null{
    DWREngine._batch.path 
= path;
  }

  
else {
    
if (DWREngine._batch.path != path) {
      DWREngine._errorHandler(
"Can't batch requests to multiple DWR Servlets.");
      
return;
    }

  }

  
// From the other params, work out which is the function (or object with
  // call meta-data) and which is the call parameters
  var params;
  
var callData;
  
var firstArg = args[0];
  
var lastArg = args[args.length - 1];

  
if (typeof firstArg == "function"{
    callData 
= { callback:args.shift() };
    params 
= args;
  }

  
else if (typeof lastArg == "function"{
    callData 
= { callback:args.pop() };
    params 
= args;
  }

  
else if (lastArg != null && typeof lastArg == "object" && lastArg.callback != null && typeof lastArg.callback == "function"{
    callData 
= args.pop();
    params 
= args;
  }

  
else if (firstArg == null{
    
if (lastArg == null && args.length > 2{
        DWREngine._errorHandler(
"Ambiguous nulls at start and end of parameter list. Which is the callback function?");
    }

    callData 
= { callback:args.shift() };
    params 
= args;
  }

  
else if (lastArg == null{
    callData 
= { callback:args.pop() };
    params 
= args;
  }

  
else {
    DWREngine._errorHandler(
"Missing callback function or metadata object.");
    
return;
  }


  
// Get a unique ID for this call
  var random = Math.floor(Math.random() * 10001);
  
var id = (random + "_" + new Date().getTime()).toString();
  
var prefix = "c" + "-";
  DWREngine._batch.ids.push(id);

  
// Save the callMetaData
  DWREngine._handlersMap[id] = callData;

  DWREngine._batch.map[prefix 
+ "scriptName"= scriptName;
  DWREngine._batch.map[prefix 
+ "methodName"= methodName;
  DWREngine._batch.map[prefix 
+ "id"= id;

  
// Serialize the parameters into batch.map
  for (i = 0; i < params.length; i++{
    DWREngine._serializeAll(DWREngine._batch, [], params[i], prefix 
+ "param" + i);
  }


  
// Now we have finished remembering the call, we incr the call count
  if (singleShot) {
    DWREngine.endBatch();
  }

}
;

DWREngine.endBatch 
= function(options) {
  
var batch = DWREngine._batch;
  
if (batch == null{
    DWREngine._errorHandler(
"No batch in progress.");
    
return;
  }


  
if (batch.method == null) batch.method = DWREngine._method;
  
if (batch.verb == null) batch.verb = DWREngine._verb;
  
if (batch.async == null) batch.async = DWREngine._async;
  
if (batch.timeout == null) batch.timeout = DWREngine._timeout;

  batch.completed 
= false;
  
// We are about to send so this batch should not be globally visible
  DWREngine._batch = null;

  DWREngine._sendData(batch);
  DWREngine._batches[DWREngine._batches.length] 
= batch;
}
;

DWREngine._sendData 
= function(batch) {
  
var urlPostfix = batch.map["c-scriptName"+ "." + batch.map["c-methodName"+ ".dwr";
  
// Get setup for XMLHttpRequest if possible
  if (window.XMLHttpRequest) {
    batch.req 
= new XMLHttpRequest();
  }
else{
    batch.req 
= DWREngine._newActiveXObject(DWREngine._XMLHTTP);
  }

  
var query = "";
  
var prop;

  
// This equates to (batch.method == XHR && browser supports XHR)
  if (batch.req) {
    batch.map.xml 
= "true";
    batch.req.onreadystatechange 
= function() { DWREngine._stateChange(batch); };
    
for (prop in batch.map) {
      
if (typeof batch.map[prop] != "function"{
        query 
+= prop + "=" + batch.map[prop] + "\n";
      }

    }


    
try {
      batch.req.open(
"POST", batch.path + "/exec/" + urlPostfix, batch.async);
      batch.req.setRequestHeader('Content
-Type', 'text/plain');
      batch.req.send(query);
    }

    
catch (ex) {
      DWREngine._errorHandler(ex);
    }

  }


}
;

DWREngine._stateChange 
= function(batch) {
  
if (!batch.completed && batch.req.readyState == 4{
    
try {
      
var reply = batch.req.responseText;
      
if (reply == null || reply == ""{
        DWREngine._errorHandler( 
"No data received from server");
      }

      
else {
          eval(reply);          
      }

    }

    
catch (ex) {
      
if (ex == null) ex = "Unknown error occured";
      DWREngine._errorHandler(ex);
    }

  }

}
;

DWREngine._handleResponse 
= function(id, reply) {
  
// Clear this callback out of the list - we don't need it any more
  var handlers = DWREngine._handlersMap[id];
  DWREngine._handlersMap[id] 
= null;
  
  
if (handlers) {
    
try {
      
if (handlers.callback) handlers.callback(reply);
    }

    
catch (ex) {
      DWREngine._errorHandler(ex);
    }

  }

}
;

DWREngine._newActiveXObject 
= function(axarray) {
  
var returnValue;  
  
for (var i = 0; i < axarray.length; i++{
    
try {
      returnValue 
= new ActiveXObject(axarray[i]);
      
break;
    }

    
catch (ex) /* ignore */ }
  }

  
return returnValue;
}
;

10、点击此处下载源代码

posted on 2009-05-24 18:04 俊星 阅读(870) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航: