9. Aprovechamiento de una fuente de datos
Aquí nos proponemos sentar las bases para la explotación de bases de datos dentro de una aplicación Struts.
9.1. La aplicación Struts /listarticles
Queremos mostrar el contenido de una tabla que registra las características de los artículos vendidos por una tienda.
![]() |
|
El contenido de la tabla es el siguiente:

La aplicación listarticles nos dará el mismo resultado (aunque de peor calidad) en una página web:

9.2. Configuración de la aplicación Struts /listarticles
El archivo web.xml de la aplicación es estándar:
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>
El archivo struts-config.xml introduce una nueva sección <data-sources> que permite declarar y configurar fuentes de datos:
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. Fuentes de datos
La sección <data-sources> permite declarar todas las fuentes de datos de la aplicación, cada una de las cuales se describe mediante una sección <data-source>. Esta etiqueta admite varios atributos:
identifica la fuente de datos cuando hay varias. | |
el nombre de la clase que se debe instanciar para acceder a la base de datos. Esta clase se encuentra generalmente en una biblioteca de clases (.jar) suministrada por el editor de SGBD. Esta biblioteca contiene el controlador JDBC de acceso a la base de datos. La propiedad driverClass designa este controlador. El archivo .jar de las clases de acceso a SGBD se colocará en la carpeta WEB-INF/lib de la aplicación. | |
cadena de conexión a una base de datos concreta. De hecho, el controlador JDBC permite el acceso a todas las bases de datos gestionadas por SGBD. La propiedad url nos permite indicar cuál vamos a utilizar. | |
El acceso a las bases de datos está protegido. El SGBD gestiona usuarios identificados mediante un nombre de usuario y una contraseña. Estos se especifican en los atributos user y password de la etiqueta. | |
Struts gestionará un grupo de conexiones a SGBD. Abrir una conexión a SGBD es una operación que consume muchos recursos de tiempo y memoria. En lugar de abrir y cerrar una conexión con SGBD para cada una de las solicitudes que se realicen en la aplicación, esta gestiona un grupo de n conexiones, donde n está en el intervalo [minCount, maxCount]. Si durante una solicitud la aplicación necesita una conexión: - intentará obtener una del grupo de conexiones. Si encuentra una libre, la utilizará. - si no hay conexiones libres en el grupo y hay menos de maxCount conexiones en el grupo, se abre una nueva conexión y se añade al grupo. La solicitud actual podrá utilizarla. - Si no hay conexiones libres y no hay forma de crear una nueva, la solicitud se pone en espera. Cuando la consulta actual cierra la conexión, esta no se cierra realmente, sino que se devuelve al grupo. |
Aquí tenemos las siguientes propiedades:
dbarticles: es el nombre con el que se identificará la fuente de datos en el contexto de la aplicación | |
com.mysql.jdbc.Driver. Utilizamos una base de datos MySQL. | |
jdbc:mysql://localhost/dbarticles. La base de datos se llama dbarticles y se encuentra en el equipo local. | |
admarticles, mdparticles. Se ha definido a este usuario con todos los privilegios sobre la base de datos dbarticles. | |
2, 5. Mínimo de 2 conexiones en el grupo, máximo de 5. |
9.2.2. Acciones
Las acciones declaradas en el archivo de configuración de Struts son las siguientes:
<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>
La única acción se llama /liste y está asociada a la clase istia.st.struts.articles.ListeArticlesAction. Esta acción finaliza con la visualización de:
- la página de artículos (/vues/listarticles.jsp)
- la página de errores (/vues/erreurs.jsp)
9.2.3. El archivo de mensajes
El archivo de mensajes ApplicationResources.properties se colocará en la carpeta WEB-INF/classes/istia/st/struts/articles. Su contenido será el siguiente:
# erreurs
errors.header=<ul>
errors.footer=</ul>
erreur.dbarticles=<li>Erreur d'accès à la base des articles ({0})</li>
Solo puede producirse un error: un error de acceso a la base de datos. En realidad, hay varios tipos de errores posibles, todos ellos agrupados en el mismo mensaje de error. No obstante, la causa exacta del error se especificará en el parámetro {0}.
9.3. Las vistas
9.3.1. La vista erreurs.jsp
Esta vista debe mostrar una lista de errores. Ya nos hemos encontrado con ella en varias ocasiones.
<%@ 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>
Esta vista se limita a mostrar la lista de errores con la etiqueta <html:errors/>.
9.3.2. La vista listarticles.jsp
Esta vista debe mostrar el contenido de la tabla ARTICLES de la base de datos. Su código es el siguiente:
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<%
// listarticles: ArrayList en la consulta
// listArticles(i): matriz (String[5]) de 5 elementos
%>
<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>
La acción /liste colocará el contenido de la tabla ARTICLES en un objeto ArrayList situado en la consulta con el nombre listArticles. Cada elemento del objeto listArticles es una matriz de 5 cadenas de caracteres que representan los 5 datos (código, nombre, precio, stockActuel, stockMinimum) relacionados con un artículo de la tabla. La vista debe mostrar el contenido del objeto listArticles en una tabla HTML. Para ello, utiliza la etiqueta <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>
Aquí hay dos iteraciones. La primera recorre los elementos del objeto ArrayList listArticles. El elemento actual de listArticles se denomina aquí línea. El elemento línea representa un objeto String[5] que se recorre mediante la segunda iteración. El elemento de esta segunda iteración se denomina columna. Representa el elemento actual de una matriz de cadenas de caracteres y, por lo tanto, es una cadena de caracteres (código, nombre, precio, stockActuel, stockMinimum). Su valor se muestra mediante la etiqueta <bean:write>.
La vista utiliza etiquetas de las bibliotecas struts-logic y struts-bean. Por lo tanto, es necesario declarar su uso:
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
9.4. La acción /liste
La acción /liste tiene como objetivo incluir en la solicitud un objeto ArrayList que representa el contenido de la tabla ARTICLES, para que una vista pueda utilizarlo. Su código es el siguiente:
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 {
// lee el contenido de la tabla de artículos de una conexión
// establecida al iniciar el contexto
//: se recupera la fuente de datos dbarticles
DataSource dataSource = this.getDataSource(request, "dbarticles");
if (dataSource == null) {
// no se ha podido crear la fuente de datos
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");
}
// aquí la fuente de datos existe; la utilizamos Conexión conexión = null;
Statement st = null;
ResultSet rs = null;
String requête = null;
ArrayList alArticles = new ArrayList();
// gestionamos los errores
try {
// obtener una conexión
connexion = dataSource.getConnection();
// preparar la consulta SQL
requête =
"select code, nom, prix, stockActuel, stockMinimum from articles order by nom";
// ejecutarla
st = connexion.createStatement();
rs = st.executeQuery(requête);
// analizar los resultados
while (rs.next()) {
// guardar la línea actual
alArticles.add(
new String[] {
rs.getString("code"),
rs.getString("nom"),
rs.getString("prix"),
rs.getString("stockactuel"),
rs.getString("stockMinimum")});
// línea siguiente
} //while
// liberar recursos
rs.close();
st.close();
connexion.close();
} catch (Exception ex) {
// se han producido errores
ActionErrors erreurs = new ActionErrors();
erreurs.add("dbarticles",new ActionError("erreur.dbarticles", ex.getMessage()));
this.saveErrors(request, erreurs);
return mapping.findForward("afficherErreurs");
}
// Todo bien
request.setAttribute("listArticles", alArticles);
return mapping.findForward("afficherListeArticles");
} //execute
} //classe
El lector seguramente es capaz de comprender la esencia del código anterior. Nos detendremos únicamente en la única novedad: el uso de un objeto DataSource proporcionado por el framework Struts. Este objeto DataSource representa el grupo de conexiones configurado por la sección <data-source key="dbarticles"> del archivo de configuración. El objeto DataSource se ha colocado, tras su creación, en el contexto de la aplicación para que todos los objetos de dicho contexto puedan acceder a él. Por lo tanto, se recupera de la siguiente manera:
// se está recuperando la fuente de datos dbarticles
DataSource dataSource = this.getDataSource(request, "dbarticles");
Aquí solicitamos la fuente de datos identificada por la clave «dbarticles». Si recuperamos un puntero null, significa que la fuente de datos no se pudo crear durante la inicialización de la aplicación. En este caso, anotamos el error en un objeto ActionErrors y pasamos el control a la página de errores identificada por la clave «afficherErreurs» en el archivo de configuración:
<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>
Una vez obtenida la fuente de datos, tenemos acceso al grupo de conexiones. Se establece una conexión con la base de datos mediante el código:
En este caso, el grupo nos proporcionará una conexión reciclada o una nueva, si aún es posible crearla.
9.5. Implementación
El contexto de la aplicación se define en el archivo de configuración server.xml de Tomcat:
<Context path="/listarticles" reloadable="true" docBase="E:\data\serge\web\struts\articles\liste" />
La estructura de la aplicación es la siguiente:
![]() ![]() | ||
![]() ![]() | ||
![]() | ||
Cabe destacar la biblioteca mysql-connector-java-3.0.10-stable-bin.jar en WEB-INF/lib. Es esta la que contiene el controlador JDBC de la base MySQL utilizada aquí.
9.6. Las pruebas
Iniciamos Tomcat y solicitamos el URL http://localhost:8080/listarticles/liste.do:

