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 == null) var 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、点击此处
下载源代码