9. Exploração de uma fonte de dados
Propomos aqui estabelecer as bases para a exploração de bases de dados no âmbito de uma aplicação Struts.
9.1. A aplicação Struts /listarticles
Pretendemos apresentar o conteúdo de uma tabela que regista as características dos artigos vendidos por uma loja.
![]() |
|
O conteúdo da tabela é o seguinte:

A aplicação listarticles irá apresentar-nos o mesmo resultado (de forma menos elegante) numa página web:

9.2. Configuração da aplicação Struts /listarticles
O ficheiro web.xml da aplicação é padrão:
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>
O ficheiro struts-config.xml introduz uma nova secção <data-sources> que permite declarar e configurar fontes de dados:
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. Fontes de dados
A secção <data-sources> permite declarar todas as fontes de dados da aplicação, sendo cada uma delas descrita por uma secção <data-source>. Esta baliza admite vários atributos:
identifica a fonte de dados quando existem várias. | |
o nome da classe a instanciar para aceder à base de dados. Esta classe encontra-se geralmente numa biblioteca de classes (.jar) fornecida pelo editor do SGBD. Esta biblioteca contém o controlador JDBC de acesso à base de dados. A propriedade driverClass identifica este controlador. O ficheiro .jar das classes de acesso ao SGBD será colocado na pasta WEB-INF/lib da aplicação. | |
cadeia de ligação a uma base de dados específica. Com efeito, o controlador JDBC permite o acesso a todas as bases de dados geridas pelo SGBD. A propriedade url permite-nos indicar qual delas iremos utilizar. | |
O acesso às bases de dados está protegido. O SGBD gere utilizadores identificados por um nome de utilizador e uma palavra-passe. Estes são especificados nos atributos «user» e «password» da baliza. | |
O Struts irá gerir um conjunto de ligações ao SGBD. Abrir uma ligação a um SGBD é uma operação que consome muitos recursos em termos de tempo e memória. Em vez de abrir e fechar uma ligação ao SGBD para cada uma das solicitações que serão feitas à aplicação, a aplicação gere um conjunto de n ligações, em que n está no intervalo [minCount, maxCount]. Se, durante uma solicitação, a aplicação precisar de uma ligação: - procura obter uma no conjunto de ligações. Se encontrar uma disponível, utiliza-a. - se não houver ligações livres no conjunto e se houver menos de maxCount ligações no conjunto, é aberta uma nova ligação e adicionada ao conjunto. A solicitação atual poderá utilizá-la. - se não houver ligações livres e não for possível criar uma nova, o pedido fica em espera. Quando a consulta atual encerra a ligação, esta não é realmente encerrada, mas sim devolvida ao conjunto. |
Aqui, temos as seguintes propriedades:
dbarticles — é o nome pelo qual a fonte de dados será identificada no contexto da aplicação | |
com.mysql.jdbc.Driver. Utilizamos uma base de dados MySQL. | |
jdbc:mysql://localhost/dbarticles. A base de dados chama-se dbarticles e está presente no computador local. | |
admarticles, mdparticles. Este utilizador foi definido com todos os privilégios sobre a base de dados dbarticles. | |
2, 5. Mínimo de 2 ligações no pool, máximo de 5. |
9.2.2. Ações
As ações declaradas no ficheiro de configuração do Struts são as seguintes:
<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>
A única ação chama-se /liste e está associada à classe istia.st.struts.articles.ListeArticlesAction. Esta ação termina com a exibição:
- da página dos artigos (/vues/listarticles.jsp)
- da página de erros (/vues/erreurs.jsp)
9.2.3. O ficheiro de mensagens
O ficheiro de mensagens ApplicationResources.properties será colocado na pasta WEB-INF/classes/istia/st/struts/articles. O seu conteúdo será o seguinte:
# erros
errors.header=<ul>
errors.footer=</ul>
erreur.dbarticles=<li>Erreur d'accès à la base des articles ({0})</li>
Pode ocorrer apenas um erro: um erro de acesso à base de dados. Na verdade, existem vários tipos de erros possíveis, todos agrupados na mesma mensagem de erro. A causa exata do erro será, no entanto, especificada no parâmetro {0}.
9.3. As vistas
9.3.1. A vista erreurs.jsp
Esta vista deve apresentar uma lista de erros. Já a encontrámos várias vezes.
<%@ 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 limita-se a apresentar a lista de erros com a baliza <html:errors/>.
9.3.2. A vista listarticles.jsp
Esta vista deve apresentar o conteúdo da tabela ARTICLES da base de dados. O seu código é o seguinte:
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<%
// listarticles: ArrayList na consulta
// listArticles(i): tabela (String[5]) com 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>
A ação /liste irá colocar o conteúdo da tabela ARTICLES num objeto ArrayList, inserido na consulta com o nome listArticles. Cada elemento do objeto listArticles é uma matriz de 5 cadeias de caracteres que representam as 5 informações (código, nome, preço, stockActuel, stockMinimum) associadas a um artigo na tabela. A vista deve apresentar o conteúdo do objeto listArticles numa tabela HTML. Para tal, utiliza a baliza <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>
Existem aqui duas iterações. A primeira percorre os elementos do objeto ArrayList listArticles. O elemento atual de listArticles é aqui designado por «linha». O elemento «linha» representa um objeto String[5] que é percorrido através da segunda iteração. O elemento desta segunda iteração é denominado «coluna». Representa o elemento atual de uma matriz de cadeias de caracteres e é, portanto, uma cadeia de caracteres (código, nome, preço, stockActuel, stockMinimum). O seu valor é apresentado através da baliza <bean:write>.
A vista utiliza tags das bibliotecas struts-logic e struts-bean. Por isso, é necessário declarar a utilização destas:
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
9.4. A ação /liste
A ação /liste tem como objetivo inserir na solicitação um objeto ArrayList que representa o conteúdo da tabela ARTICLES, para que uma vista o possa utilizar. O seu código é o seguinte:
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 {
// lê o conteúdo da tabela de artigos de uma ligação
// estabelecida na inicialização do contexto
// recupera-se a fonte de dados «dbarticles»
DataSource dataSource = this.getDataSource(request, "dbarticles");
if (dataSource == null) {
// não foi possível criar a fonte de dados
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");
}
// aqui, a fonte de dados existe — é utilizada Conexão conexão = null;
Statement st = null;
ResultSet rs = null;
String requête = null;
ArrayList alArticles = new ArrayList();
// gestão de erros
try {
// obter uma ligação
connexion = dataSource.getConnection();
// preparar a consulta SQL
requête =
"select code, nom, prix, stockActuel, stockMinimum from articles order by nom";
// executá-la
st = connexion.createStatement();
rs = st.executeQuery(requête);
// analisar os resultados
while (rs.next()) {
// gravar a linha atual
alArticles.add(
new String[] {
rs.getString("code"),
rs.getString("nom"),
rs.getString("prix"),
rs.getString("stockactuel"),
rs.getString("stockMinimum")});
// linha seguinte
} //enquanto
// liberar os recursos
rs.close();
st.close();
connexion.close();
} catch (Exception ex) {
// ocorreram erros
ActionErrors erreurs = new ActionErrors();
erreurs.add("dbarticles",new ActionError("erreur.dbarticles", ex.getMessage()));
this.saveErrors(request, erreurs);
return mapping.findForward("afficherErreurs");
}
// tudo bem
request.setAttribute("listArticles", alArticles);
return mapping.findForward("afficherListeArticles");
} //executar
} //classe
O leitor é, sem dúvida, capaz de compreender a essência do código acima. Iremos centrar-nos apenas na única novidade: a utilização de um objeto DataSource fornecido pelo framework Struts. Este objeto DataSource representa o conjunto de ligações configurado pela secção <data-source key="dbarticles"> do ficheiro de configuração. O objeto DataSource foi colocado, após a sua criação, no contexto da aplicação para que todos os objetos desse contexto tenham acesso ao mesmo. É, portanto, recuperado da seguinte forma:
// a recuperar a fonte de dados dbarticles
DataSource dataSource = this.getDataSource(request, "dbarticles");
Aqui, solicitamos a fonte de dados identificada pela chave «dbarticles». Se recuperarmos um ponteiro null, isso significa que a fonte de dados não pôde ser criada durante a inicialização da aplicação. Nesse caso, registamos o erro num objeto ActionErrors e passamos o controlo para a página de erros identificada pela chave «afficherErreurs» no ficheiro de configuração:
<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>
Assim que a fonte de dados for obtida, temos acesso ao conjunto de ligações. Uma ligação à base de dados é estabelecida através do código:
Neste caso, o pool fornecer-nos-á uma ligação reutilizada ou criada, caso ainda haja possibilidade de criar uma nova.
9.5. Implementação
O contexto da aplicação é definido no ficheiro de configuração server.xml do Tomcat:
<Context path="/listarticles" reloadable="true" docBase="E:\data\serge\web\struts\articles\liste" />
A estrutura da aplicação é a seguinte:
![]() ![]() | ||
![]() ![]() | ||
![]() | ||
Note-se a biblioteca mysql-connector-java-3.0.10-stable-bin.jar em WEB-INF/lib. É esta que contém o controlador JDBC da base MySQL aqui utilizada.
9.6. Os testes
Iniciamos o Tomcat e solicitamos o URL http://localhost:8080/listarticles/liste.do:

