dwr学习

来源:互联网 发布:剑三怎么导入捏脸数据 编辑:程序博客网 时间:2024/05/27 09:44
 

1、DWR: Easy AJAX for JAVA

作为一个java open source library,DWR可以帮助开发人员完成应用AJAX技术的web程序。它可以让浏览器上的javascript方法调用运行在web服务器上java方法。

DWR主要由两部门组成。javascript与web服务器通信并更新web页;运行在web服务器的Servlet处理请求并把响应发回浏览器。

DWR采用新颖的方法实现了AJAX(本来也没有确切的定义),在java代码基础上动态的生成javascript代码。web开发者可以直接调 用这些javascript代码,然而真正的代码是运行在web服务器上的java code。出与安全考虑,开发者必须配置哪些java class暴露给DWR.(dwr.xml)

这种从(java到javascript)调用机制给用户一种感觉,好象常规的RPC机制,或RMI or SOAP.但是它运行在web上,不需要任何浏览器插件。

DWR不认为浏览器和web服务器之间协议重要,把系统界面放在首位。最大挑战是java method call的同步特征与ajax异步特性之间的矛盾。在异步模型里,结果只有在方法结束后才有效。DWR解决了这个问题,把回调函数当成参数传给方法,处理 完成后,自动调用回调方法。

这个图表显示了,通过javascript事件,DWR能改变select的内容,当然这些内容由java代码返回。 javascript函数Data.getOptions(populateList)由DWR动态生成,这个函数会调用java class Data类的方法。DWR处理如何远程调用,包括转换所有的参数和返回的结果(javascript/java)。java方法执行完后,执行回调方法 populateList。在整个过程中我们就想在用本地的方法一样。

2、Getting Started

废话少说,试试就ok了。
web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app id="dwr">
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
</web-app>

dwr.xml 与web.xml同目录
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd">
<dwr>
<allow>
<create creator="new" javascript="JDate">
<param name="class" value="java.util.Date"/>
</create>
</allow>
</dwr>

index.html
<html>
<head>
<title>DWR - Test Home</title>
<script type='text/javascript' src='dwr/interface/JDate.js'></script>
<script type='text/javascript' src='dwr/engine.js'></script>
<script>
function init(){
JDate.getYear(load);
}
function load(data){
alert(data+1900+'年')
}
</script>
</head>
<body onload="init()">
</body>
</html>

dwr.jar 下载放lib下

完了,什么,够了,就这些。访问ok!
3、Examples
http://www.aboutmyhealth.org/ 这不是Google Suggest吗!ok.
4、源码浅析
dwr的设计很象webwork2的设计,隐藏http协议,扩展性,兼容性及强。

通过研究uk.ltd.getahead.dwr.DWRServlet这个servlet来研究下dwr到底是如何工作滴。

