在我目前的Spring / JSF项目中,我需要集成一个方法来将服务器端更新(最好是它们发生时)推送到基于Web的GUI,以显示给客户端。
因此,为了开始使用,我正在研究这个小应用程序,以了解DWR的工作原理。基本上,我已经开发了两种变体来实现服务器端推送。
在第一种方法中,当按下“查找按钮”时,正确显示后端更新。这将调用InstrumentManager中的findInstrumentSymbols()方法,并通过DWR将输出作为List Objects返回。
在第二种方法中,我试图实现DWR网站中建议的反向ajax方法。(http://directwebremoting.org/dwr-demo/reverseajax/peopleTable.html)
每次加载页面时如何使此功能可用作默认功能,而无需通过按钮专门激活它?
在这个实现中,我无法像第一种方法那样通过DWR将输出作为List Objects返回,并且必须作为字符串数组发送。我看到新结果没有像第一种方法那样正确填充,并且当按下“禁用按钮”时,它往往会丢失新数据。如何使用DWR正确实现反向服务器推送功能?
我已经列出了下面的代码片段。我真的很感激任何关于使反向Ajax功能运行的指针。
我已经使用了早期DWR版本中描述的轮询。如果切换到DWR3是前进的方法,那么实现反向Ajax功能最理想的方法是什么?
Web.xml中
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>AdminConsole</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/application-context.xml
/WEB-INF/application-security-context.xml</param-value>
</context-param>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
<context-param>
<description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<context-param>
<param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
<param-value>resources.application</param-value>
</context-param>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<servlet>
<display-name>DWR Servlet</display-name>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>org.directwebremoting.extend.ServerLoadMonitor</param-name>
<param-value>org.directwebremoting.impl.PollingServerLoadMonitor</param-value>
</init-param>
<init-param>
<param-name>timeToNextPoll</param-name>
<param-value>5000</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>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>faces/index.xhtml</welcome-file>
</welcome-file-list>
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/login.xhtml</location>
</error-page>
.......
</web-app>
的dwr.xml
<?xml version="1.0" encoding="UTF-8"?>
<DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN" "http://directwebremoting.org/schema/dwr30.dtd">
<dwr>
<allow>
<convert converter="bean" match="com.stocktrade.admin.entity.*"/>
<create creator="spring" javascript="InstrumentManager">
<param name="beanName" value="instrumentManager"/>
</create>
</allow>
</dwr>
应用context.xml中
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:p="http://www.springframework.org/schema/p"
xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring- context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.directwebremoting.org/schema/spring-dwr
http://www.directwebremoting.org/schema/spring-dwr-3.0.xsd">
.....
<!-- bean for Instrument class -->
<bean id="instrumentManager" class="com.stocktrade.admin.instrument.InstrumentManagerImpl">
<property name="instrumentDAO" ref="instrumentDAO"></property>
<property name="userManager" ref="userManager"></property>
<property name="accountManager" ref="accountManager"></property>
<property name="portfolioManager" ref="portfolioManager"></property>
</bean>
......
</beans>
乐器类
package com.xxxxx.admin.entity;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = "instrument")
public class Instrument implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name="symbolName")
private String SymbolName;
@Column(name="name")
private String Name;
@Column(name="quantity")
private long Quantity;
@Column(name="price")
private BigDecimal Price;
@Column(name="Limit")
private int Limit;
public String getSymbolName() {
return SymbolName;
}
public void setSymbolName(String symbolName) {
SymbolName = symbolName;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public long getQuantity() {
return Quantity;
}
public void setQuantity(long quantity) {
Quantity = quantity;
}
public BigDecimal getPrice() {
return Price;
}
public void setPrice(BigDecimal price) {
Price = price;
}
public int getLimit() {
return Limit;
}
public void setLimit(int Limit) {
Limit = Limit;
}
}
InstrumentManager类
package com.xxxxx.admin.instrument;
import java.math.BigDecimal;
import java.util.List;
import com. xxxxx.admin.entity.Instrument;
import com. xxxxx.admin.entity.Portfolio;
import com. xxxxx.admin.entity.Account;
import com. xxxxx.admin.entity.Users;
public interface InstrumentManager {
………
/*used to implement the find() functionality*/
public List<Instrument> findInstrumentSymbols();
/*used to implement the reverse ajax functionality*/
public void SendInstrumentSymbols();
public void addAttributeToScriptSession();
public void removeAttributeToScriptSession();
public void run();
}
InstrumentManagerImpl类
package com.xxxxx.admin.instrument;
import java.math.BigDecimal;
import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
import com.xxxxx.admin.account.AccountManager;
import com.xxxxx.admin.dao.InstrumentDAO;
import com.xxxxx.admin.entity.Instrument;
import com.xxxxx.admin.entity.Account;
import com.xxxxx.admin.entity.Portfolio;
import com.xxxxx.admin.entity.Users;
import com.xxxxx.admin.portfolio.PortfolioManager;
import com.xxxxx.admin.user.UserManager;
import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory;
import org.directwebremoting.util.Logger;
import org.directwebremoting.ScriptSession;
import org.directwebremoting.ScriptSessionFilter;
import org.directwebremoting.Browser;
import org.directwebremoting.ServerContextFactory;
import org.directwebremoting.impl.DaemonThreadFactory;
import org.directwebremoting.ui.dwr.Util;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class InstrumentManagerImpl implements InstrumentManager,Runnable {
private final static String SCRIPT_SESSION_ATTR = "SCRIPT_SESSION_ATTR";
public static String getScriptSessionAttr() {
return SCRIPT_SESSION_ATTR;
}
private UserManager userManager;
public UserManager getUserManager() {
return userManager;
}
public void setUserManager(UserManager userManager) {
this.userManager = userManager;
}
private InstrumentDAO instrumentDAO;
public InstrumentDAO getInstrumentDAO() {
return instrumentDAO;
}
public void setInstrumentDAO(InstrumentDAO instrumentDAO) {
this.instrumentDAO = instrumentDAO;
}
public InstrumentManagerImpl() {
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()
{
SendInstrumentSymbols();
}
/*used to implement the find() functionality*/
@Override
public List<Instrument> findInstrumentSymbols() {
return instrumentDAO.findInstrumentSymbols();
}
/*used to implement the reverse ajax functionality*/
public void SendInstrumentSymbols() {
// Get the current page.
String page = ServerContextFactory.get().getContextPath() + "/faces/gehan.xhtml";
// 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()
{
List<Instrument> InstrumentList = new ArrayList<Instrument>();
InstrumentList = findInstrumentSymbols() ;
//Creates a multi-dimensional array, containing a row and the rows column data.
//Added the First Element of the List returned - values are converted to String
String[][] data = {
{InstrumentList.get(0).getSymbolName().toString(), InstrumentList.get(0).getName().toString(), String.valueOf(InstrumentList.get(0).getQuantity()), InstrumentList.get(0).getPrice().toString(), String.valueOf(InstrumentList.get(0).getMarketMakingLimit())}};
// 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("MMTable", 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
{
private final String attributeName;
public AttributeScriptSessionFilter(String attributeName)
{
this.attributeName = attributeName;
}
@Override
public boolean match(ScriptSession session)
{
Object check = session.getAttribute(attributeName);
return (check != null && check.equals(Boolean.TRUE));
}
}
}
updateMMStatus.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Reverse Ajax Table Update</title>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<script type='text/javascript' src='/AdminConsole/dwr/engine.js'></script>
<script type='text/javascript' src='/AdminConsole/dwr/util.js'></script>
<script type='text/javascript' src='/AdminConsole/dwr/interface/InstrumentManager.js'></script>
<script type="text/javascript">
window.onload=function()
{
// Initiate reverse ajax polling
dwr.engine.setActiveReverseAjax(true);
// Called when a call and all retry attempts fail
dwr.engine.setErrorHandler(errorHandler);
// Optional function to call when the reverse ajax status changes (e.g. online to offline)
dwr.engine.setPollStatusHandler(updatePollStatus);
// Optional - We are online right now! Until DWR determines we are not!
updatePollStatus(true);
//Optional - When the page is unloaded, remove this ScriptSession.
dwr.engine.setNotifyServerOnPageUnload(true);
// Initialize the tabs for this display
Tabs.init('tabList', 'tabContents');
// Make a call to the server to begin updating the table!
InstrumentManager.SendInstrumentSymbols();
//Make a remote call to the server to add an attribute onto the ScriptSession
//which will be used in determining what pages receive updates!
addAttributeToScriptSession();
}
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() {
InstrumentManager.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() {
InstrumentManager.removeAttributeToScriptSession();
}
</script>
/*Java script to updated instrument table related changes when the "find" Button is pressed */
function find() {
<script type="text/javascript">
function find() {
InstrumentManager.findInstrumentSymbols();
}
</script>
</h:head>
<h:body onload="dwr.engine.setActiveReverseAjax(true);">
<input type="button" value="Enable page updates" onclick="addAttributeToScriptSession();"/>
<input type="button" value="Disable page updates" onclick="removeAttributeToScriptSession();"/>
<h:messages styleClass="error" />
<div class="data_header">Current Symbols in the System</div>
<h:dataTable rowClasses="odd,even" id="MMTable"
value="#{updateMMStausBean.instrumentsList}" var="insList"
rendered="#{updateMMStausBean.instrumentsList != null}"
headerClass="tableHeader" styleClass="table">
<h:column>
<f:facet name="header">
<h:outputText value="Symbol" />
</f:facet>
<div align="left">
<h:outputText value="#{insList.symbolName}" />
</div>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Name" />
</f:facet>
<div align="left">
<h:outputText value="#{insList.name}" />
</div>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Quantity" />
</f:facet>
<div align="center">
<h:outputText value="#{insList.quantity}" />
</div>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Price($)" />
</f:facet>
<div align="right">
<h:outputText value="#{insList.price}" />
</div>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Limit" />
</f:facet>
<div align="right">
<h:outputText value="#{insList.mMLimit}" />
</div>
</h:column>
</h:dataTable>
<div id="container">
<h:panelGrid columns="2" cellpadding="6">
<h:form id="authenticate1">
<h:commandButton action="#{updateMMStausBean.ActivateAllMMOrdrerOn()}" value="Activate all Orders">
</h:commandButton>
</h:form>
<h:form id="authenticate2">
<h:commandButton action="#{updateMMStausBean.DeactivateAllMMOrdrerOn()}" value="Deactivate all Orders">
</h:commandButton>
</h:form>
/* Java script to updated instrument table related changes when the "find" Button is pressed */
<h:form id="authenticate3">
<h:commandButton value="Find" onclick="find()">
</h:commandButton>
</h:form>
</h:panelGrid>
</div>
</h:body>
</html>
答案 0 :(得分:0)
排除了问题的一部分,但我还没有运气,因为现在使用服务器端推送传递了一个java List。
我一直在研究基于网络的peopleTable demo application和类似的应用程序,为我的问题提出解决方案。这些应用程序中的大多数都传递String或String数组。
* &gt;&gt;&gt; *这会调用InstrumentManager中的findInstrumentSymbols()方法,并通过DWR将输出作为Object返回。
我在DWR中注意到的一件事是,当调用DWR java脚本链接到GUI操作(如Onclick(Egfind按钮))时,可以顺利传递Object或集合类型数据。我相信返回JSON对象这个例子。
程序中显示的findInstuments methods JSON output,可以轻松集成到网页中。
&gt;&gt;&gt; * 但是当您尝试使用服务器推送操作将数据传递到网页时,我无法像以前那样通过DWR返回输出,就像第一种方法一样。它有作为字符串数组发送(根据我遇到的信息* :| )。
我将服务器Push示例代码基于peopleTable演示的变体。似乎DWR提供了很少的工具来将集合或对象发送到GUI,尽管在链接到传递JSON对象的用户操作时它很容易获得。 (它似乎支持String / String数组和基于字符串的集合,或者我收集的是:| )
下面列出了与此描述相关的相关代码示例。(完整代码参考原始帖子)
public void SendInstrumentSymbols() {
// Get the current page.
String page = ServerContextFactory.get().getContextPath() + "/faces/Instruments.xhtml";
// 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.
Collection sessions = ServerContextFactory.get().getScriptSessionsByPage(page);
Browser.withPageFiltered(page, attributeFilter, new Runnable()
{
<b>@Override
public void run()
{
// Creates a new Person bean.
List<Instrument> InstrumentList = new ArrayList<Instrument>();
InstrumentList = findInstrumentSymbols() ;
/*This seems to be the tricky part - Sending the List<Instrument> to the server end.*/
// Creates a multi-dimensional array, containing a row and the rows column data.
String[][] data = {
{InstrumentList.get(0).getSymbolName().toString(), InstrumentList.get(0).getName().toString(), String.valueOf(InstrumentList.get(0).getQuantity()), InstrumentList.get(0).getPrice().toString(), String.valueOf(InstrumentList.get(0).getMarketMakingLimit()),String.valueOf(InstrumentList.get(0).isBuyOrderMarketMakingOn()),String.valueOf(InstrumentList.get(0).isSellOrderMarketMakingOn())}};
// Call DWR's util which adds rows into a table. instrumentTable is the id of the tbody and
// data contains the row/column data.
Util.addRows("instrumentTable", data);
}
}</b>);
}
当你试图改变这个功能以支持其他数据类型时,List我找不到一个Clean方法,就像第一个传递Json对象的实例一样 - 这很容易。(我希望我没有错过显而易见的事情:|)
在使用此方法使用服务器推送时,是否有更好的方法可以设计传输对象?(求助于字符串转换似乎是大多数网络示例中建议的方法。)< / p>
在没有GUI触发器的情况下执行服务器端推送以满足相同要求时,可以将数据作为JSON对象进行交换吗? * 是否需要进行其他配置更改和更新? *
如果基于JSON的数据传输对于服务器端推送是可能的,那么请您对某些可能有任何帮助的文档,站点或示例代码提出一些看法。任何这样的领导都会非常感谢我没有找到关于这个主题的具体内容
先谢谢你