9. Arbeiten mit einer Datenquelle
Hier wollen wir die Grundlagen für die Arbeit mit Datenbanken innerhalb einer Struts-Anwendung schaffen.
9.1. Die Struts-Anwendung /listarticles
Wir möchten den Inhalt einer Tabelle anzeigen, in der die Eigenschaften der von einem Geschäft verkauften Artikel gespeichert sind.
![]() |
|
Die Tabelle enthält Folgendes:

Die Anwendung „listarticles“ zeigt dieselben Informationen (wenn auch weniger elegant) auf einer Webseite an:

9.2. Konfiguration der Struts-Anwendung „/listarticles“
Die Datei „web.xml“ der Anwendung entspricht dem Standard:
web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<taglib>
<taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
</taglib>
</web-app>
Die Datei struts-config.xml enthält einen neuen Abschnitt <data-sources>, in dem Sie Datenquellen deklarieren und konfigurieren können:
struts-config.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<data-sources>
<data-source key="dbarticles">
<set-property property="driverClass" value="com.mysql.jdbc.Driver"></set-property>
<set-property property="url" value="jdbc:mysql://localhost/dbarticles"></set-property>
<set-property property="user" value="admarticles"></set-property>
<set-property property="password" value="mdparticles"></set-property>
<set-property property="minCount" value="2"></set-property>
<set-property property="maxCount" value="5"></set-property>
</data-source>
</data-sources>
<action-mappings>
<action path="/liste" type="istia.st.struts.articles.ListeArticlesAction">
<forward name="afficherListeArticles" path="/vues/listarticles.jsp"/>
<forward name="afficherErreurs" path="/vues/erreurs.jsp"/>
</action>
</action-mappings>
<message-resources parameter="istia.st.struts.articles.ApplicationResources"
null="false" />
</struts-config>
9.2.1. Datenquellen
Der Abschnitt <data-sources> dient zur Deklaration aller Datenquellen der Anwendung, die jeweils durch einen <data-source>-Abschnitt beschrieben werden. Dieses Tag unterstützt mehrere Attribute:
identifiziert die Datenquelle, wenn mehrere Quellen vorhanden sind. | |
Der Name der Klasse, die instanziiert werden soll, um auf die Datenbank zuzugreifen. Diese Klasse befindet sich in der Regel in einer vom DBMS-Anbieter bereitgestellten Klassenbibliothek (.jar). Diese Bibliothek enthält den JDBC-Treiber für den Datenbankzugriff. Die Eigenschaft driverClass gibt diesen Treiber an. Die .jar-Datei mit den DBMS-Zugriffsklassen wird im Ordner WEB-INF/lib der Anwendung abgelegt. | |
Verbindungszeichenfolge zu einer bestimmten Datenbank. Der JDBC-Treiber ermöglicht den Zugriff auf alle vom DBMS verwalteten Datenbanken. Über die Eigenschaft „url“ können wir festlegen, welche davon verwendet werden soll. | |
Der Datenbankzugriff ist geschützt. Das DBMS verwaltet Benutzer, die durch einen Benutzernamen und ein Passwort identifiziert werden. Diese werden in den Attributen „user“ und „password“ des Tags angegeben. | |
Struts verwaltet einen Pool von Verbindungen zum DBMS. Das Öffnen einer Verbindung zu einem DBMS ist ein ressourcenintensiver Vorgang, was Zeit und Speicher betrifft. Anstatt für jede an die Anwendung gerichtete Anfrage eine Verbindung zum DBMS zu öffnen und zu schließen, verwaltet die Anwendung einen Pool von n Verbindungen, wobei n im Bereich [minCount, maxCount] liegt. Wenn die Anwendung während einer Anfrage eine Verbindung benötigt: - versucht sie, eine aus dem Verbindungspool zu beziehen. Wenn sie eine freie Verbindung findet, nutzt sie diese. - Wenn keine freien Verbindungen im Pool vorhanden sind und weniger als maxCount Verbindungen im Pool vorhanden sind, wird eine neue Verbindung geöffnet und dem Pool hinzugefügt. Die aktuelle Abfrage kann diese nutzen. - Wenn keine freien Verbindungen vorhanden sind und keine neue Verbindung erstellt werden kann, wird die Anfrage in die Warteschlange gestellt. Wenn die aktuelle Anfrage die Verbindung schließt, wird diese nicht tatsächlich geschlossen, sondern an den Pool zurückgegeben. |
Hier haben wir die folgenden Eigenschaften:
dbarticles – dies ist der Name, unter dem die Datenquelle im Anwendungskontext bekannt sein wird | |
com.mysql.jdbc.Driver. Wir verwenden eine MySQL-Datenbank. | |
jdbc:mysql://localhost/dbarticles. Die Datenbank heißt dbarticles und befindet sich auf dem lokalen Rechner. | |
admarticles, mdparticles. Diesem Benutzer wurden alle Berechtigungen für die Datenbank dbarticles erteilt. | |
2, 5. Mindestens 2 Verbindungen im Pool, höchstens 5. |
9.2.2. Aktionen
Die in der Struts-Konfigurationsdatei deklarierten Aktionen lauten wie folgt:
<action-mappings>
<action path="/liste" type="istia.st.struts.articles.ListeArticlesAction">
<forward name="afficherListeArticles" path="/vues/listarticles.jsp"/>
<forward name="afficherErreurs" path="/vues/erreurs.jsp"/>
</action>
</action-mappings>
Die einzige Aktion heißt /list und ist der Klasse istia.st.struts.articles.ListeArticlesAction zugeordnet. Diese Aktion endet mit der Anzeige:
- die Artikelseite (/vues/listarticles.jsp)
- die Fehlerseite (/views/errors.jsp)
9.2.3. Die Meldungsdatei
Die Meldungsdatei ApplicationResources.properties wird im Ordner WEB-INF/classes/istia/st/struts/articles abgelegt. Ihr Inhalt lautet wie folgt:
# erreurs
errors.header=<ul>
errors.footer=</ul>
erreur.dbarticles=<li>Erreur d'accès à la base des articles ({0})</li>
Es kann nur ein Fehler auftreten: ein Datenbankzugriffsfehler. Tatsächlich gibt es mehrere mögliche Fehlerarten, die alle unter derselben Fehlermeldung zusammengefasst sind. Die genaue Ursache des Fehlers wird jedoch im Parameter {0} angegeben.
9.3. Ansichten
9.3.1. Die Ansicht errors.jsp
Diese Ansicht muss eine Liste von Fehlern anzeigen. Wir sind ihr bereits mehrmals begegnet.
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html>
<head>
<title>Liste d'articles - erreurs</title>
</head>
<body>
<h2>Les erreurs suivantes se sont produites</h2>
<html:errors/>
</body>
</html>
Diese Ansicht zeigt einfach die Liste der Fehler mithilfe des Tags <html:errors/> an.
9.3.2. Die Ansicht listarticles.jsp
Diese Ansicht muss den Inhalt der Tabelle ARTICLES in der Datenbank anzeigen. Ihr Code lautet wie folgt:
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<%
// listarticles : ArrayList dans la requête
// listArticles(i) : tableau (String[5]) de 5 éléments
%>
<html>
<head>
<title>DataSource Struts</title>
</head>
<body>
<h3>Liste des articles</h3>
<hr>
<table border="1">
<logic:iterate id="ligne" name="listArticles">
<tr>
<logic:iterate id="colonne" name="ligne">
<td><bean:write name="colonne"/></td>
</logic:iterate>
</tr>
</logic:iterate>
</table>
</body>
</html>
Die Aktion /list fügt den Inhalt der Tabelle ARTICLES in ein ArrayList-Objekt namens listArticles in der Anfrage ein. Jedes Element des listArticles-Objekts ist ein Array aus 5 Strings, die die 5 Informationen (code, name, price, currentStock, minimumStock) darstellen, die mit einem Eintrag in der Tabelle verknüpft sind. Die Ansicht muss den Inhalt des Objekts „listArticles“ in einer HTML-Tabelle anzeigen. Dazu verwendet sie das Tag <logic:iterate>:
<logic:iterate id="ligne" name="listArticles">
<tr>
<logic:iterate id="colonne" name="ligne">
<td><bean:write name="colonne"/></td>
</logic:iterate>
</tr>
</logic:iterate>
Hier gibt es zwei Iterationen. Die erste durchläuft die Elemente des ArrayList-Objekts listArticles. Das aktuelle Element von listArticles wird hier als row bezeichnet. Das Element „row“ stellt ein String[5]-Objekt dar, das in der zweiten Iteration durchlaufen wird. Das Element dieser zweiten Iteration wird als „column“ bezeichnet. Es stellt das aktuelle Element eines Arrays von Strings dar und ist daher selbst ein String (code, name, price, currentStock, minimumStock). Sein Wert wird mithilfe des Tags <bean:write> angezeigt.
Die Ansicht verwendet Tags aus den Bibliotheken struts-logic und struts-bean. Daher müssen Sie deren Verwendung deklarieren:
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
9.4. Die Aktion /list
Der Zweck der Aktion /list besteht darin, ein ArrayList-Objekt, das den Inhalt der Tabelle ARTICLES darstellt, in die Anfrage einzubinden, damit eine Ansicht darauf zugreifen kann. Der Code lautet wie folgt:
package istia.st.struts.articles;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
public class ListeArticlesAction extends Action {
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// reads the contents of a connection's items table
// performed at context init
// retrieve the dbarticles data source
DataSource dataSource = this.getDataSource(request, "dbarticles");
if (dataSource == null) {
// the data source could not be created
ActionErrors erreurs = new ActionErrors();
erreurs.add( "dbarticles",new ActionError("erreur.dbarticles","La source de données n'a pu être créée"));
this.saveErrors(request, erreurs);
return mapping.findForward("afficherErreurs");
}
// here the data source exists - we use it Conne ction connexion = null;
Statement st = null;
ResultSet rs = null;
String requête = null;
ArrayList alArticles = new ArrayList();
// error handling
try {
// get a connection
connexion = dataSource.getConnection();
// prepare query SQL
requête =
"select code, nom, prix, stockActuel, stockMinimum from articles order by nom";
// execute it
st = connexion.createStatement();
rs = st.executeQuery(requête);
// exploit results
while (rs.next()) {
// save current line
alArticles.add(
new String[] {
rs.getString("code"),
rs.getString("nom"),
rs.getString("prix"),
rs.getString("stockactuel"),
rs.getString("stockMinimum")});
// next line
} //while
// free up resources
rs.close();
st.close();
connexion.close();
} catch (Exception ex) {
// errors have occurred
ActionErrors erreurs = new ActionErrors();
erreurs.add("dbarticles",new ActionError("erreur.dbarticles", ex.getMessage()));
this.saveErrors(request, erreurs);
return mapping.findForward("afficherErreurs");
}
// it's good
request.setAttribute("listArticles", alArticles);
return mapping.findForward("afficherListeArticles");
} //execute
} //class
Der Leser kann wahrscheinlich den Kern des obigen Codes erfassen. Wir konzentrieren uns nur auf das einzige neue Element: die Verwendung eines vom Struts-Framework bereitgestellten DataSource-Objekts. Dieses DataSource-Objekt repräsentiert den Verbindungspool, der durch den Abschnitt <data-source key="dbarticles"> der Konfigurationsdatei konfiguriert wurde. Nach seiner Erstellung wurde das DataSource-Objekt in den Anwendungskontext eingefügt, sodass alle Objekte in diesem Kontext darauf zugreifen können. Es wird daher wie folgt abgerufen:
// retrieve the dbarticles data source
DataSource dataSource = this.getDataSource(request, "dbarticles");
Hier fordern wir die Datenquelle an, die durch den Schlüssel „dbarticles“ identifiziert wird. Wenn wir einen Null-Zeiger erhalten, bedeutet dies, dass die Datenquelle während der Anwendungsinitialisierung nicht erstellt werden konnte. In diesem Fall protokollieren wir den Fehler in einem ActionErrors-Objekt und leiten zur Fehlerseite weiter, die durch den Schlüssel „afficherErreurs“ in der Konfigurationsdatei identifiziert wird:
<action path="/liste" type="istia.st.struts.articles.ListeArticlesAction">
<forward name="afficherListeArticles" path="/vues/listarticles.jsp"/>
<forward name="afficherErreurs" path="/vues/erreurs.jsp"/>
</action>
</action-mappings>
Sobald die Datenquelle abgerufen wurde, haben wir Zugriff auf den Verbindungspool. Eine Verbindung zur Datenbank wird mit dem folgenden Code hergestellt:
Hier stellt uns der Pool eine wiederverwendete Verbindung oder eine neu erstellte Verbindung zur Verfügung, sofern noch Verbindungen verfügbar sind.
9.5. Bereitstellung
Der Anwendungskontext wird in der Konfigurationsdatei server.xml von Tomcat definiert:
<Context path="/listarticles" reloadable="true" docBase="E:\data\serge\web\struts\articles\liste" />
Die Verzeichnisstruktur der Anwendung sieht wie folgt aus:
![]() ![]() | |||
![]() ![]() | |||
![]() | |||
Beachten Sie die Bibliothek „mysql-connector-java-3.0.10-stable-bin.jar“ im Verzeichnis „WEB-INF/lib“. Diese Datei enthält den JDBC-Treiber für die hier verwendete MySQL-Datenbank.
9.6. Testen
Wir starten Tomcat und rufen die URL http://localhost:8080/listarticles/liste.do auf:

