当前位置:   article > 正文

使用DWR更新Table_dwrthb

dwrthb

1.简介

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事件更新页面的下拉列表

dwr version 1.0 interaction diagram

下图展示利用Reverse Ajax,服务器端能够监控不同客户端在打开哪些页面,将手工或者使用Java API生成的javascript发送给它们。

dwr version 2.0 interaction diagram

官网上能够下载用于演示的war包,里面有一些常见的功能演示。本文仅从学习的角度,自己从头搭建使用DWR动态更新Table的环境,完成后页面如图



2.环境搭建

 环境介绍

        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

  1. <?xml version="1.0" encoding="ISO-8859-1"?>
  2. <!DOCTYPE web-app PUBLIC
  3. "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
  4. "http://java.sun.com/dtd/web-app_2_3.dtd">
  5. <web-app id="dwr">
  6. <display-name>DWR (Direct Web Remoting)</display-name>
  7. <description>A Simple Demo DWR</description>
  8. <listener>
  9. <listener-class>org.directwebremoting.servlet.DwrListener</listener-class>
  10. </listener>
  11. <servlet>
  12. <servlet-name>dwr-invoker</servlet-name>
  13. <display-name>DWR Servlet</display-name>
  14. <description>Direct Web Remoter Servlet</description>
  15. <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
  16. <!-- This should NEVER be present in live -->
  17. <init-param>
  18. <param-name>debug</param-name>
  19. <param-value>true</param-value>
  20. </init-param>
  21. <init-param>
  22. <param-name>accessLogLevel</param-name>
  23. <param-value>CALL</param-value>
  24. </init-param>
  25. <!-- Remove this unless you want to use active reverse ajax -->
  26. <init-param>
  27. <param-name>activeReverseAjaxEnabled</param-name>
  28. <param-value>true</param-value>
  29. </init-param>
  30. <!-- By default DWR creates application scope objects when they are first
  31. used. This creates them when the app-server is started -->
  32. <init-param>
  33. <param-name>initApplicationScopeCreatorsAtStartup</param-name>
  34. <param-value>true</param-value>
  35. </init-param>
  36. <load-on-startup>1</load-on-startup>
  37. </servlet>
  38. <servlet-mapping>
  39. <servlet-name>dwr-invoker</servlet-name>
  40. <url-pattern>/dwr/*</url-pattern>
  41. </servlet-mapping>
  42. </web-app>
dwr.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN" "http://getahead.org/dwr/dwr30.dtd">
  3. <dwr>
  4. <allow>
  5. <create creator="new" scope="application">
  6. <param name="class" value="com.example.dwr.reverseajax.PeopleTable"/>
  7. </create>
  8. <convert match="com.example.dwr.people.Person" converter="bean"/>
  9. <!-- resources not in this war file: java.util.Date -->
  10. <create creator="new" javascript="JDate">
  11. <param name="class" value="java.util.Date"/>
  12. <exclude method="getHours"/>
  13. <auth method="getMinutes" role="admin"/>
  14. <auth method="getMinutes" role="devel"/>
  15. <filter class="org.directwebremoting.filter.ExtraLatencyAjaxFilter"/>
  16. </create>
  17. <!-- this is a bad idea for live, but can be useful in testing -->
  18. <convert converter="exception" match="java.lang.Exception"/>
  19. <convert converter="bean" match="java.lang.StackTraceElement"/>
  20. </allow>
  21. </dwr>
web.xml里面定义了DWR的servlet,包含一些初始化参数,这些参数不是必须的,有的仅仅是为了调试方便,比如debug和accessLogLevel。

dwr.xml可以看出,它的主要作用就是定义java类和javascript对象的映射关系。

4).编辑Java Code,实际上就是实现了Runnable接口,每10秒钟随机生成一个Person记录,推送到前端

PeopleTable.java

  1. package com.example.dwr.reverseajax;
  2. import java.util.concurrent.ScheduledThreadPoolExecutor;
  3. import java.util.concurrent.TimeUnit;
  4. import org.directwebremoting.Browser;
  5. import org.directwebremoting.ScriptSession;
  6. import org.directwebremoting.ScriptSessionFilter;
  7. import org.directwebremoting.ServerContextFactory;
  8. import org.directwebremoting.WebContextFactory;
  9. import org.directwebremoting.impl.DaemonThreadFactory;
  10. import org.directwebremoting.ui.dwr.Util;
  11. import org.directwebremoting.util.Logger;
  12. import com.example.dwr.people.Person;
  13. public class PeopleTable implements Runnable {
  14. Logger log = Logger.getLogger(this.getClass());
  15. /**
  16. * Constructor - Creates a thread pool that runs every 10 seconds.
  17. */
  18. public PeopleTable() {
  19. ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(
  20. 1, new DaemonThreadFactory());
  21. executor.scheduleAtFixedRate(this, 1, 10, TimeUnit.SECONDS);
  22. }
  23. /*
  24. * (non-Javadoc)
  25. *
  26. * @see java.lang.Runnable#run()
  27. */
  28. @Override
  29. public void run() {
  30. updateTableDisplay();
  31. }
  32. public void updateTableDisplay() {
  33. log.error("enter updateTableDisplay");
  34. // Get the current page.
  35. String page = ServerContextFactory.get().getContextPath()
  36. + "/index.html";
  37. // Create a new AttributeScriptSessionFilter which will look for an
  38. // attribute on the ScriptSession
  39. ScriptSessionFilter attributeFilter = new AttributeScriptSessionFilter(
  40. SCRIPT_SESSION_ATTR);
  41. // Update the page, filters ScriptSessions using attributeFilter. If the
  42. // SCRIPT_SESSION_ATTR
  43. // has not been set on the ScriptSession the page in question will not
  44. // receive updates.
  45. Browser.withPageFiltered(page, attributeFilter, new Runnable() {
  46. @Override
  47. public void run() {
  48. // Creates a new Person bean.
  49. Person person = new Person(true);
  50. // Creates a multi-dimensional array, containing a row and the
  51. // rows column data.
  52. String[][] data = { { person.getId(), person.getName(),
  53. person.getAddress(), person.getAge() + "",
  54. person.isSuperhero() + "" } };
  55. // Call DWR's util which adds rows into a table. peopleTable is
  56. // the id of the tbody and
  57. // data contains the row/column data.
  58. Util.addRows("peopleTable", data);
  59. }
  60. });
  61. }
  62. /**
  63. * Called from the client to add an attribute on the ScriptSession. This
  64. * attribute will be used so that only pages (ScriptSessions) that have set
  65. * this attribute will be updated.
  66. */
  67. public void addAttributeToScriptSession() {
  68. ScriptSession scriptSession = WebContextFactory.get()
  69. .getScriptSession();
  70. scriptSession.setAttribute(SCRIPT_SESSION_ATTR, true);
  71. }
  72. /**
  73. * Called from the client to remove an attribute from the ScriptSession.
  74. * When called from a client that client will no longer receive updates
  75. * (unless addAttributeToScriptSession) is called again.
  76. */
  77. public void removeAttributeToScriptSession() {
  78. ScriptSession scriptSession = WebContextFactory.get()
  79. .getScriptSession();
  80. scriptSession.removeAttribute(SCRIPT_SESSION_ATTR);
  81. }
  82. /**
  83. * This is the ScriptSessionFilter that will be used to filter out all
  84. * ScriptSessions unless they contain the SCRIPT_SESSION_ATTR attribute.
  85. */
  86. protected class AttributeScriptSessionFilter implements ScriptSessionFilter {
  87. public AttributeScriptSessionFilter(String attributeName) {
  88. this.attributeName = attributeName;
  89. }
  90. /*
  91. * (non-Javadoc)
  92. *
  93. * @see
  94. * org.directwebremoting.ScriptSessionFilter#match(org.directwebremoting
  95. * .ScriptSession)
  96. */
  97. @Override
  98. public boolean match(ScriptSession session) {
  99. Object check = session.getAttribute(attributeName);
  100. return (check != null && check.equals(Boolean.TRUE));
  101. }
  102. private final String attributeName;
  103. }
  104. private final static String SCRIPT_SESSION_ATTR = "SCRIPT_SESSION_ATTR";
  105. }
