Einsatz von AJAX im täglichen Betrieb des Hotelreservierungssystems myRES 2006

Einchecken
Kommentare

Es gibt bereits viel Hype und zahlreiche theoretische Erörterungen um die viel gepriesene AJAX-Technologie. Doch wie wird die Technik tatsächlich genutzt? Fat Clients in Form von AJAX-gestützten Web Clients haben sich neben Technologien wie Java-Applets etabliert und sind State of the Art. In diesem Artikel wird dargestellt, wie man sich auf einfache Weise AJAX-Technologien in der Praxis zunutze machen kann, und wie die Technik in einem Produkt, das täglich von Hoteliers weltweit eingesetzt wird, tatsächlich zum Einsatz kommt. Ebenso wird gezeigt, wie durch den Einsatz von AJAX die Trennung von Businesslogik und Darstellung erreicht und trotzdem ein schneller, sich lebendig anfühlender Web Client geschaffen wurde.

Über das Reservierungssystem myRES 2006 kann der Hotelier für die Online-Buchungsplattform hotel.de die Preise und Verfügbarkeiten der Zimmer seines Hotels pflegen. Er kann u.a. erlaubte Anreisetage und Messetage bestimmen sowie Zimmer und Raten für bestimmte Tage sperren. Die Anzeige erfolgt in Form von Jahres- und Monatsübersichten, die sich je nach angezeigten Details durchaus komplex gestalten können. Um die technischen Voraussetzungen aufseiten des Hoteliers möglichst gering zu gestalten, wurde ein Rich Client unter Verwendung von AJAX-Technologien erstellt, der die komplexe Oberfläche ohne weitere Installationsmaßnahmen aufseiten des Hoteliers zur Verfügung stellt.

Der im System zu betrachtende Zeitraum beträgt bis zu zwei Jahre, typischerweise pflegt der Hotelier zwei bis vier Zimmertypen mit verschiedensten Ratentypen. Die anzuzeigende Datenmenge kann also sehr umfangreich werden. Daher können bestimmte Daten bei Bedarf ein- oder ausgeblendet werden. Dies geschieht mithilfe von DIV-Blöcken. Es wurde bald davon abgesehen, sämtliche Daten initial zu laden, da dies den Aufbau der Seite auf Zeiten jenseits einer Minute verzögert hätte. Ursachen hierfür liegen in der großen Datenmenge, aber auch die Render-Engine des Browsers ist ein begrenzender Faktor – eine Schwäche, die alle browsergestützten Clients derzeit noch gemein haben. Des Weiteren ist die Auswahl der anzuzeigenden Preise pro Zimmertyp und Rate  nicht trivial, insbesondere wenn preislich meist deutlich teurer gestaltete Messezeiträume mit beachtet werden müssen. Ein initiales Laden aller möglichen Messeraten würde die Darstellungszeit überdies weiter negativ beeinflussen. Aufseiten der Businesslogik lässt sich am besten entscheiden, welche Daten relevant sind und aktuell zur Anzeige gebracht werden. Daher ist eine strikte Trennung von Logik und Anzeige nicht nur hilfreich, sondern unabdingbar. Der Client kann und soll an dieser Stelle nicht entscheiden, welche Daten er gerne vom Server nachladen würde: Messe- oder Standardrate. Dies ist ein typisches Beispiel für die Notwendigkeit einer strikten Trennung der verschiedenen Schichten.

Struktur des Web Clients

Die in der Einleitung beschriebene Pflege des Hotels beginnt mit der Navigation, dem Steuerungsmechanismus der Anwendung. Klassisch (wie in bekannten Softwareprodukten) findet sich die Navigation als Baumdarstellung auf der linken Seite und löst bei entsprechender Interaktion des Benutzers eine Änderung im Hauptfenster auf der rechten Seite aus, nachfolgend auch Content-Bereich genannt (Abbildung 1).

Abb. 1: Reservierungssystem myRES 2006

Der Aufbau der Navigation ist in zwei Bereiche unterteilt:

  • B1: Zeitraum: Monate vom Beginn des aktuellen Jahres bis zum Ende des übernächsten Jahres sind auswählbar
  • B2: Zimmer/Raten(-details): Kontingente aller Zimmer, Preise und Detailinformationen aller Raten (Verpflegung, Anreisetag etc.) sind auswählbar

Die Kombination der beiden Navigationsbereiche (B1 und B2) lösen eine Änderung im Content-Bereich aus. Dazu ein Kombinationsbeispiel: Einzelzimmer(EZ)-Kontingente und Preise der Rate sowie Frist der möglichen Stornierung in Tagen, Verpflegungsart und erlaubter Anreisetag sollen für den Monat Februar im Jahr 2007 kombiniert werden. Würde man jetzt noch dazu den Januar aus B1 anwählen, wird oberhalb des Februars zusätzlich die Information des Einzelzimmers mit Raten und Details für den gesamten Januar eingeblendet. Würde man anschließend noch das Doppelzimmer in B2 auswählen, ergibt sich sowohl für den Januar als auch für den Februar die Anzeige der Kontingente des Doppelzimmers. Somit lassen sich auf einfache Weise alle möglichen Varianten für die Pflege des Hotels zusammenstellen. Die Anzeige ist ein Kreuzprodukt aus den angewählten Elementen aus B1 und B2. Wird z.B. der Knoten „nächste 12 Monate“ ausgewählt, erscheinen diese nacheinander im Content-Bereich ab dem aktuellen Monat. Wählt man dazu noch das Einzelzimmer, erscheint dieses, ebenfalls 12-mal, unterhalb des jeweiligen Monats.