9.7. Eine zweite Datenquelle
Wir verwenden nun eine zweite Datenquelle, die sich in einer Postgres-Datenbank befindet. Auch hier befinden sich die Daten in einer Tabelle namens ARTICLES mit denselben Spalten wie zuvor. Ihr Inhalt lautet wie folgt:

Diese neue Datenquelle wird in der Struts-Konfigurationsdatei deklariert:
<data-sources>
<data-source key="dbarticles" >
<set-property property="driverClass" value="com.mysql.jdbc.Driver"></set-property>
<set-property property="url" value="jdbc:mysql://localhost/dbarticles"></set-property>
<set-property property="user" value="admarticles"></set-property>
<set-property property="password" value="mdparticles"></set-property>
<set-property property="minCount" value="2"></set-property>
<set-property property="maxCount" value="5"></set-property>
</data-source>
<data-source key="pgdbarticles" type="org.apache.commons.dbcp.BasicDataSource">
<set-property property="driverClassName" value="org.postgresql.Driver" />
<set-property property="url" value="jdbc:postgresql://localhost/dbarticles" />
<set-property property="username" value="serge" />
<set-property property="password" value="serge" />
<set-property property="maxActive" value="10" />
<set-property property="maxWait" value="5000" />
<set-property property="defaultAutoCommit" value="false" />
<set-property property="defaultReadOnly" value="false" />
</data-source>
</data-sources>
Die neue Datenquelle erhält die Kennung (Schlüssel) pgdbarticles. Die neue Funktion stammt aus der Klasse, die die Schnittstelle javax.sql.DataSource implementiert. Die Standardklasse ist org.apache.struts.util.GenericDataSource, definiert in der Bibliothek struts.jar. Diese Klasse wird in zukünftigen Versionen von Struts veraltet sein, und für Version 1.1 wird empfohlen, die Klasse org.apache.commons.dbcp.BasicDataSource zu verwenden, die in der Bibliothek commons-dbcp-1.1.jar zu finden ist. Diese Bibliothek ist nicht unbedingt im Struts-Paket enthalten. Sie ist unter der URL http://jakarta.apache.org/commons/index.html zu finden, genauer gesagt unter http://jakarta.apache.org/site/binindex.cgi. Sie müssen das Produkt namens Commons DBCP herunterladen. Für Windows können Sie die ZIP-Datei herunterladen. Diese enthält den Quellcode der Bibliothek sowie die entsprechende JAR-Datei. Sie müssen diese aus dem .zip-Archiv extrahieren und im Ordner WEB-INF/lib der Anwendung ablegen. Außerdem müssen Sie den Treiber für das verwendete DBMS in denselben Ordner legen:

