В моем текущем проекте Spring / JSF мне нужно интегрировать метод для отправки обновлений на стороне сервера (предпочтительно, как они происходят) в веб-интерфейс для отображения клиентам.
Итак, чтобы начать работуЯ работаю над этим небольшим приложением, чтобы понять, как работает DWR.По сути, я разработал два варианта для реализации push на стороне сервера.
В первом подходе, когда нажата «кнопка поиска», обновления на стороне сервера отображаются правильно.Это вызывает метод findInstrumentSymbols () в InstrumentManager и возвращает выходные данные в виде объектов List через DWR.
Во втором подходе я попытался реализовать подход обратного ajax, предложенный на веб-сайте DWR. (http://directwebremoting.org/dwr-demo/reverseajax/peopleTable.html)
Как сделать эту функцию доступной в качестве функции по умолчанию каждый раз, когда страница загружается, без необходимости специально активировать ее с помощью кнопки?
В этой реализации мне не удалось вернуть вывод какСписок объектов через DWR, как в первом подходе и должен был быть отправлен в виде строкового массива. Я вижу, что новые результаты не заполняются должным образом, как в первом подходе, и это имеет тенденцию терять новые данные, когда «Отключить кнопку»Как это может быть достигнуто с помощью DWR?
Я перечислил фрагменты кода ниже. Буду очень признателен за любые указания по началу работы функции обратного Ajax.
Я использовалопрос, как описано в предыдущих выпусках DWR. Какой метод был бы наиболее идеальным для реализации функции обратного Ajax, если переход к DWR3 - это путь вперед?
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>
application-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>