Zkoss:如何通知用户会话超时或丢失与服务器的连接?

时间:2015-03-02 01:50:52

标签: javascript session client-side zk

使用zkoss Web UI框架时,有没有一种方法检查会话超时或丢失连接?问题是,即使我关闭服务器,重新部署或重新启动它,UI仍将显示在浏览器中。

用户只有在尝试与用户界面进行互动时才会发现错误(例如点击按钮)。它会弹出会话超时信息或服务器无法访问的信息。

我正在寻找的是客户端上可以立即(或在合理的短时间内)通知用户的内容。当会话丢失,服务器出现故障或无法访问时,会出现一些弹出窗口,告诉用户出现问题(这样他就可以立即刷新或采取其他措施)。

我正在查看文档,但他们没有说明这个案例的具体内容。会话设置包括限制,保持活动以防止会话超时,但这就是它。

我正在考虑一些定期ping服务器的自定义javascript(可能是一个特殊的servlet,也可以让脚本知道会话超时),但我更喜欢zk框架的原生内容。当连接丢失时,zk计时器组件似乎停止运行,但它不会触发错误弹出。

1 个答案:

答案 0 :(得分:3)

我将发布tommorow代码,告诉你如何为所有登录的客户端分发消息。

同时,这里是代码,您可以实现在会话超时激活之前通知用户(不是服务器重启):

SessionTimeOutExecListener.java:

public class SessionTimeOutExecListener implements ExecutionInit, UiLifeCycle {

    private String timerId = "timeoutNotifyTimer";

    public void init(Execution exec, Execution parent) throws Exception {

        Timer timer = (Timer) exec.getDesktop().getAttribute(timerId);
        if (timer != null) {

            if (isSendbyMsgBox(timer, exec))
                return;

            timer.stop();
            timer.start();
        }
    }

    private boolean isSendbyMsgBox(Timer timer, Execution exec) {
        HttpServletRequest hreq = (HttpServletRequest)exec.getNativeRequest();

        for (int j = 0;; ++j) {
            final String uuid = hreq.getParameter("uuid_"+j);
            if (uuid == null)
                break;

            if (uuid.equals(timer.getUuid()))
                return true;
        }
        return false;
    }

    public void afterComponentAttached(Component comp, Page page) {
    }

    public void afterComponentDetached(Component comp, Page prevpage) {
    }

    public void afterComponentMoved(Component parent, Component child,
            Component prevparent) {
    }

    public void afterPageAttached(Page page, Desktop desktop) {
         Object obj = desktop.getAttribute(timerId);

        if (obj == null) {

            int tmout = desktop.getWebApp().getConfiguration()
                    .getSessionMaxInactiveInterval();

            final Timer timer = new Timer((tmout - 2) * 1000);

            timer.addEventListener(Events.ON_TIMER, new EventListener() {
                public void onEvent(Event event) throws Exception {

                    Messagebox.show("Your session are about to be expired",
                        "Information", Messagebox.OK,
                        Messagebox.INFORMATION, new EventListener() {

                            @Override
                            public void onEvent(Event event) throws Exception {
                                if (Messagebox.ON_OK.equals(event.getName())){
                                    timer.start();
                                }
                            }
                        });
                }
            });
            timer.setPage(page);
            desktop.setAttribute(timerId, timer);
            timer.start();
        }
    }

    public void afterPageDetached(Page page, Desktop prevdesktop) {
    }

}

zk.xml内:

<listener>
    <listener-class>test.MyExecListener</listener-class>
</listener>

编辑:

就像我说的,这是用于向所有活动会话发送消息的代码 首先是一个可以发送消息的简单页面。

message.zul:

<?xml version="1.0" encoding="UTF-8"?>
<window xmlns="http://www.zkoss.org/2005/zul" apply="org.zkoss.bind.BindComposer"
            viewModel="@id('vm') @init('be.chillworld.MessageVM')" width="100%" height="100%">
    <textbox value="@bind(vm.message)"/>
    <button onClick="@command('sendMessage')" label="Send"/>
</window>

正如您所看到的,它是MVVM但不用担心,您也可以在MVC项目中插入它,因为我使用EventQueue

然后我们需要一个所有页面的监听器,因此最佳做法是创建一个抽象VM或扩展您使用的Composer。

AbstractVM.java:

package be.chillworld;

import org.zkoss.bind.annotation.Init;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.EventQueues;
import org.zkoss.zk.ui.util.Clients;

/**
 *
 * @author chillworld
 */
public abstract class AbstractVM {

    @Init
    public void abstractInit() {
        EventQueues.lookup("globalMessage", EventQueues.APPLICATION, true).subscribe(new EventListener<Event>() {

            public void onEvent(Event event) throws Exception {
                if ("onSendMessage".equals(event.getName())) {
                    Clients.showNotification(String.valueOf(event.getData()));
                }
            }
        });
    }
}

因此,当我们得到活动时,这实际上就是我们要做的事情 如果你想制作一个基本的作曲家,你可以这样做:

BasicComposer.java:

package be.chillworld;

import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.EventQueues;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.util.Clients;

/**
 *
 * @author chillworld
 */
public class BasicComposer extends SelectorComposer<Component> {

    @Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
        EventQueues.lookup("globalMessage", EventQueues.APPLICATION, true).subscribe(new EventListener<Event>() {

            public void onEvent(Event event) throws Exception {
                if ("onSendMessage".equals(event.getName())) {
                    Clients.showNotification(String.valueOf(event.getData()));
                }
            }
        });
    }

}

不要忘记为每个视图延长BasicComposerAbstractVM 这就是为什么我问你是否使用pagetemplates,如果你有一个每个页面的主模板,你只需将它插入那里,每个页面都会有eventlistener的订阅,所以你不必使用{{1} }或BasicComposer

Oke,现在我们为message.zul创建了viewmodel。

MessageVM.java:

AbstractVM

正如您所看到的,我会扩展package be.chillworld; import org.zkoss.bind.annotation.Command; import org.zkoss.bind.annotation.Init; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventQueues; import org.zkoss.zk.ui.util.Clients; /** * * @author chillworld */ public class MessageVM extends AbstractVM { private String message; @Init(superclass = true) public void init(){} @Command public void sendMessage () { if (message==null || message.trim().isEmpty()) { Clients.showNotification("Please enter something to send."); } else { System.out.println("posting event"); EventQueues.lookup("globalMessage", EventQueues.APPLICATION, true).publish(new Event("onSendMessage", null, message)); } } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } ,但 1部分甚至非常重要然后只是扩展它,即AbstractVM
正如您所看到的,我再次声明了一个init方法,但我在注释中说@Init
如果我们不这样做,那么来自abstractVM的init方法永远不会被触发!

对于BasicComposer,它是不同的,如果您覆盖superclass = true方法,则始终调用doAfterCompose以便始终执行。

您可以在1台电脑上使用多个会话进行测试,如下所示:

  • 打开IE =&gt;转到message.zul
  • 私下打开IE =&gt;转到某个订阅了eventlistener的页面。
  • 打开FF =&gt;与私人IE相同。
  • 在文本框中输入消息,然后按“发送”。
  • 查看是否所有浏览器都收到了消息。 (如果您想确定,请将super放入String.valueOf(Sessions.getCurrent())

希望这可以帮助您解决问题。