Um diese Datenquelle zu verwenden, ändern wir eine Anweisung im Code der Aktion /list:
Diesmal fordern wir die Datenquelle mit dem Namen pgdbarticles an, d. h. die Postgres-Datenquelle.
Jetzt müssen wir nur noch alles kompilieren, Tomcat starten und die URL http://localhost:8080/listarticles/liste.do aufrufen:

9.8. Fazit
Wir haben gezeigt, wie man einen Verbindungspool für den Zugriff auf eine Datenbank verwendet. Beachten Sie, dass wir uns hier nicht an die MVC-Architektur gehalten haben. Tatsächlich führt die Aktion /list selbst die SQL-Abfragen aus, um auf die Daten zuzugreifen. Es wäre vorzuziehen gewesen, wenn sie eine zwischengeschaltete Business-Klasse aufgerufen hätte, die die Tatsache verbergen würde, dass die Daten aus einem Datenbankmanagementsystem abgerufen werden. Wahrscheinlich würde die Business-Klasse dann den Verbindungspool erstellen, und es wäre nicht notwendig, ihn in der Struts-Konfigurationsdatei zu deklarieren. Hier ein Hinweis: Das Vorhandensein eines <data-sources>-Abschnitts in der Konfigurationsdatei könnte darauf hindeuten, dass unsere Anwendung nicht der MVC-Architektur folgt.