Person.java

  1. package com.example.dwr.people;
  2. import java.util.Random;
  3. import org.directwebremoting.datasync.ExposeToString;
  4. @ExposeToString
  5. public class Person {
  6. private String id;
  7. private String name;
  8. private String address;
  9. private int age;
  10. private boolean superhero;
  11. private static int nextId = 1;
  12. private static final Random random = new Random();
  13. public Person() {
  14. this.id = getNextId();
  15. }
  16. public Person(boolean withRandom) {
  17. if (withRandom) {
  18. this.name = RandomData.getFullName();
  19. this.address = RandomData.getAddress();
  20. this.age = RandomData.getAge();
  21. this.superhero = (random.nextInt(100) == 1);
  22. }
  23. this.id = getNextId();
  24. }
  25. public String getId() {
  26. return this.id;
  27. }
  28. public void setId(String id) {
  29. this.id = id;
  30. }
  31. public String getName() {
  32. return this.name;
  33. }
  34. public void setName(String name) {
  35. this.name = name;
  36. }
  37. public String getAddress() {
  38. return this.address;
  39. }
  40. public void setAddress(String address) {
  41. this.address = address;
  42. }
  43. public int getAge() {
  44. return this.age;
  45. }
  46. public void setAge(int age) {
  47. this.age = age;
  48. }
  49. public boolean isSuperhero() {
  50. return this.superhero;
  51. }
  52. public void setSuperhero(boolean superhero) {
  53. this.superhero = superhero;
  54. }
  55. public String toString() {
  56. return this.name;
  57. }
  58. public static synchronized String getNextId() {
  59. return "P" + nextId++;
  60. }
  61. }
