目前Ajax的开发框架有很多,使用这些框架可以简化Ajax的开发。DWR (Direct Web Remoting)是一个用于改善Web页面与Java类交互的远程服务器端Ajax开源框架。DWR可以动态生成基于Java类的JavaScript代码。对于公开的每个类,DWR帮我们做好了创建对象、发送数据、接受响应等许多繁琐的工作,大大节省了客户端代码和工作量。
示例应用程序:用户注册
本文使用的示例应用程序是一个简单的用户注册过程。借助简化了的数据模型,主要介绍DWR和Spring MVC的结合。我们先来研究一下DWR如何启用程序的Ajax功能。
配置DWR
首先,需要下载dwr.jar文件,把它放在web程序的WEB-INF/lib目录下面。清单 1 显示了要公开给Ajax的Java方法。
清单 1. 需要公开的userManager类的两个方法
以下是引用片段: public int findExistedUser(String name) public List<User> showUsers() |
接下来需要配置DWR,告诉它Ajax应当如何构建userManager并调用这些方法。在清单 2 所示的dwr.xml文件中进行配置。
清单 2. 配置 DWR,公开需要远程调用的方法
以下是引用片段: <?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=”spring” javascript=”userManager” scope=”application”> <param name=”beanName” value=”userManager”/> <include method=”findExistedUser”/> <include method=”showAllUsers”/> </create> <convert converter=”bean” match=”com.ibm.osl.entity.User”> <param name=”include” value=”name”/> </convert> </allow> </dwr> |
creator属性用来指定使用哪种创造器。如果creator属性被设置为值new,意味着DWR调用类的默认构造函数来获得实例。这里通过与Spring进行集成来获得实例,creator=”spring”提供了一个Spring的创造器,允许直接调用Spring容器中的bean,然后DWR将bean转换成一个 javascript对象。SpringCreator 这个创造器会查找Spring所配置的bean,并创建它们。Javascript属性用于指定浏览器中被创造出来的对象的名字。scope属性指定这个bean的生命周期。嵌套在create元素内的 param 元素的name属性值可以是class,beanName等。此处用 beanName,value 的值 userManager 是在beans.xml中定义的某个id值。include元素指定公开的方法名称。也可以用exclude元素指定不想被被访问的方法。
convert元素的作用是告诉 DWR 在服务器端的 Java 对象表示和 JavaScript 之间如何转换数据类型。
DWR能自动地在Java对象和JavaScript表示之间转换简单数据类型。这些类型包括Java原生类型和它们各自的类表示,还有数组和集合类型。这里convert元素告诉DWR用bean转换器处理showAllUsers方法返回的List<User>对象,并指定序列化中只包含User类的name属性。
接下来在清单 3 中定义需要的bean 。
清单 3. 配置beans.xml
以下是引用片段: <beans> <bean id=”userManager” class=”developworks.dwrspring.service.impl.UserManagerImpl”/> </beans> |
有三种方式寻找配置文件beans.xml,最简单的方式是使用org.springframework.web.context.ContextLoaderListener。需要在web.xml中做如下配置:
清单 4. 使用ContextLoaderListener寻找配置文件beans.xml
以下是引用片段: <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/beans.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> |
测试部署
如果在web.xml中把init-param的debug属性设置为true,就会启用DWR的测试模式,如清单 5 所示。访问/[web-app]/dwr/就可以看到服务器暴露出来的所有类列表。
清单 5. 将web.xml的debug属性设置为true
以下是引用片段: <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param> |
清单 6. 服务器端暴露出来的所有类列表
以下是引用片段: Classes known to DWR: * userManager (developworks.dwrspring.service.impl.UserManagerImpl) |
点击进入userManager可以看到该类暴露出的所有方法,并可以进行测试。这里有两个用户自己定义的方法,可以在可访问的方法旁边的文本框中输入参数值并点击Execute按钮调用方法。服务器的响应如果是简单值,会在方法旁边直接显示。其他的输出将在警告框中用JSON标注显示出来。这样,测试页面不仅可以检查公开了哪个类和方法用于远程调用,还可以测试每个方法是否正常工作。下面让我们看下本例中的两个方法:
函数findExistedUser(“”)可以查找是否存在该用户。若不输入参数,点击Execute按钮,显示0。在函数参数中输入已存在的id,如 “tom@cn.ibm.com”,点击Execute按钮,显示 1。
函数showAllUsers()可以显示所有的用户名。点击Execute按钮,会弹出一个显示所有user信息的警告框,内容如清单 7。
清单 7. 点击Execute按钮返回的JSON对象
以下是引用片段: [ {name:”tom@cn.ibm.com”}, {name:”mike@cn.ibm.com”} ] |
调用远程对象
对于公开的每个类,DWR动态地生成包含在Web页面中的JavaScript。生成的JavaScript 包含存根函数,代表Java类对应的方法。Java方法与对应的JavaScript函数之间的映射规则为JavaScriptName.methodName(methodParams …, callBack),其中JavaScriptName是creator属性指定浏览器中被创造出来的对象名字,methodName是Java的方法名,methodParams代表Java方法的参数,最后的callBack是Java方法返回后要回调的JavaScript函数。清单 8 是在jsp页面中使用DWR创建的javascript对象调用公开的方法。
清单 8. 用javascript对象调用公开的方法
以下是引用片段: function callBackfindExistedUser(data){ var userExistedMessage = $(“userExistedMessage”); if (data == 1) userExistedMessage.style.display = “block”; else userExistedMessage.style.display = “none”; } function findExistedUser(){ var name = DWRUtil.getValue(“name”); if (name != “”) userManager.findExistedUser(name,callBackfindExistedUser); } |
在jsp页面使用DWR,需要添加清单 9 的代码。
清单 9. 在jsp页面使用DWR要包含的文件
以下是引用片段: <script type=’text/javascript’ src=’dwr/interface/userManager.js’></script> <script type=’text/javascript’ src=’dwr/engine.js’></script> <script type=’text/javascript’ src=’dwr/util.js’></script> |
DWR会自动根据UserManager类帮我们生成了userManager.js 文件。engine.js是用来转换动态生成接口的javascript函数调用,util.js包含了一些工具函数,让页面对javascript的调用更加方便。
Spring MVC简介
Spring框架提供了构建Web应用程序的MVC模块。Spring MVC内建了一个请求驱动的web mvc框架,以一个DispatcherServlet分发器为中心,将web请求分发到各个不同的处理器进行处理。Spring MVC分离了控制器、模型对象、分派器以及处理程序对象的角色。
配置Spring MVC
需要下载spring.jar和spring-webmvc.jar包,将它放 web程序的WEB-INF/lib目录下面。
本例中使用控制器AbstractWizardFormController,它的主要功能是允许多个表单共用一个表单对象,通常一些表单填的内容比较多,表单会很长,可以将表单分成几页,让用户一页页去完成。表单对象的属性与多个页面所有需填写的对象绑定。AbstractWizardFormController类的 processFinish方法定义的是全部表单完成后提交的处理。所有的表单内容都收集在command对象中,通过ModelAndView的构造方法把它放在model对象中,并在 view 页面上显示出来。
清单 10. processFinish方法将表单内容传输给view页面
以下是引用片段: protected ModelAndView processFinish(HttpServletRequest request, HttpServletResponse response, Object command, BindException exception) throws Exception { RegisterForm registerForm = (RegisterForm) command; return new ModelAndView(this.getSuccessView(), “registerForm”, registerForm); } |
清单 11 在mvc-config.xml中对controller进行配置。
清单 11. 对controller进行配置
以下是引用片段: <bean id=”registerController” class=” developworks.dwrspring.action.RegisterController”> <property name=”commandClass” value=”developworks.dwrspring.vo.RegisterForm”> </property> <property name=”userManager” ref=”userManager”></property> <property name=”successView” value=”account/success”/> <property name=”pages”> <list> <value>account/register1</value> <value>account/register2</value> </list> </property> </bean> |
这里commandClass用来绑定form的bean class。list元素定义的两个value值分别表示表单的第一个页面和第二个页面。successView属性表示表单提交后要转到的页面。
第一个页面中的表单内容如下:
清单 12. 第一个表单页面
以下是引用片段: <form:form action=”register.action” method=”post”> <form:input path=”name” onblur=”javascript:findExistedUser()”/> <form:input path=”age”/> <input type=”submit” value=”Next” name=”_target1″ /> </form:form> path 中的属性name对应的是表单对象RegisterForm的name属性。Javascript方法findExistedUser会调用DWR产生的javascript对象的findExistedUser方法来判断是否存在该用户。 target1的数字 1 表示在xml文件中 <list> 的顺序。这里_target1对应的是account/register2页面。即提交后转到第二个表单页面继续填写。 第二个页面中的表单内容如下: 清单 13. 第二个表单页面 <form:form action=”register.action” method=”post”> <form:select path=”location”> <form:option value=”” label=”—“/> <form:options items=”${location}”/> </form:select> <input class=”button” type=”submit” value=”Back” name=”_target0″/> <input class=”button” type=”submit” value=”Submit” name=”_finish” /> </form:form> |
_target0对应的是account/register1页面。即回到前一个表单页面。
_finish会执行controller的processFinish 法。
path中的属性location所含的数据来自于controller的referenceData函数为表单页面准备的数据。
清单 14. 为页面的select框准备数据
以下是引用片段: protected Map<String,Object> referenceData(HttpServletRequest request, int page) throws Exception { refData = new HashMap<String,Object>(); if (page == 1){ Map<String,Object> location = new HashMap<String,Object>(); location.put(“0”, “Beijing”); location.put(“1”, “Shanghai”); refData.put(“location”, location); } return refData; } |
referenceData函数为第二个页面register2.jsp的select框的location下拉框添加选项。
最后在success页面通过 <c:out value=”${registerForm.name}” /> 等jstl标签显示先前表单输入的值。用户还可以通过点击按钮showAllUsers来显示当前所有用户。因为在convert属性中只配置了name属性,所以用户只能看到所有的用户名。若输出age属性,显示 undefined。
清单 15. 在页面中显示所有的用户名
以下是引用片段: function showAllUser(){ userManager.showUsers(callBackAllUser); } function callBackAllUser(data){ var result = “”; for (var i = 0; i < data.length; i++){ result += data[i].name + “, “; } DWRUtil.setValue(“demoAllUser”,result); } |
使用DWR标注
DWR从 2.0版本开始支持标注,需要在JDK1.5以上使用。使用标注可以省掉dwr.xml,把这个文件的配置信息都移植到程序代码中。下面看一下配置过程。首先,需要在web.xml中配置,把使用 DWR 注释的类都要加在这里。
清单 16. 对web.xml进行配置
以下是引用片段: <init-param> <param-name>classes</param-name> <param-value> com.ibm.osl.service.impl.UserManagerImpl, com.ibm.osl.entity.User, </param-value> </init-param> |
接下来对要远程调用的方法进行标注。
清单 17. 配置要远程调用的方法
以下是引用片段: @RemoteProxy(name=”userManager”,creator=SpringCreator.class, creatorParams={@Param(name=”beanName”,value=”userManager”),}) public class UserManagerImpl implements UserManager { @RemoteMethod public int findExistedUser(String name){ return accountDAO.findExistedUser(String name); } @RemoteMethod public List<User> showUsers(){ return accountDAO.showUsers(); } } |
@RemoteProxy标注要远程调用的类,也就是告诉DWR,这个class是要暴露出来的。相当于dwr.xml中的<creator>标签。RemoteProxy的name指定暴露出来的DWR接口的名字,creator指定使用哪种创造器,本例中使用SpringCreator。creatorParams指定创造器的其他参数。
@RemoteMethod标注要远程调用的方法。只有加了@RemoteMethod标注的方法才会被暴露。
接下来对bean的转换进行配置。
清单 18. 配置要转换的bean
以下是引用片段: @DataTransferObject(converter=BeanConverter.class) public class User { private String name; private Integer age; public String getName() { return name; } @RemoteProperty public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } } |
@DataTransferObject标注在客户端和服务器之间转换类。相当于dwr.xml中的<convert>标签。@RemoteProperty标注在类中需要转换的属性。这里只对name进行标注。进行以上配置后,就可以达到和使用dwr的xml配置文件一样的效果了。
DWR的安全性
在使用DWR时要明确哪些类和方法是可以被远程调用的。dwr.xml要求为每一个远程类定义一个create项。还可以通过指定include和exclude元素控制远程调用Bean中可以被调用的方法,而不是把所有的方法都暴露给服务器端。除此之外,如果要 DWR 在转换JavaBean到Javascript时有一定限制,可以控制哪些bean的属性可以被转换。特别地,在做删除和更新操作时,可以通过WebContext得到session来判断用户是否有权限进行该操作。另外,不要在生产环境中打开debug属性。
结束语
DWR为在客户端使用服务器端的对象和方法提供了一条捷径,并且DWR还提供了一个Spring的创建器,允许直接调用Spring容器中的bean,将bean转换成一个javascript对象。通过本文,您了解了如何结合使用DWR和Spring MVC。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
作者
相关推荐
-
八个超实用的jQuery技巧攻略
jQuery是JavaScript最好的库之一,主要用于制作动画、事件处理,支持Ajax及HTML脚本客户端。文中分享了8个超实用的jQuery代码技巧攻略,希望你会喜欢。
-
HTML5强大功能背后的安全陷阱
尽管HTML5使网站的功能更为强大,但开发人员需充分利用其新的技术特征来提高网站的安全性,使用不当会带安全问题,你知道吗?
-
前端页面开发之Node.js初学者指南
Node.js是刚刚兴起的一个概念,你对它的了解有多少?Node.js的意义是什么,它是怎么发展起来的?Node.js的作用是怎样的呢?
-
分析Java语言的复杂数据类型
除了简单数据类型之外,Java语言中还定义了三种索引数据类型,你知道它们是什么吗?如何初始化过程、默认初值和针对复杂数据类型操作的呢?