9.7. Una segunda fuente de datos
Ahora utilizamos una segunda fuente de datos presente en una base de datos Postgres. También en este caso, los datos se encuentran en una tabla ARTICLES con las mismas columnas que antes. Su contenido es el siguiente:

Esta nueva fuente de datos se declara en el archivo de configuración de 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>
La nueva fuente tendrá como identificador (clave) pgdbarticles. La novedad proviene de la clase que implementa la interfaz javax.sql.DataSource. La clase por defecto es org.apache.struts.util.GenericDataSource, definida en la biblioteca struts.jar. Esta clase quedará obsoleta en futuras versiones de Struts y, para Struts 1.1, se recomienda utilizar la clase org.apache.commons.dbcp.BasicDataSource, que se encuentra en la biblioteca commons-dbcp-1.1. Esta no se incluye necesariamente con el paquete Struts. Se puede encontrar en url http://jakarta.apache.org/commons/index.html y, más concretamente, en url http://jakarta.apache.org/site/binindex.cgi. Hay que descargar el producto llamado Commons DBCP. En Windows, se puede descargar el archivo .zip. Este contiene el código fuente de la biblioteca, así como el .jar correspondiente. Hay que extraerlo del archivo .zip y colocarlo en la carpeta WEB-INF/lib de la aplicación. También hay que colocar en esa misma carpeta el controlador del SGBD utilizado:

Para utilizar esta fuente, cambiamos una instrucción en el código de la acción /liste:
En esta ocasión, solicitamos la fuente de datos denominada pgdbarticles, c.a.d. la fuente de datos Postgres.
Ahora solo nos queda compilarlo todo, iniciar Tomcat y solicitar el URL http://localhost:8080/listarticles/liste.do:

9.8. Conclusión
Hemos mostrado cómo utilizar un grupo de conexiones para acceder a una base de datos. Cabe señalar aquí que no hemos respetado la arquitectura MVC. De hecho, la acción /liste realiza ella misma las consultas SQL para acceder a los datos. Hubiera sido preferible que se dirigiera a una clase de negocio intermedia que ocultara el hecho de que se van a buscar los datos en un SGBD. Probablemente sería la clase de negocio la que crearía entonces el grupo de conexiones y, por lo tanto, no habría necesidad de declararlo en el archivo de configuración de Struts. Esto es una pista: la presencia de una sección <data-sources> en el archivo de configuración puede significar que nuestra aplicación no respeta la arquitectura MVC.