RandomData.java

  1. package com.example.dwr.people;
  2. import java.util.Random;
  3. public class RandomData {
  4. private static final Random random = new Random();
  5. private static final String[] FIRSTNAMES = { "Fred", "Jim", "Shiela",
  6. "Jack", "Betty", "Jacob", "Martha", "Kelly", "Luke", "Matt",
  7. "Gemma", "Joe", "Ben", "Jessie", "Leanne", "Becky", "William",
  8. "Jo", "Jane", "Joan", "Jerry", "Jason", "Martin", "Mark", "Max",
  9. "Mike", "Molly", "Sam", "Shane", "Dwane", "Diane", "Anne", "Anna",
  10. "Bill", "Jack", "Thomas", "Oliver", "Joshua", "Harry", "Charlie",
  11. "Dan", "Will", "James", "Alfie", "Grace", "Ruby", "Olivia",
  12. "Emily", "Jessica", "Sophie", "Chloe", "Lily", "Ella", "Amelia",
  13. "Kimberly", "Owen", "Rhys", "Layla", "Jonny", "Darren", "Laura",
  14. "Bridget", "Carl", "Josie" };
  15. private static final String[] SURNAMES = { "Sutcliffe", "MacDonald",
  16. "Duckworth", "Smith", "Wisner", "Jones", "Nield", "Turton",
  17. "Trelfer", "Wilson", "Johnson", "Daniels", "Jones", "Wilkinson",
  18. "Wilton", "Jackson" };
  19. private static final String[] ROADS1 = { "Amaranth", "Apricot", "Aqua",
  20. "Aquamarine", "Beige", "Bronze", "Buff", "Burgundy", "Cerise",
  21. "Chestnut", "Cobalt", "Coral", "Cream", "Cyan", "Denim",
  22. "Eggplant", "Fuchsia", "Grey", "Gold", "Indigo", "Ivory", "Jade",
  23. "Khaki", "Lemon", "Lilac", "Linen", "Magenta", "Magnolia",
  24. "Maroon", "Mustard", "Ochre", "Olive", "Orange", "Orchid", "Peach",
  25. "Pear", "Pink", "Ruby", "Scarlet", "Silver", "Sepia", "Tangerine",
  26. "Taupe", "Tan", "Teal", "Torquise", "Ultramarine", "Violet",
  27. "Wheat", "Green", "Red", "Yellow", "Brown", "Blue", "Black",
  28. "White", "Yellow" };
  29. private static final String[] ROADS2 = { "Close", "Drive", "Street",
  30. "Avenue", "Crescent", "Road", "Place", "Way", "Croft", "Lane" };
  31. private static final String[] TOWNS = { "San Mateo", "San Francisco",
  32. "San Diego", "New York", "Atlanta", "Sandford", "York", "London",
  33. "Coventry", "Exeter", "Knowle", "Rhyl", "Stamford" };
  34. public static String getPhoneNumber(boolean isUS) {
  35. String phoneNumber;
  36. if (isUS) {
  37. phoneNumber = "+1 (" + random.nextInt(9) + random.nextInt(9)
  38. + random.nextInt(9) + ") " + random.nextInt(9)
  39. + random.nextInt(9) + random.nextInt(9) + " - "
  40. + random.nextInt(9) + random.nextInt(9) + random.nextInt(9)
  41. + random.nextInt(9);
  42. } else {
  43. phoneNumber = "+44 (0) 1" + random.nextInt(9) + random.nextInt(9)
  44. + random.nextInt(9) + " " + random.nextInt(9)
  45. + random.nextInt(9) + random.nextInt(9) + random.nextInt(9)
  46. + random.nextInt(9) + random.nextInt(9);
  47. }
  48. return phoneNumber;
  49. }
  50. public static String getFirstName() {
  51. return FIRSTNAMES[random.nextInt(FIRSTNAMES.length)];
  52. }
  53. public static String getSurname() {
  54. return SURNAMES[random.nextInt(SURNAMES.length)];
  55. }
  56. public static String getFullName() {
  57. return getFirstName() + " " + getSurname();
  58. }
  59. public static String getAddress() {
  60. String housenum = random.nextInt(399) + 1 + " ";
  61. String road1 = ROADS1[random.nextInt(ROADS1.length)];
  62. String road2 = ROADS2[random.nextInt(ROADS2.length)];
  63. int townNum = random.nextInt(TOWNS.length);
  64. String town = TOWNS[townNum];
  65. return housenum + road1 + " " + road2 + ", " + town;
  66. }
  67. public static String[] getAddressAndNumber() {
  68. String[] reply = new String[2];
  69. String housenum = random.nextInt(399) + 1 + " ";
  70. String road1 = ROADS1[random.nextInt(ROADS1.length)];
  71. String road2 = ROADS2[random.nextInt(ROADS2.length)];
  72. int townNum = random.nextInt(TOWNS.length);
  73. String town = TOWNS[townNum];
  74. reply[0] = (housenum + road1 + " " + road2 + ", " + town);
  75. reply[1] = getPhoneNumber(townNum < 5 ? true : false);
  76. return reply;
  77. }
  78. public static int getAge() {
  79. return random.nextInt(80);
  80. }
  81. public static float getSalary() {
  82. return Math.round(10.0F + 90.0F * random.nextFloat()) * 1000;
  83. }
  84. }