AJAX kommt ins Spiel

Wird bei der Kombination der beiden Navigationsbereiche (B1 und B2) ein Content-Block zur Ansicht angefordert, wird die AJAX-Engine auf den Plan gerufen. Clientseitiges JavaScript sorgt für die Aufbereitung der in der Navigation angeforderten Elemente. Die in der Navigation anwählbaren Elemente besitzen je einen Schlüssel, der in Kombination (B1-Element + B2-Element) ein Element (DIV-Block) im Content-Bereich referenziert. Auf unser Beispiel bezogen sieht das wie folgt aus: der Schlüssel für das Navigationselement B1 setzt sich aus dem Februar 2007 zusammen. Dieser Schlüssel wird in der ID des Span-Elements abgelegt:

[Checkbox] Februar

Ebenso besitzen die Elemente in B2 einen Schlüssel für die Identifizierung:

EZ_BP (BP)

Zusammen ergibt dies dann die ID des DIV-Elements auf der Content-Seite:

Nachdem durch die Zusammensetzung der Schlüssel von B1 und B2 die im Content-Bereich anzuzeigenden Elemente bestimmt wurden, müssen jetzt auch die entsprechenden Anfragen an den Server gestellt werden.

Jeder Klick auf Navigations-Elemente sorgt für eine Berechnung der Schlüssel der angeforderten bzw. abgewählten Elemente durch die Content-Engine. Jedes ermittelte Block-Element, das zur Anzeige gebracht werden soll, wird von einem Objekt gesteuert. Dieses sorgt für den Server-Request und hängt das Ergebnis des Requests in den DOM-Baum des bestehenden Content-Bereichs ein. Folgende JavaScript-Methode sorgt für diesen Aufruf:

function GetMyHTML(serverPageURL, objID) {
  var req = new DataRequestor();
  req.setObjToReplace(objID);
  req.addArg(_GET, "key", objID);
  ...
  req.getURL(serverPageURL);
}

GetMyHTML verwendet zwei Parameter: ServerPageUrl und objID. ServerPageURL ist die ASPX-Seite, die für die entsprechenden Inhalte der DIV-Blöcke sorgt. objID ist die ID des (leeren) DIV-Blocks, der den Inhalt abbilden soll. Die in dem GetMyHTML-Aufruf verwendeten Objekt-Methoden werden im Zuge des in Listing 2 abgebildeten DataRequestor-Objekts erläutert. Das DataRequestor-Objekt erstellt bei Instanziierung ein neues XMLHttp-Objekt und stellt Methoden zum Anfordern und Einbinden von Webseiten zur Verfügung. Als Instanz steht hier je nach verwendetem Browser entweder das XMLHttpRequest-Objekt der Mozilla-ähnlichen Browser zur Verfügung oder das MSXML.XMLHttp-Objekt des Internet Exporer.

Listing 1
-------------------------------------------------------------------
function DataRequestor() {
    var self = this;
    this.getXMLHTTP = function() {
        var xmlHTTP = null;
  ...
  try {
    xmlHTTP = new XMLHttpRequest();
  } catch (e) {
            try {
                xmlHTTP = new ActiveXObject("Msxml.XMLHTTP");
     ...
      }
  }
  ...
  self._XML_REQ =  xmlHTTP;
  return self._XML_REQ;
    }
  
    this.getURL = function(url) {
  ...
  self._XML_REQ.open('GET', url_AND_ParamString, true);
  ...
  self._XML_REQ.onreadystatechange = self.callback;
  ...
  self._XML_REQ.send(null);
    }
    
    this.callback = function() {
  if (self._XML_REQ.readyState == 4 && self._XML_REQ.status == 200) {
  var obj = self.getObjToReplace();
  ...
  // vereinfachtes Ersetzen/Einsetzen von DOM-Elementen
  obj.innerHTML = self._XML_REQ.responseText;
    }

    this.setObjToReplace(obj) {
  // das Object oder die ID des Objektes werden in einer Member-Variablen des
  // Requestor-Objektes gespeichert
  ...
    }

    this.getObjToReplace() {
  ...
  return objToReplace;
    }

    this.addArg = function(type, name, val) {
  // adds name and val to an argument array of the requestType type (GET,
  // POST,...)
  ...
    }

    ...	
}

Für unser Beispiel sind die in Listing 1 abgebildeten Methoden getURL(url) und callback() interessant. getURL(url) sorgt für den Request und verwendet dafür die vom XMLHttp-Objekt bereitgestellte Methode open(requestType, url + ParamString, true). Als requestType verwenden wir in unseren Beispielen GET und POST. url ist die serverseitige Adresse, und falls benötigt, wird ein String mit name/value-Paaren als Parameter angehängt (bei RequestType GET). Der dritte Parameter besitzt als Default den Wert true und steht für asynchrone Ausführung. Das hat zur Folge, dass die weitere Bearbeitung nicht blockiert wird. Die XMLHttp-Methode send() startet schließlich die Anfrage des Clients. Der Benutzer kann während der Transaktion weiter mit dem System interagieren, die Verarbeitung läuft im Hintergrund ab. Dies haben wir uns bei dem gesamten Aufbau aller anzuzeigenden Blöcke zunutze gemacht.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -