赞
踩
DWR是Direct Web Remoting的简写,它是一套RPC库,使服务器端的Java和浏览器端的Javascript能够方便地互相调用。官网地址:http://directwebremoting.org/dwr/index.html
DWR能够生成Javascript,使浏览器能够像调用本地API一样调用服务器端的Java API。它能够序列化任何数据类型,如Collections, POJOs, XML和二进制数据,例如图像和PDF文件。
使用Reverse AJAX, DWR能够让Java调用客户端API来更新任意页面。DWR支持Comet,Polling和Piggyback三种方式来推送内容到浏览器。
下图展示了DWR如何基于javascript事件更新页面的下拉列表
下图展示利用Reverse Ajax,服务器端能够监控不同客户端在打开哪些页面,将手工或者使用Java API生成的javascript发送给它们。
官网上能够下载用于演示的war包,里面有一些常见的功能演示。本文仅从学习的角度,自己从头搭建使用DWR动态更新Table的环境,完成后页面如图
环境介绍
windows 7,使用XAMPP中的Tomcat服务器,开发环境是eclipse
1).使用eclipse建立一个Dynamic Web Project。
2).下载相关jar包,包括dwr.jar、commons-logging-1.0.4.jar、log4j-1.2.12.jar, dwr.jar对commons-logging有依赖。下载完后放到WEB-INF\lib目录,修改build path包含上述jar包。
3).编辑web.xml和dwr.xml,文件位于WEB-INF\目录下
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">
-
- <display-name>DWR (Direct Web Remoting)</display-name>
- <description>A Simple Demo DWR</description>
-
- <listener>
- <listener-class>org.directwebremoting.servlet.DwrListener</listener-class>
- </listener>
-
- <servlet>
- <servlet-name>dwr-invoker</servlet-name>
- <display-name>DWR Servlet</display-name>
- <description>Direct Web Remoter Servlet</description>
- <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
-
- <!-- This should NEVER be present in live -->
- <init-param>
- <param-name>debug</param-name>
- <param-value>true</param-value>
- </init-param>
-
- <init-param>
- <param-name>accessLogLevel</param-name>
- <param-value>CALL</param-value>
- </init-param>
-
- <!-- Remove this unless you want to use active reverse ajax -->
- <init-param>
- <param-name>activeReverseAjaxEnabled</param-name>
- <param-value>true</param-value>
- </init-param>
-
- <!-- By default DWR creates application scope objects when they are first
- used. This creates them when the app-server is started -->
- <init-param>
- <param-name>initApplicationScopeCreatorsAtStartup</param-name>
- <param-value>true</param-value>
- </init-param>
-
- <load-on-startup>1</load-on-startup>
- </servlet>
-
- <servlet-mapping>
- <servlet-name>dwr-invoker</servlet-name>
- <url-pattern>/dwr/*</url-pattern>
- </servlet-mapping>
-
- </web-app>
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
dwr.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN" "http://getahead.org/dwr/dwr30.dtd">
-
- <dwr>
- <allow>
- <create creator="new" scope="application">
- <param name="class" value="com.example.dwr.reverseajax.PeopleTable"/>
- </create>
-
- <convert match="com.example.dwr.people.Person" converter="bean"/>
-
- <!-- resources not in this war file: java.util.Date -->
- <create creator="new" javascript="JDate">
- <param name="class" value="java.util.Date"/>
- <exclude method="getHours"/>
- <auth method="getMinutes" role="admin"/>
- <auth method="getMinutes" role="devel"/>
- <filter class="org.directwebremoting.filter.ExtraLatencyAjaxFilter"/>
- </create>
-
- <!-- this is a bad idea for live, but can be useful in testing -->
- <convert converter="exception" match="java.lang.Exception"/>
- <convert converter="bean" match="java.lang.StackTraceElement"/>
-
- </allow>
- </dwr>
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
web.xml里面定义了DWR的servlet,包含一些初始化参数,这些参数不是必须的,有的仅仅是为了调试方便,比如debug和accessLogLevel。
dwr.xml可以看出,它的主要作用就是定义java类和javascript对象的映射关系。
4).编辑Java Code,实际上就是实现了Runnable接口,每10秒钟随机生成一个Person记录,推送到前端
PeopleTable.java
- package com.example.dwr.reverseajax;
-
- import java.util.concurrent.ScheduledThreadPoolExecutor;
- import java.util.concurrent.TimeUnit;
-
- import org.directwebremoting.Browser;
- import org.directwebremoting.ScriptSession;
- import org.directwebremoting.ScriptSessionFilter;
- import org.directwebremoting.ServerContextFactory;
- import org.directwebremoting.WebContextFactory;
- import org.directwebremoting.impl.DaemonThreadFactory;
- import org.directwebremoting.ui.dwr.Util;
- import org.directwebremoting.util.Logger;
-
- import com.example.dwr.people.Person;
-
- public class PeopleTable implements Runnable {
- Logger log = Logger.getLogger(this.getClass());
-
- /**
- * Constructor - Creates a thread pool that runs every 10 seconds.
- */
- public PeopleTable() {
- ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(
- 1, new DaemonThreadFactory());
- executor.scheduleAtFixedRate(this, 1, 10, TimeUnit.SECONDS);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Runnable#run()
- */
- @Override
- public void run() {
- updateTableDisplay();
- }
-
- public void updateTableDisplay() {
- log.error("enter updateTableDisplay");
- // Get the current page.
- String page = ServerContextFactory.get().getContextPath()
- + "/index.html";
- // Create a new AttributeScriptSessionFilter which will look for an
- // attribute on the ScriptSession
- ScriptSessionFilter attributeFilter = new AttributeScriptSessionFilter(
- SCRIPT_SESSION_ATTR);
- // Update the page, filters ScriptSessions using attributeFilter. If the
- // SCRIPT_SESSION_ATTR
- // has not been set on the ScriptSession the page in question will not
- // receive updates.
- Browser.withPageFiltered(page, attributeFilter, new Runnable() {
- @Override
- public void run() {
- // Creates a new Person bean.
- Person person = new Person(true);
- // Creates a multi-dimensional array, containing a row and the
- // rows column data.
- String[][] data = { { person.getId(), person.getName(),
- person.getAddress(), person.getAge() + "",
- person.isSuperhero() + "" } };
- // Call DWR's util which adds rows into a table. peopleTable is
- // the id of the tbody and
- // data contains the row/column data.
- Util.addRows("peopleTable", data);
- }
- });
- }
-
- /**
- * Called from the client to add an attribute on the ScriptSession. This
- * attribute will be used so that only pages (ScriptSessions) that have set
- * this attribute will be updated.
- */
- public void addAttributeToScriptSession() {
- ScriptSession scriptSession = WebContextFactory.get()
- .getScriptSession();
- scriptSession.setAttribute(SCRIPT_SESSION_ATTR, true);
- }
-
- /**
- * Called from the client to remove an attribute from the ScriptSession.
- * When called from a client that client will no longer receive updates
- * (unless addAttributeToScriptSession) is called again.
- */
- public void removeAttributeToScriptSession() {
- ScriptSession scriptSession = WebContextFactory.get()
- .getScriptSession();
- scriptSession.removeAttribute(SCRIPT_SESSION_ATTR);
- }
-
- /**
- * This is the ScriptSessionFilter that will be used to filter out all
- * ScriptSessions unless they contain the SCRIPT_SESSION_ATTR attribute.
- */
- protected class AttributeScriptSessionFilter implements ScriptSessionFilter {
- public AttributeScriptSessionFilter(String attributeName) {
- this.attributeName = attributeName;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * org.directwebremoting.ScriptSessionFilter#match(org.directwebremoting
- * .ScriptSession)
- */
- @Override
- public boolean match(ScriptSession session) {
- Object check = session.getAttribute(attributeName);
- return (check != null && check.equals(Boolean.TRUE));
- }
-
- private final String attributeName;
- }
-
- private final static String SCRIPT_SESSION_ATTR = "SCRIPT_SESSION_ATTR";
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
Person.java
- package com.example.dwr.people;
-
- import java.util.Random;
- import org.directwebremoting.datasync.ExposeToString;
-
- @ExposeToString
- public class Person {
- private String id;
- private String name;
- private String address;
- private int age;
- private boolean superhero;
- private static int nextId = 1;
-
- private static final Random random = new Random();
-
- public Person() {
- this.id = getNextId();
- }
-
- public Person(boolean withRandom) {
- if (withRandom) {
- this.name = RandomData.getFullName();
- this.address = RandomData.getAddress();
- this.age = RandomData.getAge();
- this.superhero = (random.nextInt(100) == 1);
- }
-
- this.id = getNextId();
- }
-
- public String getId() {
- return this.id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- public String getName() {
- return this.name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getAddress() {
- return this.address;
- }
-
- public void setAddress(String address) {
- this.address = address;
- }
-
- public int getAge() {
- return this.age;
- }
-
- public void setAge(int age) {
- this.age = age;
- }
-
- public boolean isSuperhero() {
- return this.superhero;
- }
-
- public void setSuperhero(boolean superhero) {
- this.superhero = superhero;
- }
-
- public String toString() {
- return this.name;
- }
-
- public static synchronized String getNextId() {
- return "P" + nextId++;
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
RandomData.java
- package com.example.dwr.people;
-
- import java.util.Random;
-
- public class RandomData {
- private static final Random random = new Random();
-
- private static final String[] FIRSTNAMES = { "Fred", "Jim", "Shiela",
- "Jack", "Betty", "Jacob", "Martha", "Kelly", "Luke", "Matt",
- "Gemma", "Joe", "Ben", "Jessie", "Leanne", "Becky", "William",
- "Jo", "Jane", "Joan", "Jerry", "Jason", "Martin", "Mark", "Max",
- "Mike", "Molly", "Sam", "Shane", "Dwane", "Diane", "Anne", "Anna",
- "Bill", "Jack", "Thomas", "Oliver", "Joshua", "Harry", "Charlie",
- "Dan", "Will", "James", "Alfie", "Grace", "Ruby", "Olivia",
- "Emily", "Jessica", "Sophie", "Chloe", "Lily", "Ella", "Amelia",
- "Kimberly", "Owen", "Rhys", "Layla", "Jonny", "Darren", "Laura",
- "Bridget", "Carl", "Josie" };
-
- private static final String[] SURNAMES = { "Sutcliffe", "MacDonald",
- "Duckworth", "Smith", "Wisner", "Jones", "Nield", "Turton",
- "Trelfer", "Wilson", "Johnson", "Daniels", "Jones", "Wilkinson",
- "Wilton", "Jackson" };
-
- private static final String[] ROADS1 = { "Amaranth", "Apricot", "Aqua",
- "Aquamarine", "Beige", "Bronze", "Buff", "Burgundy", "Cerise",
- "Chestnut", "Cobalt", "Coral", "Cream", "Cyan", "Denim",
- "Eggplant", "Fuchsia", "Grey", "Gold", "Indigo", "Ivory", "Jade",
- "Khaki", "Lemon", "Lilac", "Linen", "Magenta", "Magnolia",
- "Maroon", "Mustard", "Ochre", "Olive", "Orange", "Orchid", "Peach",
- "Pear", "Pink", "Ruby", "Scarlet", "Silver", "Sepia", "Tangerine",
- "Taupe", "Tan", "Teal", "Torquise", "Ultramarine", "Violet",
- "Wheat", "Green", "Red", "Yellow", "Brown", "Blue", "Black",
- "White", "Yellow" };
-
- private static final String[] ROADS2 = { "Close", "Drive", "Street",
- "Avenue", "Crescent", "Road", "Place", "Way", "Croft", "Lane" };
-
- private static final String[] TOWNS = { "San Mateo", "San Francisco",
- "San Diego", "New York", "Atlanta", "Sandford", "York", "London",
- "Coventry", "Exeter", "Knowle", "Rhyl", "Stamford" };
-
- public static String getPhoneNumber(boolean isUS) {
- String phoneNumber;
- if (isUS) {
- phoneNumber = "+1 (" + random.nextInt(9) + random.nextInt(9)
- + random.nextInt(9) + ") " + random.nextInt(9)
- + random.nextInt(9) + random.nextInt(9) + " - "
- + random.nextInt(9) + random.nextInt(9) + random.nextInt(9)
- + random.nextInt(9);
- } else {
- phoneNumber = "+44 (0) 1" + random.nextInt(9) + random.nextInt(9)
- + random.nextInt(9) + " " + random.nextInt(9)
- + random.nextInt(9) + random.nextInt(9) + random.nextInt(9)
- + random.nextInt(9) + random.nextInt(9);
- }
-
- return phoneNumber;
- }
-
- public static String getFirstName() {
- return FIRSTNAMES[random.nextInt(FIRSTNAMES.length)];
- }
-
- public static String getSurname() {
- return SURNAMES[random.nextInt(SURNAMES.length)];
- }
-
- public static String getFullName() {
- return getFirstName() + " " + getSurname();
- }
-
- public static String getAddress() {
- String housenum = random.nextInt(399) + 1 + " ";
- String road1 = ROADS1[random.nextInt(ROADS1.length)];
- String road2 = ROADS2[random.nextInt(ROADS2.length)];
- int townNum = random.nextInt(TOWNS.length);
- String town = TOWNS[townNum];
- return housenum + road1 + " " + road2 + ", " + town;
- }
-
- public static String[] getAddressAndNumber() {
- String[] reply = new String[2];
-
- String housenum = random.nextInt(399) + 1 + " ";
- String road1 = ROADS1[random.nextInt(ROADS1.length)];
- String road2 = ROADS2[random.nextInt(ROADS2.length)];
- int townNum = random.nextInt(TOWNS.length);
- String town = TOWNS[townNum];
-
- reply[0] = (housenum + road1 + " " + road2 + ", " + town);
- reply[1] = getPhoneNumber(townNum < 5 ? true : false);
-
- return reply;
- }
-
- public static int getAge() {
- return random.nextInt(80);
- }
-
- public static float getSalary() {
- return Math.round(10.0F + 90.0F * random.nextFloat()) * 1000;
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
注意:需要修改eclipse的default output folder为:dwrtest/WEB-INF/classes。
5).到这里,应该可以访问DWR的测试页面了(必须在web.xml里面配置了debug才能访问测试页面)。在浏览器中输入 http://localhost:8080/dwrtest/dwr/index.html如果一切OK的话,应该显示如下图
这些就是在Javascript端能够调用的Java API,点击PeopleTable进入
这个页面告诉我们,如果要使用提供的API,需要在web页面中包含前两个js文件,这两个URL相当于DWR提供的服务,本地并没有对应的文件。
6).完成html和javascript代码。
我们只有一个页面, 新建html文件命名为index.html并放到工程的根目录下
index.html
- <!DOCTYPE html>
- <html>
- <head>
- <title>Reverse Ajax Table Update</title>
- <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
- <script type='text/javascript' src='../dwrtest/dwr/engine.js'> </script>
- <script type='text/javascript' src='../dwrtest/dwr/util.js'> </script>
- <script type='text/javascript' src='../dwrtest/dwr/interface/PeopleTable.js'> </script>
- <script type='text/javascript' src='../dwrtest/js/onload.js'> </script>
- <link rel="stylesheet" type="text/css" href="../dwrtest/generic.css" />
- </head>
- <body>
- <h1>Reverse Ajax Table Update</h1>
- <div id="tabContents">
- <div id="demoDiv">
- <div id="error"></div>
- <input type="button" id="enable" value="Enable page updates"
- οnclick="addAttributeToScriptSession();" /> <input type="button"
- id="disable" value="Disable page updates"
- οnclick="removeAttributeToScriptSession();" />
- <p>
- Server status: <span id="pollStatus"></span>
- </p>
- <table>
- <thead>
- <th>Id</th>
- <th>Name</th>
- <th>Address</th>
- <th>Age</th>
- <th>Is Superhero?</th>
- </thead>
- <tbody id="peopleTable"></tbody>
- </table>
- </div>
- </div>
- </body>
- </html>
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
onload.js
- window.οnlοad=function()
- {
- dwr.engine.setActiveReverseAjax(true); // Initiate reverse ajax polling
- dwr.engine.setErrorHandler(errorHandler); // Called when a call and all retry attempts fail
- dwr.engine.setPollStatusHandler(updatePollStatus); // Optional function to call when the reverse ajax status changes (e.g. online to offline)
- updatePollStatus(true); // Optional - We are online right now! Until DWR determines we are not!
- dwr.engine.setNotifyServerOnPageUnload(true); // Optional - When the page is unloaded, remove this ScriptSession.
- PeopleTable.updateTableDisplay(); // Make a call to the server to begin updating the table!
- addAttributeToScriptSession(); // Make a remote call to the server to add an attribute onto the ScriptSession which will be used in determining what pages receive updates!
- }
-
- function errorHandler(message, ex) {
- dwr.util.setValue("error", "Cannot connect to server. Initializing retry logic.", {escapeHtml:false});
- setTimeout(function() { dwr.util.setValue("error", ""); }, 5000)
- }
-
- function updatePollStatus(pollStatus) {
- dwr.util.setValue("pollStatus", pollStatus ? "Online" : "Offline", {escapeHtml:false});
- }
-
- // Make a remote call to add an attribute on the ScriptSession.
- // Only clients that have this attribute set will receive updates.
- function addAttributeToScriptSession() {
- PeopleTable.addAttributeToScriptSession();
- }
-
- // Make a remote call to remove an attribute from the ScriptSession.
- // Clients that call this will no longer receive updates (unless addAttributeToScriptSession is called again).
- function removeAttributeToScriptSession() {
- PeopleTable.removeAttributeToScriptSession();
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
7)访问
http://localhost:8080/dwrtest/,大功告成
如果是生产环境,通常需要配置log4J。
新建log4j.xml并放到WEB-INF\classes\目录下,内容如下:
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
-
- <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
- <appender name="console" class="org.apache.log4j.ConsoleAppender">
- <param name="Target" value="System.out"/>
- <layout class="org.apache.log4j.PatternLayout">
- <param name="ConversionPattern" value="%-5p %c{1} - %m%n"/>
- </layout>
- </appender>
-
- <appender name="dwrLogFile" class="org.apache.log4j.FileAppender">
- <param name="File" value="d:/tools/xampp/tomcat/webapps/dwrtest/log/dwrAccess.log"/>
- <param name="Append" value="true"/>
- <param name="Threshold" value="DEBUG"/>
- <layout class="org.apache.log4j.PatternLayout">
- <param name="ConversionPattern" value="%d %-5p [%c] %m%n"/>
- </layout>
- </appender>
-
- <appender name="otherFile" class="org.apache.log4j.FileAppender">
- <param name="File" value="d:/tools/xampp/tomcat/webapps/dwrtest/log/other.log"/>
- <param name="Append" value="true"/>
- <param name="Threshold" value="DEBUG"/>
- <layout class="org.apache.log4j.PatternLayout">
- <param name="ConversionPattern" value="%d %-5p [%c] %m%n"/>
- </layout>
- </appender>
-
- <!-- All application exceptions/errors will be written here -->
- <category name="org.directwebremoting.log.accessLog">
- <priority value="INFO"/>
- <appender-ref ref="dwrLogFile" />
- </category>
-
- <!-- All DWR startup information will be written here -->
- <category name="org.directwebremoting.log.startup">
- <priority value="DEBUG"/>
- <appender-ref ref="dwrLogFile" />
- </category>
-
- <!-- All DWR script information will be written here -->
- <category name="org.directwebremoting.log.scripts">
- <priority value="DEBUG"/>
- <appender-ref ref="dwrLogFile" />
- </category>
-
- <!-- All DWR session information will be written here -->
- <category name="org.directwebremoting.log.session">
- <priority value="DEBUG"/>
- <appender-ref ref="dwrLogFile" />
- </category>
-
- <!-- All other messages will be written here, including exceptions internal to DWR -->
- <root>
- <priority value="DEBUG" />
- <appender-ref ref="otherFile" />
- </root>
-
- </log4j:configuration>
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。