当我不使用任何 JSF 命令组件调用发送方法时,PushContext 不向打开的套接字发送任何内容
The PushContext sends nothing to the opened socket when i don't use any JSF command component to invoke the send method
故事:
我在一个住宿网站上工作。我想根据日期变化在页面中进行一些 Ajax 渲染。如果我使用像命令按钮这样的 JSF 命令组件,WebSocket Push 将起作用。但是,如果我使用可观察 bean 要求观察者 bean 调用 pushContext.send
方法,则 onDayChange 方法会在一分钟后被调用,并且此方法中没有异常,但 accommodationSearchFields 元素没有呈现,因此 data-currentDate 属性没有改变,当我查看 Web Developer Tools > Network > XHR 时,有没有记录。
我做了什么:
EJB Bean:
@Singleton @Lock(LockType.READ)
public class DateScheduled implements NextDayObservable{
// Other member variables
private final ScheduledExecutorService scheduledExecutorService;
private final List<NextDayObserver> dateObservers;
public DateScheduled(){
/*this.now = LocalDateTime.now();
this.nextDay = LocalDateTime.now()
.withHour(00)
.withMinute(0)
.withSecond(1)
.withNano(0);
scheduledExecutorService.scheduleAtFixedRate(
() -> { notifyObserversOfDayChange(); },
now.until(nextDay, ChronoUnit.MILLIS),
TimeUnit.DAYS.toMillis(1),
TimeUnit.MILLISECONDS
);*/
this.scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledExecutorService.scheduleAtFixedRate(
() -> { notifyObserversOfDayChange(); },
10000,
TimeUnit.DAYS.toMillis(1),
TimeUnit.MILLISECONDS
);
this.dateObservers = new ArrayList<>();
}
@Override @Lock(LockType.WRITE)
public void registerObserver(final NextDayObserver dateObserver){
if(dateObservers.indexOf(dateObserver) < 0){
dateObservers.add(dateObserver);
}
}
@Override @Lock(LockType.WRITE)
public void removeObserver(final NextDayObserver dateObserver){
dateObservers.remove(dateObserver);
}
@Override
public void notifyObserversOfDayChange(){
dateObservers.forEach(
dateObserver -> { dateObserver.onDayChange(); }
);
}
}
支持 Bean:
@Named @ApplicationScoped
public class MainTemplateMB extends BaseManagedBean implements Serializable, NextDayObserver{
private static final long serialVersionUID = 1L;
// Other member variables
private String currentDate;
@EJB
protected NextDayObservable nextDayObservable;
@Inject @Push
private PushContext pushContext;
// Other member variables
public MainTemplateMB(){
// Other Initializations
this.currentDate = "";
}
@PostConstruct
private void initialization(){
// Other Initializations
nextDayObservable.registerObserver(this);
currentDate = DateUtility.getCurrentYear() + "." + (DateUtility.getCurrentMonth() -1) + "." + DateUtility.getCurrentDay() + "." + DateUtility.getMonthFirstDay()+ "." + DateUtility.getLastMonthMaximumDays();
}
// Other Methods
@Override
public void onDayChange(){
// currentDate has changed for testing
currentDate = DateUtility.getCurrentYear() + "." + ( DateUtility.getCurrentMonth() + 1 ) + "." + DateUtility.getCurrentDay() + "." + DateUtility.getMonthFirstDay()+ "." + DateUtility.getLastMonthMaximumDays();
pushContext.send("dayChange");
}
}
MainTemplate.xhtml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:jsf="http://xmlns.jcp.org/jsf"
xmlns:jsfc="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
lang="#{sessionTools.language}" xml:lang="#{sessionTools.language}">
<jsfc:view locale="#{sessionTools.locale}" contentType="text/html">
<head>
.
.
.
</head>
<body>
<div id="wrapper">
.
.
.
<section jsf:id="accommodationSearchFields" data-currentDate="#{mainTemplateMB.currentDate}">
<form jsf:id="accommodationSearchForm" method="GET" autocomplete="off">
.
.
.
<input class="button field roundedCorners4" type="submit" value="#{mainTemplateProp.search}" jsf:action="#{mainTemplateMB.goToTheCity()}" />
<!-- <input class="button field roundedCorners4" type="submit" value="#{mainTemplateProp.search}" jsf:action="#{mainTemplateMB.onDayChange()}">
<jsfc:ajax />
</input> -->
.
.
.
</form>
</section>
.
.
.
</div>
<form jsf:id="dayChangeWebSocket">
<jsfc:websocket channel="pushContext">
<jsfc:ajax event="dayChange" render=":accommodationSearchFields" />
</jsfc:websocket>
</form>
</body>
</jsfc:view>
</html>
切换到 JEE 观察者模式后:
EJB Bean:
@Singleton @Startup @Lock(LockType.READ)
public class DateScheduled{
// Other member variables
private final ScheduledExecutorService scheduledExecutorService;
@Inject
private BeanManager beanManager;
public DateScheduled(){
/*this.now = LocalDateTime.now();
this.nextDay = LocalDateTime.now()
.withHour(00)
.withMinute(0)
.withSecond(1)
.withNano(0);
scheduledExecutorService.scheduleAtFixedRate(
() -> { notifyObserversOfDayChange(); },
now.until(nextDay, ChronoUnit.MILLIS),
TimeUnit.DAYS.toMillis(1),
TimeUnit.MILLISECONDS
);*/
this.scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledExecutorService.scheduleAtFixedRate(
() -> { notifyObserversOfDayChange(); },
60000,
TimeUnit.DAYS.toMillis(1),
TimeUnit.MILLISECONDS
);
}
public void notifyObserversOfDayChange(){
beanManager.fireEvent("Hello");
}
}
支持 Bean:
@Named @ApplicationScoped
public class MainTemplateMB extends BaseManagedBean implements Serializable{
private static final long serialVersionUID = 1L;
// Other member variables
private String currentDate;
@Inject @Push
private PushContext pushContext;
// Other member variables
public MainTemplateMB(){
// Other Initializations
this.currentDate = "";
}
@PostConstruct
private void initialization(){
// Other Initializations
currentDate = DateUtility.getCurrentYear() + "." + (DateUtility.getCurrentMonth() -1) + "." + DateUtility.getCurrentDay() + "." + DateUtility.getMonthFirstDay()+ "." + DateUtility.getLastMonthMaximumDays();
}
// Other Methods
public void onDayChange(@Observes String message){
// currentDate has changed for testing
currentDate = DateUtility.getCurrentYear() + "." + ( DateUtility.getCurrentMonth() + 1 ) + "." + DateUtility.getCurrentDay() + "." + DateUtility.getMonthFirstDay()+ "." + DateUtility.getLastMonthMaximumDays();
pushContext.send("dayChange");
}
}
工作工具:
。 Apache TomEE Plus 8.0.3
。阿帕奇 NetBeans IDE 12.0
问题:
- 我是不是有什么问题?
- 有什么问题?
- 如何解决问题?
我解决了问题。
当我将 onopen 客户端事件添加到 <f:websocket>
时,我意识到套接字没有打开。我在搜索时遇到了这个很好的答案:.
原因编号 8:
If you're using Ajax via JSF 2.x <f:ajax>
or e.g. PrimeFaces
<p:commandXxx>
, make sure that you have a <h:head>
in the master
template instead of the <head>
. Otherwise JSF won't be able to
auto-include the necessary JavaScript files which contains the Ajax
functions. This would result in a JavaScript error like "mojarra is
not defined" or "PrimeFaces is not defined" in browser's JS console.
现在我明白我必须使用 来解决这个问题。感谢 BalusC.
但我不明白为什么单击命令按钮有效但调用观察者方法却无效?鉴于我在控制台中没有看到任何 JavaScript 错误。
故事:
我在一个住宿网站上工作。我想根据日期变化在页面中进行一些 Ajax 渲染。如果我使用像命令按钮这样的 JSF 命令组件,WebSocket Push 将起作用。但是,如果我使用可观察 bean 要求观察者 bean 调用 pushContext.send
方法,则 onDayChange 方法会在一分钟后被调用,并且此方法中没有异常,但 accommodationSearchFields 元素没有呈现,因此 data-currentDate 属性没有改变,当我查看 Web Developer Tools > Network > XHR 时,有没有记录。
我做了什么:
EJB Bean:
@Singleton @Lock(LockType.READ)
public class DateScheduled implements NextDayObservable{
// Other member variables
private final ScheduledExecutorService scheduledExecutorService;
private final List<NextDayObserver> dateObservers;
public DateScheduled(){
/*this.now = LocalDateTime.now();
this.nextDay = LocalDateTime.now()
.withHour(00)
.withMinute(0)
.withSecond(1)
.withNano(0);
scheduledExecutorService.scheduleAtFixedRate(
() -> { notifyObserversOfDayChange(); },
now.until(nextDay, ChronoUnit.MILLIS),
TimeUnit.DAYS.toMillis(1),
TimeUnit.MILLISECONDS
);*/
this.scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledExecutorService.scheduleAtFixedRate(
() -> { notifyObserversOfDayChange(); },
10000,
TimeUnit.DAYS.toMillis(1),
TimeUnit.MILLISECONDS
);
this.dateObservers = new ArrayList<>();
}
@Override @Lock(LockType.WRITE)
public void registerObserver(final NextDayObserver dateObserver){
if(dateObservers.indexOf(dateObserver) < 0){
dateObservers.add(dateObserver);
}
}
@Override @Lock(LockType.WRITE)
public void removeObserver(final NextDayObserver dateObserver){
dateObservers.remove(dateObserver);
}
@Override
public void notifyObserversOfDayChange(){
dateObservers.forEach(
dateObserver -> { dateObserver.onDayChange(); }
);
}
}
支持 Bean:
@Named @ApplicationScoped
public class MainTemplateMB extends BaseManagedBean implements Serializable, NextDayObserver{
private static final long serialVersionUID = 1L;
// Other member variables
private String currentDate;
@EJB
protected NextDayObservable nextDayObservable;
@Inject @Push
private PushContext pushContext;
// Other member variables
public MainTemplateMB(){
// Other Initializations
this.currentDate = "";
}
@PostConstruct
private void initialization(){
// Other Initializations
nextDayObservable.registerObserver(this);
currentDate = DateUtility.getCurrentYear() + "." + (DateUtility.getCurrentMonth() -1) + "." + DateUtility.getCurrentDay() + "." + DateUtility.getMonthFirstDay()+ "." + DateUtility.getLastMonthMaximumDays();
}
// Other Methods
@Override
public void onDayChange(){
// currentDate has changed for testing
currentDate = DateUtility.getCurrentYear() + "." + ( DateUtility.getCurrentMonth() + 1 ) + "." + DateUtility.getCurrentDay() + "." + DateUtility.getMonthFirstDay()+ "." + DateUtility.getLastMonthMaximumDays();
pushContext.send("dayChange");
}
}
MainTemplate.xhtml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:jsf="http://xmlns.jcp.org/jsf"
xmlns:jsfc="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
lang="#{sessionTools.language}" xml:lang="#{sessionTools.language}">
<jsfc:view locale="#{sessionTools.locale}" contentType="text/html">
<head>
.
.
.
</head>
<body>
<div id="wrapper">
.
.
.
<section jsf:id="accommodationSearchFields" data-currentDate="#{mainTemplateMB.currentDate}">
<form jsf:id="accommodationSearchForm" method="GET" autocomplete="off">
.
.
.
<input class="button field roundedCorners4" type="submit" value="#{mainTemplateProp.search}" jsf:action="#{mainTemplateMB.goToTheCity()}" />
<!-- <input class="button field roundedCorners4" type="submit" value="#{mainTemplateProp.search}" jsf:action="#{mainTemplateMB.onDayChange()}">
<jsfc:ajax />
</input> -->
.
.
.
</form>
</section>
.
.
.
</div>
<form jsf:id="dayChangeWebSocket">
<jsfc:websocket channel="pushContext">
<jsfc:ajax event="dayChange" render=":accommodationSearchFields" />
</jsfc:websocket>
</form>
</body>
</jsfc:view>
</html>
切换到 JEE 观察者模式后:
EJB Bean:
@Singleton @Startup @Lock(LockType.READ)
public class DateScheduled{
// Other member variables
private final ScheduledExecutorService scheduledExecutorService;
@Inject
private BeanManager beanManager;
public DateScheduled(){
/*this.now = LocalDateTime.now();
this.nextDay = LocalDateTime.now()
.withHour(00)
.withMinute(0)
.withSecond(1)
.withNano(0);
scheduledExecutorService.scheduleAtFixedRate(
() -> { notifyObserversOfDayChange(); },
now.until(nextDay, ChronoUnit.MILLIS),
TimeUnit.DAYS.toMillis(1),
TimeUnit.MILLISECONDS
);*/
this.scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledExecutorService.scheduleAtFixedRate(
() -> { notifyObserversOfDayChange(); },
60000,
TimeUnit.DAYS.toMillis(1),
TimeUnit.MILLISECONDS
);
}
public void notifyObserversOfDayChange(){
beanManager.fireEvent("Hello");
}
}
支持 Bean:
@Named @ApplicationScoped
public class MainTemplateMB extends BaseManagedBean implements Serializable{
private static final long serialVersionUID = 1L;
// Other member variables
private String currentDate;
@Inject @Push
private PushContext pushContext;
// Other member variables
public MainTemplateMB(){
// Other Initializations
this.currentDate = "";
}
@PostConstruct
private void initialization(){
// Other Initializations
currentDate = DateUtility.getCurrentYear() + "." + (DateUtility.getCurrentMonth() -1) + "." + DateUtility.getCurrentDay() + "." + DateUtility.getMonthFirstDay()+ "." + DateUtility.getLastMonthMaximumDays();
}
// Other Methods
public void onDayChange(@Observes String message){
// currentDate has changed for testing
currentDate = DateUtility.getCurrentYear() + "." + ( DateUtility.getCurrentMonth() + 1 ) + "." + DateUtility.getCurrentDay() + "." + DateUtility.getMonthFirstDay()+ "." + DateUtility.getLastMonthMaximumDays();
pushContext.send("dayChange");
}
}
工作工具:
。 Apache TomEE Plus 8.0.3
。阿帕奇 NetBeans IDE 12.0
问题:
- 我是不是有什么问题?
- 有什么问题?
- 如何解决问题?
我解决了问题。
当我将 onopen 客户端事件添加到 <f:websocket>
时,我意识到套接字没有打开。我在搜索时遇到了这个很好的答案:.
原因编号 8:
If you're using Ajax via JSF 2.x
<f:ajax>
or e.g. PrimeFaces<p:commandXxx>
, make sure that you have a<h:head>
in the master template instead of the<head>
. Otherwise JSF won't be able to auto-include the necessary JavaScript files which contains the Ajax functions. This would result in a JavaScript error like "mojarra is not defined" or "PrimeFaces is not defined" in browser's JS console.
现在我明白我必须使用
但我不明白为什么单击命令按钮有效但调用观察者方法却无效?鉴于我在控制台中没有看到任何 JavaScript 错误。