9.7. Uma segunda fonte de dados
Utilizamos agora uma segunda fonte de dados presente numa base de dados Postgres. Também aqui, os dados encontram-se numa tabela ARTICLES com as mesmas colunas que anteriormente. O seu conteúdo é o seguinte:

Esta nova fonte de dados é declarada no ficheiro de configuração do 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>
A nova fonte terá como identificador (chave) pgdbarticles. A novidade provém da classe que implementa a interface javax.sql.DataSource. A classe predefinida é a org.apache.struts.util.GenericDataSource, definida na biblioteca struts.jar. Esta classe será descontinuada em futuras versões do Struts e, para a versão 1.1, recomenda-se a utilização da classe org.apache.commons.dbcp.BasicDataSource, que se encontra na biblioteca commons-dbcp-1.1.jar. Esta não é necessariamente fornecida com o pacote Struts. Pode ser encontrada no endereço http://jakarta.apache.org/commons/index.html e, mais especificamente, no endereço http://jakarta.apache.org/site/binindex.cgi. É necessário descarregar o produto denominado Commons DBCP. No Windows, é possível descarregar o ficheiro .zip. Este contém o código-fonte da biblioteca, bem como o ficheiro .jar correspondente. É necessário extrair este último do arquivo .zip e colocá-lo na pasta WEB-INF/lib da aplicação. É igualmente necessário colocar nessa mesma pasta o controlador do SGBD utilizado:

Para utilizar este código-fonte, alteramos uma instrução no código da ação /liste:
Desta vez, solicitamos a fonte de dados denominada pgdbarticles, c.a.d, a fonte de dados Postgres.
Resta-nos apenas compilar tudo, iniciar o Tomcat e aceder à página http://localhost:8080/listarticles/liste.do:

9.8. Conclusão
Mostrámos como utilizar um conjunto de ligações para aceder a uma base de dados. Note-se aqui que não respeitámos a arquitetura MVC. Com efeito, a ação /liste efetua ela própria as consultas SQL para aceder aos dados. Teria sido preferível que ela recorresse a uma classe de negócio intermédia que ocultasse o facto de que os dados são obtidos num SGBD. Provavelmente, seria essa classe de negócio a criar o conjunto de ligações, pelo que não seria necessário declará-lo no ficheiro de configuração do Struts. Isto é um indício: a presença de uma secção <data-sources> no ficheiro de configuração pode significar que a nossa aplicação não respeita a arquitetura MVC.





