俊星的BLOG

          我的DWR之簡單實現(xiàn)

          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、調(diào)用處理類:
          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("參數(shù)轉(zhuǎn)換出現(xiàn)異常", 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、類型轉(zhuǎn)換工具類:
          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、調(diào)用實體類:
          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為內(nèi)置對象
            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 俊星 閱讀(885) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導航:
           
          主站蜘蛛池模板: 偏关县| 绥中县| 楚雄市| 文水县| 台南市| 遂平县| 宁远县| 临江市| 商南县| 宣化县| 潜山县| 道真| 龙口市| 株洲市| 梁河县| 曲麻莱县| 手游| 海城市| 商都县| 和顺县| 论坛| 昌吉市| 彭山县| 江永县| 抚远县| 区。| 沂水县| 正镶白旗| 息烽县| 临汾市| 南乐县| 前郭尔| 蒙自县| 鹤岗市| 新源县| 扬州市| 万州区| 临潭县| 长春市| 苏尼特右旗| 二连浩特市|