当我不使用任何 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

问题:

  1. 我是不是有什么问题?
  2. 有什么问题?
  3. 如何解决问题?

我解决了问题。

当我将 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 错误。