注意:需要修改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

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Reverse Ajax Table Update</title>
  5. <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
  6. <script type='text/javascript' src='../dwrtest/dwr/engine.js'> </script>
  7. <script type='text/javascript' src='../dwrtest/dwr/util.js'> </script>
  8. <script type='text/javascript' src='../dwrtest/dwr/interface/PeopleTable.js'> </script>
  9. <script type='text/javascript' src='../dwrtest/js/onload.js'> </script>
  10. <link rel="stylesheet" type="text/css" href="../dwrtest/generic.css" />
  11. </head>
  12. <body>
  13. <h1>Reverse Ajax Table Update</h1>
  14. <div id="tabContents">
  15. <div id="demoDiv">
  16. <div id="error"></div>
  17. <input type="button" id="enable" value="Enable page updates"
  18. οnclick="addAttributeToScriptSession();" /> <input type="button"
  19. id="disable" value="Disable page updates"
  20. οnclick="removeAttributeToScriptSession();" />
  21. <p>
  22. Server status: <span id="pollStatus"></span>
  23. </p>
  24. <table>
  25. <thead>
  26. <th>Id</th>
  27. <th>Name</th>
  28. <th>Address</th>
  29. <th>Age</th>
  30. <th>Is Superhero?</th>
  31. </thead>
  32. <tbody id="peopleTable"></tbody>
  33. </table>
  34. </div>
  35. </div>
  36. </body>
  37. </html>
