Skip to content


Wicket - Back Button zuverlässig erkennen

Die Entwicklung moderner Webanwendungen orientiert sich zunehmend am Interaktionsmodel wie es Desktopanwendungen bieten. Wicket unterstütz dabei erheblich, in dem z.B. der Einsatz von Ajax keine große Hürde mehr darstellt. Eine Interaktionsmöglichkeit ist Desktopanwendungen doch bisher eher fremd: der Back Button im Browser. Der Nutzer erwartet, dass er auf einen vorherigen Zustand zurück navigieren kann. Je komplexer die Webanwendung, desto aufwendiger war es mit anderen Frameworks, die Nutzererwartung auch in ein sinnvolles Anwendungsverhalten zu übertragen. Wicket bietet mit versionierten Seiten bereits eine gute Unterstützung, die einem Entwickler ermöglicht, die kleine "Zeitreise", die der Nutzer vornimmt, auf Anwendungsseite entsprechend abbilden zu können.

Trotzdem möchte man unter Umständen wissen, dass der Nutzer den Back Button betätigt hat, weil es vielleicht auch einen Rückschluss darauf zulässt, dass der Nutzer in der Anwendung nicht die richtige Interaktionsmöglichkeit gefunden hat (z.B. in einem Bestellvorgang doch nochmal die Anschrift ändern zu wollen).

Folgendes Beispiel ist eine Möglichkeit, zu erkennen, ob der Nutzer mit dem Browser vor und zurück navigiert hat. Dabei gibt es zwei Dinge zu beachten. Der erste Seitenaufruf darf nicht in einer Url enden, die den Konstruktor der Seite aufruft. Denn dann sieht das aus Anwendungssicht so aus, als ob der Nutzer erneut auf die Seite navigiert ist. Zum zweiten muss man den Browser dazu zwingen, die Seite in jedem Fall neu vom Server abzurufen.

Daher brauchen wir zu erst eine Sprungseite:

package de.wicketpraxis.web.blog.pages.questions.backbutton;

import org.apache.wicket.markup.html.WebPage;

public class BackButtonStartPage extends WebPage {

  public BackButtonStartPage() {
    setResponsePage(new BackButtonPage());
    setRedirect(true);
  }
}

Die Sprungseite ruft die eigentliche Seite auf. Außerdem ist der Aufruf von setRedirect() notwendig, damit nicht nur die neue Seite dargestellt wird, sondern sich auch die Url entsprechend ändert.

Die Seite mit der Erkennung der Button-Nutzung sieht dann wie folgt aus:

package de.wicketpraxis.web.blog.pages.questions.backbutton;

import java.util.Date;

import org.apache.wicket.MetaDataKey;
import org.apache.wicket.Session;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.protocol.http.WebResponse;

public class BackButtonPage extends WebPage {

  static final TimeStampKey KEY = new TimeStampKey();
  private long _pageInitTimeStamp;

  public BackButtonPage() {
    //setVersioned(true);

    _pageInitTimeStamp = new Date().getTime();
    setPageTimeStamp(_pageInitTimeStamp);

    add(new FeedbackPanel("feedback"));

    add(new Link<Void>("link") {

      @Override
      public void onClick() {
        setResponsePage(new BackButtonPage());
      }
    });
  }

  private static void setPageTimeStamp(long timeStamp) {
    Session.get().setMetaData(KEY, timeStamp);
  }

  @Override
  protected void onBeforeRender() {
    super.onBeforeRender();

    Long lastPageRendered = Session.get().getMetaData(KEY);
    setPageTimeStamp(_pageInitTimeStamp);

    if (lastPageRendered > _pageInitTimeStamp) {
      info("BackButton pressed");
    }
    if (lastPageRendered < _pageInitTimeStamp) {
      info("ForwardButton pressed");
    }
  }

  @Override
  protected void configureResponse() {
    super.configureResponse();
    WebResponse response = getWebRequestCycle().getWebResponse();
    response.setHeader("Cache-Control", "no-cache, max-age=0,must-revalidate, no-store");
  }

  static class TimeStampKey extends MetaDataKey<Long> {

  }
}

Das Markup der Seite:

<html>
  <head>
    <title>BackButton Page</title>
  </head>
  <body>
    <div wicket:id="feedback"></div>
    <a wicket:id="link">Link</a>
  </body>
</html>

Das Prinzip funktioniert wie folgt: Die Seite bekommt einen Zeitstempel über den Zeitpunkt der Erstellung. Dieser Zeitpunkt wird außerdem als Metainformation in die Session gesetzt (Hinweis: um diese Funktion bei mehr als einer Seite benutzen zu können, ist natürlich etwas mehr Aufwand nötig). Das bedeutet, dass jede Version der Seite einen eigenen Zeitstempel hat. In onBeforeRender() kann man nun prüfen, ob diese Seite auch die aktuelle Seite ist, oder ob der Nutzer auf einen neuere oder ältere Version zurückgegriffen hat. Der Link dient dazu, immer neue Version der Seite zu erzeugen.

Damit der Browser die Seite aber in jedem Fall neu lädt, muss man entsprechende Header in den Http-Response einfügen. Eine Möglichkeit besteht darin, die configureResponse()-Methode entsprechend zu überschreiben.

Wenn man nun auf der Seite den Link klickt und dann mit dem Back Button oder dem Forward Button navigiert, erscheinen die entsprechenden Hinweise auf der Seite.

Tags:

Veröffentlicht in Allgemein, Wicket, .