代码
  1. web.xml配置  
  2. <servlet>  
  3.     <servlet-name>dwr-invoker</servlet-name>  
  4.     <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>  
  5.   </servlet>  
  6.   <servlet-mapping>  
  7.     <servlet-name>dwr-invoker</servlet-name>  
  8.     <url-pattern>/dwr/*</url-pattern>  
  9. </servlet-mapping>  

这样所有的/dwr/*所有请求都由这个servlet来处理,它到底处理了些什么能。我们还以上面最简单的例子来看。
1、web服务器启动,DWRServlet init()方法调用,init主要做了以下工作。
设置日志级别、实例化DWR用到的单例类(这些类在jvm中只有一个实例对象)、读去配置文件(包括dwr.jar包中的dwr.xml,WEB-INF/dwr.xml. config*.xml)。
2、请求处理
DWRServlet.doGet, doPost方法都调用processor.handle(req, resp)方法处理。Processor对象在init()方法中已经初始化了。
代码
  1. public void handle(HttpServletRequest req, HttpServletResponse resp)  
  2.         throws IOException  
  3.     {  
  4.         String pathinfo = req.getPathInfo();  
  5.         if(pathinfo == null || pathinfo.length() == 0 || pathinfo.equals("/"))  
  6.         {  
  7.             resp.sendRedirect(req.getContextPath() + req.getServletPath() + '/' + "index.html");  
  8.         } else  
  9.         if(pathinfo != null && pathinfo.equalsIgnoreCase("/index.html"))  
  10.         {  
  11.             doIndex(req, resp);  
  12.         } else  
  13.         if(pathinfo != null && pathinfo.startsWith("/test/"))  
  14.         {  
  15.             doTest(req, resp);  
  16.         } else  
  17.         if(pathinfo != null && pathinfo.equalsIgnoreCase("/engine.js"))  
  18.         {  
  19.             doFile(resp, "engine.js""text/javascript");  
  20.         } else  
  21.         if(pathinfo != null && pathinfo.equalsIgnoreCase("/util.js"))  
  22.         {  
  23.             doFile(resp, "util.js""text/javascript");  
  24.         } else  
  25.         if(pathinfo != null && pathinfo.equalsIgnoreCase("/deprecated.js"))  
  26.         {  
  27.             doFile(resp, "deprecated.js""text/javascript");  
  28.         } else  
  29.         if(pathinfo != null && pathinfo.startsWith("/interface/"))  
  30.         {  
  31.             doInterface(req, resp);  
  32.         } else  
  33.         if(pathinfo != null && pathinfo.startsWith("/exec"))  
  34.         {  
  35.             doExec(req, resp);  
  36.         } else  
  37.         {  
  38.             log.warn("Page not found. In debug/test mode try viewing /[WEB-APP]/dwr/");  
  39.             resp.sendError(404);  
  40.         }  
  41.     }  

哦。这些恍然大悟。dwr/*处理的请求也就这几种。
(1)dwr/index.html,dwr/test/这种只能在debug模式下使用,调试用。
dwr/engine.js,dwr/util.js,dwr/deprecated.js当这个请求到达,从dwr.jar包中读取文件流,响应回去。(重复请求有缓存)
(2)当dwr/interface/这种请求到来,(例如我们在index.html中的 <script type='text/javascript' src='dwr/interface/JDate.js'></script>)DWR做一件伟大的事。把我们在WEB- INF/dwr.xml中的
<create creator="new" javascript="JDate">
<param name="class" value="java.util.Date"/>
</create>
java.util.Date转化为javascript函数。
http://localhost:port/simpledwr/dwr/interface/JDate.js看看吧。
细节也比较简单,通过java反射,把方法都写成javascript特定的方法。(我觉得这些转换可以放到缓存里,下次调用没必要再生成一遍,不知道作者为什么没这样做)。
(3)dwr/exec
javascript调用方法时发送这种请求,可能是XMLHttpRequest或IFrame发送。
当然,javascript调用的方法签名与java代码一致,包括参数,还有javascript的回调方法也传到了服务器端,在服务器端很容 易实现。回调方法的java的执行结果 返回类似 <script>callMethod(结果)<script>的javascript字符串,在浏览器执行。哈,一切就这么简 单,巧妙。

dwr的设计构思很是巧妙。
第一、把java类转化为javascript类由dwr自动完成,只需简单的配置。
第二、应用起来极其简单。开发者不要该服务器代码就可以集成。
第三、容易测试。和webwork一样,隐藏的http协议。
第四、及强扩展性。例如与spring集成,只需修改一点代码。
第五、性能。就我与jason,等简单比较,dwr性能可能是最好的。
第六、自动把java对象转化为javascript对象,并且及易扩展。[/code]


 

1、最小配置

代码
  1. <servlet>  
  2.   <servlet-name>dwr-invoker</servlet-name>  
  3.   <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>  
  4. </servlet>  
  5. <servlet-mapping>  
  6.   <servlet-name>dwr-invoker</servlet-name>  
  7.   <url-pattern>/dwr/*</url-pattern>  
  8. </servlet-mapping>  

2、当我们想看DWR自动生成的测试页(Using debug/test mode)时,可在
代码
  1. servlet中加  
  2. <init-param>  
  3.   <param-name>debug</param-name>  
  4.   <param-value>true</param-value>  
  5. </init-param>  
这 个参数DWR默认是false.如果选择true.我们可以通过url http://localhost:port/app/dwr ,你就可以看到你部署的每个DWR class。并且可以测试java代码的每个方法是否运行正常。为了安全考虑,在正式环境下你一定把这个参数设为false.
3、logging信息配置。
在无java.util.logging的jdk1.3下运行DWR,我们不希望强制用户加一个logging包,而是用 HttpServlet.log()方法来输出日志。如果classpath中包括logging jar包,DWR自动切换用logging输出日志。
如果用HttpServlet.log()方法,以下配置是有效的。
代码
  1. <init-param>  
  2.  <param-name>logLevel</param-name>  
  3.  <param-value>DEBUG</param-value>  
  4. </init-param>  
有效的值是 FATAL, ERROR, WARN (the default), INFO and DEBUG

我是喜欢用log4j输出日志,那么在log4j.properties下加,log4j.logger.uk.ltd.getahead.dwr = debug。这样可以看DWR的调试日志。
4、多dwr.xml文件的配置
可能有几种情况,我们一一列举。 一个servlet,多个dwr.xml配置文件;多个servlet,每个servlet对应一个或多个dwr.xml.
一个servlet,多个dwr.xml配置文件;

代码
  1. <servlet>  
  2.     <servlet-name>dwr-invoker</servlet-name>  
  3.     <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>   
  4.     <init-param>  
  5.       <param-name>config-1</param-name>  
  6.       <param-value>WEB-INF/dwr1.xml</param-value>  
  7.     </init-param>  
  8.     <init-param>  
  9.       <param-name>config-2</param-name>  
  10.       <param-value>WEB-INF/dwr2.xml</param-value>  
  11.     </init-param>  
  12. </servlet>  
在 这种配置下,param-name的值必须以config开头。param-name可以有>=0个。如果没有param-name,那么将会读取 WEB-INF/dwr.xml。如果有大于零个param-name,那么WEB-INF/dwr.xml文件将不会被读取。

多个servlet,每个servlet对应一个或多个dwr.xml

代码
  1. <servlet>  
  2.    <servlet-name>dwr-invoker</servlet-name>  
  3.     <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>   
  4. <!--用classes/dwr.xml-->  
  5. </servlet>  
  6. <servlet>  
  7.    <servlet-name>dwr-invoker1</servlet-name>  
  8.    <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>   
  9.    <init-param>  
  10.      <param-name>config-admin</param-name>  
  11.      <param-value>WEB-INF/dwr1.xml</param-value>  
  12.    </init-param>  
  13.    <init-param>  
  14.      <param-name>debug</param-name>  
  15.      <param-value>true</param-value>  
  16.    </init-param>  
  17. </servlet>  
  18. <servlet-mapping>  
  19.    <servlet-name>dwr-invoker</servlet-name>  
  20.    <url-pattern>/dwr/*</url-pattern>  
  21. </servlet-mapping>  
  22. <servlet-mapping>  
  23.    <servlet-name>dwr-invoker1</servlet-name>  
  24.    <url-pattern>/dwr1/*</url-pattern>  
  25. </servlet-mapping>  
在这种情况下,我们可以根据J2EE security来控制权限,针对不同url,加不同的角色。
5、dwr的几个扩展点(Plug-ins)
DWR对以下接口提供的默认的实现,用户可以继承DWR的默认实现类来达到我们想要的效果。但这至少需要我们读了DWR源码才能做这些工作(dwr源码很是清晰,有兴趣可以学习一下),以后可能补存这部分。
代码
  1. uk.ltd.getahead.dwr.AccessControl      
  2. uk.ltd.getahead.dwr.Configuration   
  3. uk.ltd.getahead.dwr.ConverterManager   
  4. uk.ltd.getahead.dwr.CreatorManager   
  5. uk.ltd.getahead.dwr.Processor   
  6. uk.ltd.getahead.dwr.ExecutionContext


需求很简单,就是用js向后端请求,然后把请求的结果弄进一个select里面。一开始是用xmlrequest去请求后端一个groovy的url,得 到一个xml,然后把xml的内容填进select里面去。做完老瞅着不顺眼,正好在看ajax的资料,拿dwr改造一下。

js是我一直很头疼的事了,尤其是对dom的操作上面,dwr感觉就是在直接调java接口,操作java对象,省事省心啊。

用dwr,先得在web.xml中配一下。

 1    <servlet>
 2        <servlet-name>dwr-invoker</servlet-name>
 3        <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
 4        <init-param>
 5            <param-name>debug</param-name>
 6            <param-value>true</param-value>
 7        </init-param>
 8    </servlet>
 9    <servlet-mapping>
10        <servlet-name>dwr-invoker</servlet-name>
11        <url-pattern>/dwr/*</url-pattern>
12    </servlet-mapping>
13

然后就是配dwr.xml文件了。
dwr和spring贴得比较紧,不用折腾,直接让dwr去调spring中定义的bean了。
 1<?xml version="1.0" encoding="UTF-8"?>
 2<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd" >
 3<dwr>
 4    <allow>
 5        <create javascript="ServerManager" creator="spring">
 6            <param name="beanName">ServerManager</param>
 7        </create>
 8    </allow>
 9</dwr>
10
我的project中,已经在web.xml中配了spring的listener,直接写beanName就行。

在ServerManager接口中定义了如下方法
  List<Server> loadAll(User manager, ServerStatus status, String order);
因此,在dwr中定义了三个convert(一开始没配,结果怎么调都不成功)。

1        <convert converter="bean" match="com.yninfo.sa.domain.Server" />
2        <convert converter="bean" match="com.yninfo.sa.domain.ServerStatus" />
3        <convert converter="bean" match="com.yninfo.sa.domain.User" />


loadAll方法中的manager参数,是用户登录成功后,session.setAttribute("user",user)存放的。在html里面,用js是无法读到的,因此,自己定义了一个java bean。
1public class Remote {
2  public User getUser(HttpSession session) {
3    return (User) session.getAttribute("user");
4  }

5}

6

同样的,在dwr中配了一下
1        <create javascript="Remote" creator="new">
2            <param name="class" value="com.yninfo.sa.web.ajax.Remote" />
3        </create>


所有配置完成后,js代码如下:
 1<script type='text/javascript' src='dwr/interface/Remote.js'></script>
 2<script type='text/javascript' src='dwr/interface/ServerManager.js'></script>
 3<script type='text/javascript' src='dwr/engine.js'></script>
 4<script type='text/javascript' src='dwr/util.js'></script>
 5<script>
 6    function init(){
 7        Remote.getUser(
 8            function(user){
 9                ServerManager.loadAll(user,null,null,load);
10            }
);
11    }

12    function load(data){
13        for (var i=0; i<data.length; i++{
14          document.DailyRecordAdd.elements["model.serverId"].options[i]=
15            new Option(data[i].name,data[i].id);
16        }

17    }

18    window.onload = function (){
19        init();
20    }

21</script>


最终的配置文件:
 1<?xml version="1.0" encoding="UTF-8"?>
 2<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd" >
 3<dwr>
 4    <allow>
 5        <create javascript="ServerManager" creator="spring">
 6            <param name="beanName">ServerManager</param>
 7            <include method="add" />
 8            <include method="findByPrimaryKey" />
 9            <include method="loadAll" />
10        </create>
11        <create javascript="Remote" creator="new">
12            <param name="class" value="com.yninfo.sa.web.ajax.Remote" />
13        </create>
14        <convert converter="bean" match="com.yninfo.sa.domain.User" />
15        <convert converter="bean" match="com.yninfo.sa.domain.Server" />
16        <convert converter="bean" match="com.yninfo.sa.domain.ServerStatus" />
17    </allow>
18</dwr>
19
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 微信支付打款认证超时怎么办 微信上买东西钱付款了货没发怎么办 掌上道聚城王者轮回分解错了怎么办 鞋子脱胶了怎么办别傻傻用胶水粘 斗鱼主播积分太低无法收礼物怎么办 信誉积分没有了什么也玩不了怎么办 忘记自己电信卡号的密码怎么办 淘宝卖出去东西的钱被冻结了怎么办 手机店铺搞抽奖活动上当了怎么办 网易云音乐上传作品编辑失败怎么办 手机连了wifi后自动扣费怎么办 店铺被低价拍了一部分商品该怎么办 淘宝买家退货快递单号填错了怎么办 卖家同意退款了买家不退货怎么办 淘宝代购衣服有破损不给退怎么办 网上购飞机票身份证号写错了怎么办 交易猫买家把我号清了怎么办 光大普卡额度4万封顶了怎么办 天天特价通过后价格设置错误怎么办 苏宁易购不小心点了免密支付怎么办 别人知道自己京东的账号密码怎么办 oppo手机刷机要锁屏密码怎么办 在苏宁易购退款成功又收到货怎么办 今日头条转发出现未安装微信怎么办 打开手机后自动弹出广告怎么办去除 朋友圈发广告被腾讯屏蔽了怎么办 新商盟手机订烟登录密码忘了怎么办 手机版战神斯巴达幽灵经常崩怎么办 代购买的东西被海关扣了怎么办 托朋友代购给了钱联系不上人怎么办 签了合同被加盟商骗了怎么办 百度云盘下载时本地空间不足怎么办 百度云盘隐私空间没密码忘了怎么办 华为云空间的帐号密码忘记了怎么办 快递被快递公司弄丢了怎么办 快递到了人不在那个地方了怎么办 微信被骗了1千多怎么办 客户货已经用啦要求退款退货怎么办 网购收到别人退货的东西怎么办 好省输入订单编号查不到订单怎么办 快递没有当面验收后发现损坏怎么办