Dwr 通過用戶配置文件 dwr.xml 將 java 類映射成一個 javascript 對象,從實現手法上看與 java 里的數據映射很相似。而 dwr 是將 JAVA 的對象映射到了 js 里,由客戶端的 JS 提供給用戶各類實現,而 java 代碼完全在后臺運行。
DWR 函數調用里涉及到的 JS 代碼: engine.js
DWR 函數調用里涉及到的類有: AbstractDWRServlet 、 DefaultProcessor
用戶在提交 request 以后的操作步驟請參見我 blog 里的:《 dwr 源碼學習(一)》, JAVA 代碼生成的映射 JS 代碼其實只是一個 javascript 接口,它調用了 DWREngine._execute 這個函數,而這個函數大體只是執行了一些解析的工作,在它結尾處調用了 DWREngine.endBatch() ,然后又執行了 DWREngine._sendData(batch) ,這時我們會發現有這樣一句: “ batch.req.open("GET", batch.path + "/exec/" + statsInfo + "?" + query, batch.async); ”很熟悉吧。
下一步就到了真正的實現 js 調用 java 代碼里方法的時候了,興奮吧。其實實現也是很簡單的。通過 servlet 這里實現了對各類型 request 參數的不同的匹配,還是看 AbstractDWRServlet .getPost() 這個方法:
1 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException
2 {
3 try
4 {
5 builder.set(req, resp, getServletConfig(), getServletContext(), container);
6 ServletLoggingOutput.setExecutionContext(this);
7
8 processor.handle(req, resp);
9 }
10 finally
11 {
12 builder.unset();
13 ServletLoggingOutput.unsetExecutionContext();
14 }
15 }
16 注意processor.handle(req, resp);
17 public void handle(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException
18 {
19 String pathInfo = req.getPathInfo();
20 String servletPath = req.getServletPath();
21
22 if (nullPathInfoWorkaround && pathInfo == null)
23 {
24 pathInfo = req.getServletPath();
25 servletPath = HtmlConstants.PATH_ROOT;
26 log.debug("Default servlet suspected. pathInfo=" + pathInfo + "; contextPath=" + req.getContextPath() + "; servletPath=" + servletPath); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
27 }
28
29 if (pathInfo == null ||
30 pathInfo.length() == 0 ||
31 pathInfo.equals(HtmlConstants.PATH_ROOT))
32 {
33 resp.sendRedirect(req.getContextPath() + servletPath + HtmlConstants.FILE_INDEX);
34 }
35 else if (pathInfo.startsWith(HtmlConstants.FILE_INDEX))
36 {
37 index.handle(req, resp);
38 }
39 else if (pathInfo.startsWith(HtmlConstants.PATH_TEST))
40 {
41 test.handle(req, resp);
42 }
43 else if (pathInfo.startsWith(HtmlConstants.PATH_INTERFACE))
44 {
45 iface.handle(req, resp);
46 }
47 else if (pathInfo.startsWith(HtmlConstants.PATH_EXEC))
48 {
49 exec.handle(req, resp);
50 }
51 else if (pathInfo.equalsIgnoreCase(HtmlConstants.FILE_ENGINE))
52 {
53 file.doFile(req, resp, HtmlConstants.FILE_ENGINE, HtmlConstants.MIME_JS);
54 }
55 else if (pathInfo.equalsIgnoreCase(HtmlConstants.FILE_UTIL))
56 {
57 file.doFile(req, resp, HtmlConstants.FILE_UTIL, HtmlConstants.MIME_JS);
58 }
59 else if (pathInfo.equalsIgnoreCase(HtmlConstants.FILE_DEPRECATED))
60 {
61 file.doFile(req, resp, HtmlConstants.FILE_DEPRECATED, HtmlConstants.MIME_JS);
62 }
63 else
64 {
65 log.warn("Page not found (" + pathInfo + "). In debug/test mode try viewing /[WEB-APP]/dwr/"); //$NON-NLS-1$ //$NON-NLS-2$
66 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
67 }
68 }
69
也就只有這幾種類型的請求,還記得 DWREngine._sendData 嗎?里面有這么一句:“ batch.req.open("GET", batch.path + "/exec/" + statsInfo + "?" + query, batch.async); ”看到他的請求路徑是 exec ,對應在 processor.handle(req, resp); 這個方法里就是 exec ,在剛才的 JAVA 代碼里我們已經看到過了是括號內的代碼( else if (pathInfo.startsWith(HtmlConstants. PATH_EXEC )) ),而 exec 早已在 servlet 初始化的時候就已經設置為 DefaultExecProcessor ,它的函數 hadle() 就是具體對 js 調用 java 類方法的實現了。
DWR 是一個小型的 AJAX 框架,它的實現思路簡單,其實有很多人在開發中一定也有過類似的想法。它之所以現在才出現我想大概還是要歸功于異步 javascript 消息發送這樣的技術成為現實。所以我又想 AJAX ,從技術上說只能是 javascript 有了一個飛躍性的進步,而 AJAX 的最終成功卻要靠軟件工程。