Dies ist eine überarbeitete/erneuerte Version von Schnellstart: PrimeFaces 8 mit JSF 2.3. Damals ging es noch um Java EE 8.
1. Einleitung
PrimeFaces ist mitunter das meistgenutzte Komponenten-Framework für Jakarta Faces Anwendungen. Ich zeige euch in diesem Artikel, wie ihr in wenigen Minuten eine JF-Anwendung nach Jakarta EE 10 Standard mit Maven erstellt, PrimeFaces einbindet und anschließend per Docker ausführt. Als Beispiel erzeugen wir eine ToDo-Liste, inklusive der Möglichkeit, ToDo’s hinzuzufügen und entfernen zu entfernen.
Den vollständigen Code findest du auf GitHub: https://github.com/MatthiasPischka/jakarta-ee-beispiele/tree/main/primefaces-schnellstart
2. Vorbereitung
Bevor wir uns um die eigentliche Implementierung kümmern können, sind einige Konfigurationen vorzunehmen.
pom.xml
<project ...> ... <artifactId>primefaces-schnellstart</artifactId> <packaging>war</packaging> <dependencies> <dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-api</artifactId> <version>10.0.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.primefaces</groupId> <artifactId>primefaces</artifactId> <version>14.0.6</version> <classifier>jakarta</classifier> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> </build> </project>
Über die pom.xml machen wir das Projekt zu einem Maven-Projekt und holen uns die benötigten Abhängigkeiten rein. Ich gebe gerne über finalName
den endgültigen Namen ohne Versionsangabe an, sodass dieser sich nicht im Laufe der Zeit ändert.
- jakarta.jakartaee-api: Diese Abhängigkeit wird für das Kompilieren benötigt, sie wird allerdings nicht in das war-Archiv eingepackt, da der verwendete Server die Implementierung mitbringt.
- primefaces: Das zu verwendende JF-Framework. Achtung: Wenn wir Jakarta verwenden, müssen wir hier den Classifier jakarta angeben, um PrimeFaces mit jakarta-Package-Struktur heranzuziehen.
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd" version="6.0"> <context-param> <param-name>jakarta.faces.PROJECT_STAGE</param-name> <param-value>Development</param-value> </context-param> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>jakarta.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.xhtml</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.xhtml</welcome-file> </welcome-file-list> </web-app>
Hierbei handelt es sich um eine kurz gehaltene, für Jakarta Faces benötigte, web.xml
. Auf PrimeFaces bezogen ist hier nichts zu finden. Per Standard wird das Theme saga
verwendet. Hier könntest du aber auch explizit ein anderes THEME angeben. Eine Übersicht aller Themes findest du hier.
faces-config.xml
<?xml version='1.0' encoding='UTF-8'?> <faces-config version="4.0" xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-facesconfig_4_0.xsd"> </faces-config>
Die für Jakarta Faces 4.0 vorgesehene (leere) faces-config.xml
. Diese kann eigentlich weggelassen werden, wenn stattdessen eine Bean zur Konfiguration mit @FacesConfig
versehen wird. Allerdings kann es aus meiner Sicht nicht schaden die faces-config.xml
an gewohnter Stelle vorzufinden.
beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd"> </beans>
Über die beans.xml
geben wir an, dass wir in der Laufzeitumgebung von einer CDI 4.0 Implementierung ausgehen. Per Standard werden nur entsprechend annotierte Klassen zu CDI-Beans. Wenn es anders gewünscht wäre, müssten wir das Verhalten mit einer expliziten Angabe von bean-discovery-mode="all"
anpassen.
3. Implementierung
Model
Zur technischen Darstellung der ToDo’s legen wir eine simple Klasse an, die lediglich den Titel enthält. Des Weiteren fügen wir eine ID mit Hilfe von java.util.UUID
hinzu, um die Instanzen auseinanderhalten zu können.
public class ToDo implements Serializable { private final String id; private final String titel; public ToDo(String titel) { this.id = UUID.randomUUID().toString(); this.titel = titel; } public String getId() { return id; } public String getTitel() { return titel; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ToDo toDo = (ToDo) o; return Objects.equals(id, toDo.id); } @Override public int hashCode() { return Objects.hashCode(id); } }
View
<!DOCTYPE html> <html lang="de" xmlns="http://www.w3.org/1999/xhtml" xmlns:h="jakarta.faces.html" xmlns:p="http://primefaces.org/ui"> <h:head> <title>PrimeFaces Schnellstart</title> </h:head> <h:body> <h1>ToDo Verwaltung</h1> <h:form id="form_index"> <h2>Anlegen</h2> <h:panelGrid columns="2"> <p:outputLabel for="todo" value="ToDo:"/> <p:inputText id="todo" value="#{toDoVerwaltungController.toDoNeu}"/> </h:panelGrid> <p:commandButton value="Anlegen" action="#{toDoVerwaltungController.anlegen}" update="@form"/> <h2>Abhaken</h2> <p:dataTable id="todos" var="todo" value="#{toDoVerwaltungController.toDos}" selection="#{toDoVerwaltungController.toDosErledigt}" rowKey="#{todo.id}" emptyMessage="Keine ToDos vorhanden"> <p:column selectionBox="true" style="width:16px;text-align:center"/> <p:column headerText="Titel"> <h:outputText value="#{todo.titel}"/> </p:column> </p:dataTable> <p> <p:commandButton value="Löschen" action="#{toDoVerwaltungController.loeschen}" update="@form"/> </p> </h:form> </h:body> </html>
Der vorangegangene Code-Abschnitt zeigt die gesamte index.xhtml
. Das ist alles, was wir benötigen, um die oben gezeigte Darstellung der Anwendung zu erreichen. Die PrimeFaces-spezifischen Zeilen beginnen jeweils mit <p:
. Bitte achte auch auf die Verwendung der neuen Jakarta Namespaces (hier z.B. xmlns:h="jakarta.faces.html"
)
Im ersten Abschnitt wird ein Eingabefeld, welches an die Instanzvariable toDoNeu
des ToDoVerwaltungController
s gebunden wird, gerendert. Es erhält zusätzlich ein Label.
Im zweiten Abschnitt verwenden wir eine Tabelle von PrimeFaces, um zum einen die angelegten ToDo’s anzuzeigen und zum anderen diese auswählbar zu machen. Dazu bietet die PrimeFaces-Tabelle die Möglichkeit, eine Collection anzubinden (selection
), die die markierten ToDo’s vorhält.
In beiden Fällen wird jeweils ein CommandButton
verwendet, der zum Aufruf einer Controller-Methode dient und im Anschluss das gesamte Formular (update="@form"
) neu rendert.
Controller
@Named @ViewScoped public class ToDoVerwaltungController implements Serializable { private List<ToDo> toDos; private List<ToDo> toDosErledigt; private String toDoNeu; @PostConstruct private void init() { this.toDos = new ArrayList<>(); this.toDos.add(new ToDo("Testen")); this.toDos.add(new ToDo("Dokumentieren")); } public void anlegen() { this.toDos.add(new ToDo(this.toDoNeu)); this.toDoNeu = ""; } public void loeschen() { this.toDosErledigt.forEach(this.toDos::remove); } // Getter und Setter }
Der Controller enthält die Steuerung für die zuvor gezeigte View. Dieser ist recht simpel gehalten. Die drei Instanzvariablen haben wir bereits bei der View gesehen:
- toDos: Liste der aktuell angelegten ToDo’s, die in der DataTable von PrimeFaces dargestellt werden.
- toDosErledigt: Enthält die in der Tabelle selektierten ToDo’s.
- toDoNeu: Ist an das Eingabefeld zur Anlage eines neuen ToDo’s gebunden.
Neben den hier nicht gezeigten Getter und Setter besteht der Controller aus den drei folgenden Methoden:
- init: Wird über
@PostConstruct
beim initialen Aufruf der View ausgeführt und legt Beispieldaten an, sodass bereits ToDo’s vorhanden sind. - anlegen: Entnimmt der Variable
toDoNeu
die Zeichenkette und erzeugt damit ein neues ToDo. - loeschen: Löscht alle ToDo’s aus
toDos
, die zuvor auch intoDosErledigt
abgelegt wurden.
4. Ausführen mit Docker
Ich nutze den WildFly Application Server zur Ausführung von Jakarta EE Anwendungen. Dieser lässt sich optimal in einem Docker Container verpacken und mit dem war-File der Anwendung versorgen. Hierzu enthält das vollständige Beispiel auf GitHub einen Ordner Docker. Dieser enthält das benötigte Dockerfile sowie Shell-Skripte zum Bauen der Anwendung per Maven, Bauen des Images inklusive war-File per Docker und Starten des Docker-Containers.
0 Kommentare