onload.js

  1. window.οnlοad=function()
  2. {
  3. dwr.engine.setActiveReverseAjax(true); // Initiate reverse ajax polling
  4. dwr.engine.setErrorHandler(errorHandler); // Called when a call and all retry attempts fail
  5. dwr.engine.setPollStatusHandler(updatePollStatus); // Optional function to call when the reverse ajax status changes (e.g. online to offline)
  6. updatePollStatus(true); // Optional - We are online right now! Until DWR determines we are not!
  7. dwr.engine.setNotifyServerOnPageUnload(true); // Optional - When the page is unloaded, remove this ScriptSession.
  8. PeopleTable.updateTableDisplay(); // Make a call to the server to begin updating the table!
  9. 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!
  10. }
  11. function errorHandler(message, ex) {
  12. dwr.util.setValue("error", "Cannot connect to server. Initializing retry logic.", {escapeHtml:false});
  13. setTimeout(function() { dwr.util.setValue("error", ""); }, 5000)
  14. }
  15. function updatePollStatus(pollStatus) {
  16. dwr.util.setValue("pollStatus", pollStatus ? "Online" : "Offline", {escapeHtml:false});
  17. }
  18. // Make a remote call to add an attribute on the ScriptSession.
  19. // Only clients that have this attribute set will receive updates.
  20. function addAttributeToScriptSession() {
  21. PeopleTable.addAttributeToScriptSession();
  22. }
  23. // Make a remote call to remove an attribute from the ScriptSession.
  24. // Clients that call this will no longer receive updates (unless addAttributeToScriptSession is called again).
  25. function removeAttributeToScriptSession() {
  26. PeopleTable.removeAttributeToScriptSession();
  27. }
7)访问 http://localhost:8080/dwrtest/,大功告成 大笑

3. 配置log4j

如果是生产环境,通常需要配置log4J。

新建log4j.xml并放到WEB-INF\classes\目录下,内容如下:

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
  3. <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
  4. <appender name="console" class="org.apache.log4j.ConsoleAppender">
  5. <param name="Target" value="System.out"/>
  6. <layout class="org.apache.log4j.PatternLayout">
  7. <param name="ConversionPattern" value="%-5p %c{1} - %m%n"/>
  8. </layout>
  9. </appender>
  10. <appender name="dwrLogFile" class="org.apache.log4j.FileAppender">
  11. <param name="File" value="d:/tools/xampp/tomcat/webapps/dwrtest/log/dwrAccess.log"/>
  12. <param name="Append" value="true"/>
  13. <param name="Threshold" value="DEBUG"/>
  14. <layout class="org.apache.log4j.PatternLayout">
  15. <param name="ConversionPattern" value="%d %-5p [%c] %m%n"/>
  16. </layout>
  17. </appender>
  18. <appender name="otherFile" class="org.apache.log4j.FileAppender">
  19. <param name="File" value="d:/tools/xampp/tomcat/webapps/dwrtest/log/other.log"/>
  20. <param name="Append" value="true"/>
  21. <param name="Threshold" value="DEBUG"/>
  22. <layout class="org.apache.log4j.PatternLayout">
  23. <param name="ConversionPattern" value="%d %-5p [%c] %m%n"/>
  24. </layout>
  25. </appender>
  26. <!-- All application exceptions/errors will be written here -->
  27. <category name="org.directwebremoting.log.accessLog">
  28. <priority value="INFO"/>
  29. <appender-ref ref="dwrLogFile" />
  30. </category>
  31. <!-- All DWR startup information will be written here -->
  32. <category name="org.directwebremoting.log.startup">
  33. <priority value="DEBUG"/>
  34. <appender-ref ref="dwrLogFile" />
  35. </category>
  36. <!-- All DWR script information will be written here -->
  37. <category name="org.directwebremoting.log.scripts">
  38. <priority value="DEBUG"/>
  39. <appender-ref ref="dwrLogFile" />
  40. </category>
  41. <!-- All DWR session information will be written here -->
  42. <category name="org.directwebremoting.log.session">
  43. <priority value="DEBUG"/>
  44. <appender-ref ref="dwrLogFile" />
  45. </category>
  46. <!-- All other messages will be written here, including exceptions internal to DWR -->
  47. <root>
  48. <priority value="DEBUG" />
  49. <appender-ref ref="otherFile" />
  50. </root>
  51. </log4j:configuration>

附:eclipse工程截图



声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/554961
推荐阅读
相关标签
  

闽ICP备14008679号