home  |  suche  |  kontakt/johner  |  institut 
studierende  |  tech-docs  |  mindmailer 

Übersicht

Unsere kleine Beispielanwendung besteht aus drei Bildschirmseiten:

     

  • Anmeldung: Wenn man sich erfolgreich anmeldet, wird man auf die Hauptseite weitergeleitet
  • Hauptseite: Hier sieht man alle Autos eines Fuhrparks und kann Autos löschen
  • Detailseite: Auf dieser Seite kann man ein neues Fahrzeug anlegen

Bitte beachten Sie bei diesem Beispiel auch:

     

  • Notwendige Jar-Dateien
  • Dateistruktur
  • Das in web.xml definierte FacesServlet
  • Position von faces-config.xml, Messages, Jsp-Seiten
  • die Tatsache, dass die JSF-Dateien eine Dateiendung *.jsp haben

Zwischen den drei Seiten kann wie folgt navigiert werden:

Architektur

Möchte man diese kleine Anwendung mit JSF realisieren, so ergibt sich die unten dargestellte Architektur:

     

  • JSF, JSP: Diese Artefakte stellen den View dar. Sie werden als HTML-Seiten gerendert.
  • Backing-Bean: Diese Beans stellen die Daten und Methoden für die Views bereit. Diese Beans entsprechen also dem Model.
  • DTO: Die Datatransferobjects verbinden optional die Fassade mit den Backingbeans. Man setzt sie dann ein, wenn man komplexe Rückgabewerte von oder eine Vielzahl an Übergabeparametern an die Fassade hat.
  • Fassade (in unserem Fall die Klasse Fuhrpark): Sie verbirgt das komplexe Backend (Geschäftsklassen und Datenbank) vom Client (den Backingbeans).
  • Die Geschäftsklassen werden in diesem Beispiel durch Auto repräsentiert.
  • DAO: Falls die Inhalte der Geschäftsklassen persistieren will, so kann man mittels Data Access Objects zu Zugriff (z.B. Transaktionssteuerung) kapseln

Implementierung

Das komplette Beispielprojekt steht hier (Zip 1MB) zum Download zur Verfügung. Es beinhaltet nicht den Zugriff auf die Datenbank, also keine DAOs.

Im Folgenden werden nun die Artefakte beispielhaft erläutert.

main.jsp

Die Seite main.jsp besteht aus einer Tabelle mit drei Spalten. Besonders interessant sind hierbei:

     

  • dataTable: über #{main.autos} wird die Methode getAutos() auf der Klasse MainBackingBean aufgerufen. var="auto" definiert hierbei die Laufvariable, auf die in den Spalten zugegriffen wird.
  • Der Link löschen hat als action "loeschen", weshalb auf dem MainBackingBean die Methode "loeschen" aufgerufen wird. Als Parameter wird das Kennzeichen genutzt. Dieser Parameter wird in dieser Methode abgefragt.
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> 
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<html>
<head>
 <link rel="stylesheet" href="style.css">
 <title>Uebersicht</title>
</head>
 <body>
  <f:view>
   <f:loadBundle basename="jsf.Messages" var="messages"/>
   <h1>Übersicht</h1>
   <h:panelGrid border="1" columns="1" cellpadding="5" bgcolor="lightgreen">
    <h:dataTable value="#{main.autos}" var="auto" id="Autotabelle" border="1" cellpadding="5" bgcolor="lightblue">
     <h:column id="SpalteKennzeichen">
      <f:facet name="header"><h:outputText value="#{messages.kennzeichen}"/></f:facet>
      <h:outputText value="#{auto.kennzeichen}"/>
     </h:column>
     <h:column id="SpalteTyp">
      <f:facet name="header"><h:outputText value="#{messages.typ}"/></f:facet>
      <h:outputText value="#{auto.typ}"/>
     </h:column>
     <h:column id="SpalteLoeschen">
      <f:facet name="header"><h:outputText value="-"/></f:facet>
      <h:form>
       <h:commandLink action="#{main.loeschen}">
        <h:outputText value="loeschen"/>
        <f:param name="kennzeichen" value="#{auto.kennzeichen}"/>
       </h:commandLink>
      </h:form>
     </h:column>
    </h:dataTable>
   </h:panelGrid>
   <h:panelGrid border="1" columns="2"  columnClasses="td">
    <f:subview id="abmelden">
      <jsp:include page="abmelden.jsp"/>
    </f:subview>
    <h:form>
     <h:commandButton value="#{messages.neuesauto}" action="weiter"/>
    </h:form>
   </h:panelGrid>
  </f:view>
 </body>
</html>

 

 

MainBackingBean

Dieses BackingBean greift auf die Fassade, den Fuhrpark zu, welcher während des Logins in der HttpSession gespeichert wurde.

Weiter interessant ist, wie auf den Parameter "kennzeichen" während des Löschens zugegriffen wird.

package jsf;

import java.util.Collection;
import java.util.Vector;

import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpSession;

import backend.AutoDTO;
import backend.Fuhrpark;


public class MainBackingBean {
  private String loginName;
  private ExternalContext context;
  private Fuhrpark fuhrpark;
  
  public MainBackingBean() throws Exception{
    context = FacesContext.getCurrentInstance().getExternalContext();
    HttpSession session = (HttpSession)context.getSession(false);
    loginName = (String)context.getRequestParameterMap().get("login:user");
    session.setAttribute("loginName", loginName);
    fuhrpark = (Fuhrpark)session.getAttribute("fuhrpark");
    //hier optional prüfen der Benutzerberechtigung
  }
  
  public String loeschen() {
    String kennzeichen = (String)context.getRequestParameterMap().get("kennzeichen");
    fuhrpark.autoLoeschen(kennzeichen);
    return "main";
  }
  

