9. Gebruik van een gegevensbron
We willen hier de basis leggen voor het gebruik van databases binnen een Struts-applicatie.
9.1. De Struts-applicatie /listarticles
We willen de inhoud weergeven van een tabel waarin de kenmerken van artikelen zijn opgeslagen die door een winkel worden verkocht.
![]() |
|
De inhoud van de tabel is als volgt:

De applicatie listarticles geeft ons hetzelfde resultaat (maar minder mooi) op een webpagina:

9.2. Configuratie van de Struts-applicatie /listarticles
Het bestand web.xml van de applicatie is standaard:
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>
Het bestand struts-config.xml introduceert een nieuwe sectie <data-sources> waarmee gegevensbronnen kunnen worden gedefinieerd en geconfigureerd:
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. Gegevensbronnen
In de sectie <data-sources> kunnen alle gegevensbronnen van de applicatie worden opgegeven, waarbij elke bron wordt beschreven door een sectie <data-source>. Deze tag ondersteunt verschillende attributen:
identificeert de gegevensbron wanneer er meerdere zijn. | |
de naam van de klasse die moet worden geïnstantieerd om toegang te krijgen tot de database. Deze klasse bevindt zich doorgaans in een klassenbibliotheek (.jar) die wordt geleverd door de uitgever van SGBD. Deze bibliotheek bevat de JDBC-driver voor toegang tot de database. De eigenschap driverClass verwijst naar deze driver. Het .jar-bestand met de klassen voor toegang tot de SGBD wordt in de map WEB-INF/lib van de applicatie geplaatst. | |
verbindingsstring voor een specifieke database. De driver JDBC biedt namelijk toegang tot alle databases die door SGBD worden beheerd. Met de eigenschap url kunnen we aangeven welke database we gaan gebruiken. | |
De toegang tot de databases is beveiligd. De SGBD beheert gebruikers die worden geïdentificeerd aan de hand van een gebruikersnaam en een wachtwoord. Deze worden gespecificeerd in de attributen user en password van de tag. | |
Struts beheert een pool van verbindingen met de SGBD. Het openen van een verbinding met een SGBD is een bewerking die veel tijd en geheugen kost. In plaats van voor elk verzoek dat aan de applicatie wordt gedaan een verbinding met de SGBD te openen en te sluiten, beheert de applicatie een pool van n verbindingen, waarbij n binnen het bereik van de [minCount, maxCount] ligt. Als de applicatie tijdens een verzoek een verbinding nodig heeft: - probeert ze er een uit de verbindingspool te halen. Als ze een vrije verbinding vindt, gebruikt ze die. - als er geen vrije verbindingen in de pool zijn en er minder dan maxCount verbindingen in de pool zijn, wordt er een nieuwe verbinding geopend en aan de pool toegevoegd. Het huidige verzoek kan deze gebruiken. - als er geen vrije verbindingen zijn en er geen mogelijkheid is om een nieuwe aan te maken, wordt de aanvraag in de wachtrij geplaatst. Wanneer de huidige aanvraag de verbinding sluit, wordt deze niet daadwerkelijk gesloten, maar teruggegeven aan de pool. |
Hier hebben we de volgende eigenschappen:
dbarticles – dit is de naam waaronder de gegevensbron in de context van de applicatie bekend zal staan | |
com.mysql.jdbc.Driver. We gebruiken een database met de naam MySQL. | |
jdbc:mysql://localhost/dbarticles. De database heet dbarticles en bevindt zich op de lokale machine. | |
admarticles, mdparticles. Deze gebruiker is ingesteld met alle rechten op de database dbarticles. | |
2, 5. Minimaal 2 verbindingen in de pool, maximaal 5. |
9.2.2. Acties
De acties die in het Struts-configuratiebestand zijn opgegeven, zijn de volgende:
<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>
De enige actie heet /liste en is gekoppeld aan de klasse istia.st.struts.articles.ListeArticlesAction. Deze actie resulteert in de weergave van:
- de artikelenpagina (/vues/listarticles.jsp)
- de foutpagina (/vues/erreurs.jsp)
9.2.3. Het berichtenbestand
Het berichtenbestand ApplicationResources.properties wordt in de map WEB-INF/classes/istia/st/struts/articles geplaatst. De inhoud ervan is als volgt:
# fouten
errors.header=<ul>
errors.footer=</ul>
erreur.dbarticles=<li>Erreur d'accès à la base des articles ({0})</li>
Er kan slechts één fout optreden: een fout bij het benaderen van de database. Er zijn in feite meerdere soorten fouten mogelijk, die allemaal onder dezelfde foutmelding vallen. De exacte oorzaak van de fout wordt echter gespecificeerd in de parameter {0}.
9.3. De weergaven
9.3.1. De weergave erreurs.jsp
Deze weergave moet een lijst met fouten weergeven. We zijn deze al meerdere keren tegengekomen.
<%@ 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>
Deze weergave geeft alleen de lijst met fouten weer met de tag <html:errors/>.
9.3.2. De weergave listarticles.jsp
Deze weergave moet de inhoud van de tabel ARTICLES uit de database weergeven. De code hiervoor is als volgt:
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<%
// listarticles: ArrayList in de query
// listArticles(i): array (String[5]) met 5 elementen
%>
<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>
De actie /liste zet de inhoud van de tabel ARTICLES in een object ArrayList, dat in de query wordt geplaatst onder de naam listArticles. Elk element van het object listArticles is een array van 5 tekenreeksen die de 5 gegevens (code, naam, prijs, stockActuel, stockMinimum) vertegenwoordigen die betrekking hebben op een artikel in de tabel. De weergave moet de inhoud van het object listArticles weergeven in een tabel HTML. Hiervoor maakt de weergave gebruik van de 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>
Er zijn hier twee iteraties. De eerste doorloopt de elementen van het object ArrayList listArticles. Het huidige element van listArticles wordt hier ‘regel’ genoemd. Het element ‘regel’ vertegenwoordigt een String-object [5] dat met behulp van de tweede iteratie wordt doorlopen. Het element van deze tweede iteratie wordt ‘kolom’ genoemd. Het vertegenwoordigt het huidige element van een array van tekenreeksen en is dus een tekenreeks (code, naam, prijs, stockActuel, stockMinimum). De waarde ervan wordt weergegeven met behulp van de tag <bean:write>.
De weergave maakt gebruik van tags uit de bibliotheken struts-logic en struts-bean. Het gebruik hiervan moet dus worden gedeclareerd:
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
9.4. De actie /liste
De actie /liste heeft als doel een object ArrayList, dat de inhoud van de tabel ARTICLES vertegenwoordigt, in de verzoek-URL op te nemen, zodat een weergave hier gebruik van kan maken. De code hiervoor is als volgt:
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 {
// leest de inhoud van de artikeltabel van een verbinding
// die bij het initialiseren van de context tot stand is gebracht
// de gegevensbron 'dbarticles' wordt opgehaald
DataSource dataSource = this.getDataSource(request, "dbarticles");
if (dataSource == null) {
// de gegevensbron kon niet worden aangemaakt
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");
}
// hier bestaat de gegevensbron – deze wordt geb ruikt Connection connection = null;
Statement st = null;
ResultSet rs = null;
String requête = null;
ArrayList alArticles = new ArrayList();
// fouten worden afgehandeld
try {
// een verbinding tot stand brengen
connexion = dataSource.getConnection();
// de query voorbereiden SQL
requête =
"select code, nom, prix, stockActuel, stockMinimum from articles order by nom";
// de query uitvoeren
st = connexion.createStatement();
rs = st.executeQuery(requête);
// de resultaten verwerken
while (rs.next()) {
// de huidige regel opslaan
alArticles.add(
new String[] {
rs.getString("code"),
rs.getString("nom"),
rs.getString("prix"),
rs.getString("stockactuel"),
rs.getString("stockMinimum")});
// volgende regel
} //while
// de bronnen vrijgeven
rs.close();
st.close();
connexion.close();
} catch (Exception ex) {
// er zijn fouten opgetreden
ActionErrors erreurs = new ActionErrors();
erreurs.add("dbarticles",new ActionError("erreur.dbarticles", ex.getMessage()));
this.saveErrors(request, erreurs);
return mapping.findForward("afficherErreurs");
}
// ok
request.setAttribute("listArticles", alArticles);
return mapping.findForward("afficherListeArticles");
} //uitvoeren
} //klasse
De lezer begrijpt ongetwijfeld de essentie van de bovenstaande code. We zullen alleen stilstaan bij de enige nieuwigheid: het gebruik van een DataSource-object dat door het Struts-framework wordt geleverd. Dit DataSource-object vertegenwoordigt de verbindingspool die is geconfigureerd via de sectie <data-source key="dbarticles"> in het configuratiebestand. Het object DataSource is na het aanmaken in de context van de applicatie geplaatst, zodat alle objecten in deze context er toegang toe hebben. Het wordt dus als volgt opgehaald:
// de gegevensbron dbarticles wordt opgehaald
DataSource dataSource = this.getDataSource(request, "dbarticles");
We vragen hier de gegevensbron op die wordt geïdentificeerd door de sleutel "dbarticles". Als we een pointer null terugkrijgen, betekent dit dat de gegevensbron niet kon worden aangemaakt tijdens het initialiseren van de applicatie. In dat geval registreren we de fout in een object ActionErrors en geven we het stokje door aan de foutpagina die in het configuratiebestand wordt aangeduid met de sleutel "afficherErreurs":
<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>
Zodra de gegevensbron is verkregen, hebben we toegang tot de verbindingspool. Een verbinding met de database wordt tot stand gebracht met de volgende code:
Hier levert de pool ons een hergebruikte verbinding of een nieuw aangemaakte verbinding, als er nog ruimte is om er een aan te maken.
9.5. Implementatie
De context van de applicatie wordt gedefinieerd in het Tomcat-configuratiebestand server.xml:
<Context path="/listarticles" reloadable="true" docBase="E:\data\serge\web\struts\articles\liste" />
De boomstructuur van de applicatie is als volgt:
![]() ![]() | ||
![]() ![]() | ||
![]() | ||
Let op de bibliotheek mysql-connector-java-3.0.10-stable-bin.jar in WEB-INF/lib. Deze bevat de driver JDBC van de database MySQL die hier wordt gebruikt.
9.6. De tests
We starten Tomcat en roepen de URL-http://localhost:8080/listarticles/liste.do op:

9.7. Een tweede gegevensbron
We gebruiken nu een tweede gegevensbron in een Postgres-database. Ook hier staan de gegevens in een tabel ARTICLES met dezelfde kolommen als eerder. De inhoud is als volgt:

Deze nieuwe gegevensbron wordt gedeclareerd in het configuratiebestand van Struts:
<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>
De nieuwe bron krijgt de identificatiecode (key) pgdbarticles. De nieuwigheid komt voort uit de klasse die de interface javax.sql.DataSource implementeert. De standaardklasse is org.apache.struts.util.GenericDataSource, gedefinieerd in de bibliotheek struts.jar. Deze klasse zal in toekomstige versies van Struts worden afgeschaft en voor versie 1.1 wordt aangeraden om de klasse org.apache.commons.dbcp.BasicDataSource te gebruiken, die te vinden is in de bibliotheek commons-dbcp-1.1.jar. Deze wordt niet noodzakelijkerwijs meegeleverd met het Struts-pakket. Deze is te vinden op de url http://jakarta.apache.org/commons/index.html en meer specifiek op de url http://jakarta.apache.org/site/binindex.cgi. Je moet het product met de naam Commons DBCP downloaden. Voor Windows kun je het .zip-bestand downloaden. Dit bevat de broncode van de bibliotheek en het bijbehorende .jar-bestand. Je moet dit uit het .zip-archief uitpakken en in de map WEB-INF/lib van de applicatie plaatsen. Je moet in dezelfde map ook het stuurprogramma van de gebruikte SGBD plaatsen:

Om deze broncode te gebruiken, wijzigen we één instructie in de code van de actie /liste:
We vragen deze keer de gegevensbron met de naam pgdbarticles, c.a.d, de Postgres-gegevensbron.
Nu hoeven we alleen nog maar alles te compileren, Tomcat te starten en de pagina URL http://localhost:8080/listarticles/liste.do op te vragen:

9.8. Conclusie
We hebben laten zien hoe je een verbindingspool kunt gebruiken om toegang te krijgen tot een database. Merk hierbij op dat we de architectuur MVC niet hebben gevolgd. De actie /liste voert namelijk zelf de query's SQL uit om toegang te krijgen tot de gegevens. Het zou beter zijn geweest als deze actie een tussenliggende businessklasse had aangeroepen, die zou verbergen dat de gegevens uit een SGBD worden opgehaald. Waarschijnlijk zou de businessklasse dan de verbindingspool aanmaken en zou het niet nodig zijn om deze in het Struts-configuratiebestand te vermelden. Dit is een aanwijzing: de aanwezigheid van een <data-sources>-sectie in het configuratiebestand kan betekenen dat onze applicatie niet voldoet aan de MVC-architectuur.