  public Collection<AutoDTO> getAutos() {
    return fuhrpark.getAutoDTOs();
  }

}

faces-config.xml

In der Konfigurationsdatei wird festgelegt wie

     

  • die Übersetzungdateien (Ressource Bundles) geladen werden
  • die View (*.jsp) mit dem Model (BackingBean) verbunden sind
  • die Navigation von einer Seite zu nächsten stattfindet. Z.B. sieht man, dass man von der Seite login.jsp auf main.jsp weitergeleitet wird, wenn der Rückgabewert einer Methode auf LoginBackingBean "gueltig" ist (fett).
<?xml version='1.0' encoding='UTF-8'?>
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE faces-config PUBLIC
  "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
  "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config>
 <!-- i18n -->
 <application>
  <message-bundle>org.johner.jsftest.Messages</message-bundle>
  <locale-config>
   <default-locale>de</default-locale>
   <supported-locale>en</supported-locale>
  </locale-config>
 </application>

 

 

 

 

 

 <!-- Managed Beans -->
 <managed-bean>
  <managed-bean-name>login</managed-bean-name>
  <managed-bean-class>jsf.LoginBackingBean</managed-bean-class>
  <managed-bean-scope>session</managed-bean-scope>
 </managed-bean>
 <managed-bean>
  <managed-bean-name>main</managed-bean-name>
  <managed-bean-class>jsf.MainBackingBean</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
 </managed-bean>
 <managed-bean>
  <managed-bean-name>detail</managed-bean-name>
  <managed-bean-class>jsf.DetailsBackingBean</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
 </managed-bean>
 
 <!-- Navigation -->
 <navigation-rule>
  <from-view-id>/login.jsp</from-view-id>
  <navigation-case>
   <from-outcome>gueltig</from-outcome>
   <to-view-id>/main.jsp</to-view-id>
  </navigation-case>
  <navigation-case>
   <from-outcome>ungueltig</from-outcome>
   <to-view-id>/login.jsp</to-view-id>
  </navigation-case>
 </navigation-rule>

 

 

 <navigation-rule>
  <from-view-id>/main.jsp</from-view-id>
  <navigation-case>
   <from-outcome>weiter</from-outcome>
   <to-view-id>/detail.jsp</to-view-id>
  </navigation-case>
  <navigation-case>
   <from-outcome>zurueck</from-outcome>
   <to-view-id>/login.jsp</to-view-id>
  </navigation-case>
  <navigation-case>
   <from-outcome>loeschen</from-outcome>
   <to-view-id>/login.jsp</to-view-id>
  </navigation-case>
 </navigation-rule>

 

 

 <navigation-rule>
  <from-view-id>/detail.jsp</from-view-id>
  <navigation-case>
   <from-outcome>main</from-outcome>
   <to-view-id>/main.jsp</to-view-id>
  </navigation-case>
 </navigation-rule>

 

 

 <navigation-rule>
  <from-view-id>*</from-view-id>
  <navigation-case>
   <from-outcome>abmelden</from-outcome>
   <to-view-id>/login.jsp</to-view-id>
  </navigation-case>
 </navigation-rule>

 

 

</faces-config>

 

 

Fassade

Die Klasse Fuhrpark stellt die Fassade dar. Abgesehen von den DTOs gibt sie nach außen keine komplexe Datentypen an und gibt auch keine solchen zurück. Sie verbirgt die konkrete Geschäftsklasse Auto.

package backend;

import java.util.Collection;
import java.util.HashSet;
import java.util.Vector;

public class Fuhrpark {
  private Collection<Auto> autos = new HashSet<Auto>();
  
  public Fuhrpark() {
    Auto auto1 = new Auto("KN-M1""Maybach");
    Auto auto2 = new Auto("KN-AM-9999""Aston Martin");
    Auto auto3 = new Auto("KN-LO-3""VW Lupo");
    
    autos.add(auto1);
    autos.add(auto2);
    autos.add(auto3);
  }
  
  public void autoLoeschen(String kennzeichen) {
    System.out.println("Fuhrpark: Lösche Auto mit Kennzeichen");
    Auto auto = getAuto(kennzeichen);
    if (null != auto) {
      autos.remove(auto);
    }
  }
  
  public void autoHinzufuegen(String kennzeichen, String typ) {
    System.out.println("Fuhrpark: Neues Auto mit Kennzeichen " + kennzeichen + " und Typ "+ typ);
    Auto auto = new Auto(kennzeichen, typ);
    autos.add(auto);
  }
  
  public Collection<AutoDTO> getAutoDTOs() {
    Collection<AutoDTO> autoDTOs = new Vector<AutoDTO>();
    for (Auto auto: autos) {
      AutoDTO autoDTO = new AutoDTO(auto.getKennzeichen(), auto.getName());
      autoDTOs.add(autoDTO);
    }
    System.out.println("Fuhrpark: Gebe Collection aus " + autoDTOs.size() " Elementen zurück");
    return autoDTOs;
  }
  
  
//  public AutoDTO getAutoDTO(String kennzeichen) {
//    AutoDTO autoDTO = null;
//    Auto auto = getAuto(kennzeichen);
//    if (null != auto) {
//      autoDTO = new AutoDTO(auto.getKennzeichen(), auto.getName());
//    }
//    return autoDTO;
//  }
  
  private Auto getAuto(String kennzeichen) {
    System.out.print("Fuhrpark: suche Auto mit Kennzeichen " + kennzeichen);
    for(Auto auto: autos) {
      if (auto.getKennzeichen().equals(kennzeichen)) {
        System.out.println(" gefunden");
        return auto;
      }
      System.out.println(" nicht gefunden");
    }
    return null;
  }
}