9. Veri kaynağının kullanımı
Burada, bir Struts uygulaması içinde veritabanlarından yararlanmanın temellerini atmayı amaçlıyoruz.
9.1. Struts /listarticles uygulaması
Bir mağazanın sattığı ürünlerin özelliklerini kaydeden bir tablonun içeriğini görüntülemek istiyoruz.
![]() |
|
Tablonun içeriği şöyledir:

listarticles uygulaması da bir web sayfasında aynı sonucu (ancak daha az iyi bir şekilde) verecektir:

9.2. Struts /listarticles uygulamasının yapılandırılması
Uygulamanın web.xml dosyası standarttır:
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>
struts-config.xml dosyası, veri kaynaklarını tanımlamaya ve yapılandırmaya olanak tanıyan yeni bir <data-sources> bölümü ekler:
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. Veri kaynakları
<data-sources> bölümü, uygulamanın tüm veri kaynaklarını tanımlamaya yarar; her bir veri kaynağı bir <data-source> bölümü ile tanımlanır. Bu etiket çeşitli öznitelikleri destekler:
birden fazla veri kaynağı olduğunda kaynağı tanımlar. | |
veritabanına erişmek için örneklenecek sınıfın adıdır. Bu sınıf genellikle SGBD'in yayıncısı tarafından sağlanan bir sınıf kütüphanesinde (.jar) bulunur. Bu kütüphane, veritabanına erişim için JDBC sürücüsünü içerir. driverClass özelliği bu sürücüyü belirtir. SGBD'e erişim sağlayan sınıfların .jar dosyası, uygulamanın WEB-INF/lib klasörüne yerleştirilecektir. | |
belirli bir veritabanına bağlantı dizesi. Aslında, JDBC sürücüsü, SGBD tarafından yönetilen tüm veritabanlarına erişim sağlar. url özelliği, hangi veritabanını kullanacağımızı belirtmemizi sağlar. | |
Veritabanlarına erişim korumalıdır. SGBD, kullanıcı adı ve şifre ile tanımlanan kullanıcıları yönetir. Bunlar, etiketin user ve password özniteliklerinde belirtilir. | |
Struts, SGBD'e bir bağlantı havuzu yönetecektir. SGBD'e bir bağlantı açmak, zaman ve bellek açısından kaynak tüketen bir işlemdir. Uygulamaya yapılacak her istek için SGBD'e bir bağlantı açıp kapatmak yerine, uygulama n adet bağlantıdan oluşan bir havuzu yönetir; burada n, [minCount, maxCount] aralığındadır. Bir istek sırasında uygulamanın bir bağlantıya ihtiyacı olursa: - bağlantı havuzundan bir bağlantı almaya çalışır. Boş bir bağlantı bulursa, onu kullanır. - havuzda boş bağlantı yoksa ve havuzdaki bağlantı sayısı maxCount'ten azsa, yeni bir bağlantı açılır ve havuza eklenir. Mevcut istek bu bağlantıyı kullanabilir. - Eğer boş bağlantı yoksa ve yeni bir bağlantı oluşturmanın bir yolu yoksa, istek beklemeye alınır. Mevcut istek bağlantıyı kapattığında, bağlantı gerçek anlamda kapatılmaz, ancak havuza geri verilir. |
Burada şu özellikler mevcuttur:
dbarticles - bu, uygulama bağlamında veri kaynağının tanınacağı addır | |
com.mysql.jdbc.Driver. MySQL veritabanını kullanıyoruz. | |
jdbc:mysql://localhost/dbarticles. Veritabanının adı dbarticles'dir ve yerel makinede bulunmaktadır. | |
admarticles, mdparticles. Bu kullanıcı, dbarticles veritabanında tüm ayrıcalıklara sahip olacak şekilde tanımlanmıştır. | |
2, 5. Bağlantı havuzunda en az 2, en fazla 5 bağlantı. |
9.2.2. Eylemler
Struts yapılandırma dosyasında bildirilen eylemler şunlardır:
<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>
Tek eylem /liste olarak adlandırılır ve istia.st.struts.articles.ListeArticlesAction sınıfıyla ilişkilidir. Bu eylem, aşağıdakilerden biriyle sonuçlanır:
- makaleler sayfası (/vues/listarticles.jsp)
- hata sayfası (/vues/erreurs.jsp)
9.2.3. Mesaj dosyası
ApplicationResources.properties mesaj dosyası, WEB-INF/classes/istia/st/struts/articles klasörüne yerleştirilecektir. İçeriği şu şekilde olacaktır:
# hatalar
errors.header=<ul>
errors.footer=</ul>
erreur.dbarticles=<li>Erreur d'accès à la base des articles ({0})</li>
Tek bir hata meydana gelebilir: veritabanına erişim hatası. Aslında birkaç farklı hata türü söz konusu olabilir, ancak hepsi aynı hata mesajında toplanır. Bununla birlikte, hatanın kesin nedeni {0} parametresinde belirtilecektir.
9.3. Görünümler
9.3.1. erreurs.jsp görünümü
Bu görünüm bir hata listesi göstermelidir. Bu görünümü daha önce birkaç kez gördük.
<%@ 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>
Bu görünüm, yalnızca <html:errors/> etiketiyle hata listesini görüntüler.
9.3.2. listarticles.jsp görünümü
Bu görünüm, veritabanındaki ARTICLES tablosunun içeriğini görüntülemelidir. Kod şöyledir:
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<%
// listarticles: Sorguda ArrayList
// listArticles(i): 5 elemanlı dizi (String[5])
%>
<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>
/liste komutu, ARTICLES tablosunun içeriğini, sorguda listArticles adıyla yer alan ArrayList nesnesine aktaracaktır. listArticles nesnesinin her bir öğesi, tablodaki bir ürünle ilgili 5 bilgiyi (kod, ad, fiyat, stockActuel, stockMinimum) temsil eden 5 karakter dizisinden oluşan bir dizidir. Görünüm, listArticles nesnesinin içeriğini bir HTML tablosunda görüntülemelidir. Bunun için <logic:iterate> etiketini kullanır:
<logic:iterate id="ligne" name="listArticles">
<tr>
<logic:iterate id="colonne" name="ligne">
<td><bean:write name="colonne"/></td>
</logic:iterate>
</tr>
</logic:iterate>
Burada iki yineleme vardır. İlki, ArrayList ve listArticles nesnelerinin öğeleri üzerinde döngü yapar. listArticles nesnesinin geçerli öğesine burada satır denir. Satır öğesi, ikinci yineleme yardımıyla taranan bir String[5] nesnesini temsil eder. Bu ikinci yinelemenin öğesine "sütun" denir. Bu, bir karakter dizisi tablosunun geçerli öğesini temsil eder ve dolayısıyla bir karakter dizisidir (kod, isim, fiyat, stockActuel, stockMinimum). Değeri, <bean:write> etiketiyle görüntülenir.
Görünüm, struts-logic ve struts-bean kütüphanelerine ait etiketleri kullanır. Bu nedenle, bunların kullanımını bildirmek gerekir:
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
9.4. /liste eylemi
/liste eyleminin amacı, bir görünümün bu verileri kullanabilmesi için ARTICLES tablosunun içeriğini temsil eden ArrayList nesnesini isteğe eklemektir. Kod şu şekildedir:
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 {
// bir bağlantının "articles" tablosunun içeriğini okur
// bağlamın başlatılması sırasında gerçekleştirilen
// "dbarticles" veri kaynağı alınır
DataSource dataSource = this.getDataSource(request, "dbarticles");
if (dataSource == null) {
// veri kaynağı oluşturulamadı
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");
}
// burada veri kaynağı mevcut - bu kullanılıyor Connection bağlantı = null;
Statement st = null;
ResultSet rs = null;
String requête = null;
ArrayList alArticles = new ArrayList();
// hataları işliyoruz
try {
// bağlantı kuruluyor
connexion = dataSource.getConnection();
// sorguyu hazırla SQL
requête =
"select code, nom, prix, stockActuel, stockMinimum from articles order by nom";
// yürütülür
st = connexion.createStatement();
rs = st.executeQuery(requête);
// sonuçları değerlendirme
while (rs.next()) {
// geçerli satırı kaydet
alArticles.add(
new String[] {
rs.getString("code"),
rs.getString("nom"),
rs.getString("prix"),
rs.getString("stockactuel"),
rs.getString("stockMinimum")});
// sonraki satır
} //while
// kaynakları serbest bırak
rs.close();
st.close();
connexion.close();
} catch (Exception ex) {
// hatalar oluştu
ActionErrors erreurs = new ActionErrors();
erreurs.add("dbarticles",new ActionError("erreur.dbarticles", ex.getMessage()));
this.saveErrors(request, erreurs);
return mapping.findForward("afficherErreurs");
}
// tamam
request.setAttribute("listArticles", alArticles);
return mapping.findForward("afficherListeArticles");
} //çalıştır
} //sınıf
Okuyucu, şüphesiz yukarıdaki kodun özünü anlayabilir. Burada sadece tek bir yenilik üzerinde duracağız: Struts çerçeve yapısı tarafından sağlanan DataSource nesnesinin kullanımı. Bu DataSource nesnesi, yapılandırma dosyasının <data-source key="dbarticles"> bölümüyle yapılandırılan bağlantı havuzunu temsil eder. DataSource nesnesi, oluşturulduktan sonra uygulama bağlamına yerleştirilmiştir; böylece bu bağlamdaki tüm nesneler bu nesneye erişebilir. Dolayısıyla, şu şekilde çağrılır:
// dbarticles veri kaynağını alıyoruz
DataSource dataSource = this.getDataSource(request, "dbarticles");
Burada, "dbarticles" anahtarıyla tanımlanan veri kaynağını talep ediyoruz. Eğer null işaretçisini alırsak, bu, uygulamanın başlatılması sırasında veri kaynağının oluşturulamadığı anlamına gelir. Bu durumda, hatayı bir ActionErrors nesnesine kaydediyoruz ve yapılandırma dosyasında "afficherErreurs" anahtarıyla tanımlanan hata sayfasına kontrolü devrediyoruz:
<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>
Veri kaynağına ulaştıktan sonra, bağlantı havuzuna erişebiliriz. Veritabanına bağlantı şu kodla kurulur:
Burada, havuz bize geri dönüştürülmüş bir bağlantı ya da yeni oluşturulabilecek bir bağlantı sağlayacaktır.
9.5. Dağıtım
Uygulamanın bağlamı, Tomcat'ın server.xml yapılandırma dosyasında tanımlanır:
<Context path="/listarticles" reloadable="true" docBase="E:\data\serge\web\struts\articles\liste" />
Uygulamanın dizin yapısı şu şekildedir:
![]() ![]() | ||
![]() ![]() | ||
![]() | ||
WEB-INF/lib dizininde bulunan mysql-connector-java-3.0.10-stable-bin.jar kütüphanesine dikkat edin. Burada kullanılan MySQL tabanındaki JDBC sürücüsü bu kütüphanede yer almaktadır.
9.6. Testler
Tomcat’ı başlatıyoruz ve URL http://localhost:8080/listarticles/liste.do adresini çağırıyoruz:

9.7. İkinci bir veri kaynağı
Şimdi bir Postgres veritabanında bulunan ikinci bir veri kaynağını kullanıyoruz. Burada da veriler, öncekiyle aynı sütunlara sahip ARTICLES tablosunda yer almaktadır. İçeriği şöyledir:

Bu yeni veri kaynağı, Struts yapılandırma dosyasında şu şekilde tanımlanmıştır:
<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>
Yeni kaynağın tanımlayıcısı (anahtarı) pgdbarticles olacaktır. Bu yenilik, javax.sql.DataSource arayüzünü uygulayan sınıftan kaynaklanmaktadır. Varsayılan sınıf, struts.jar kütüphanesinde tanımlanan org.apache.struts.util.GenericDataSource sınıfıdır. Bu sınıf, Struts’un gelecek sürümlerinde kullanımdan kaldırılacaktır ve 1.1 sürümü için commons-dbcp-1.1.jar kütüphanesinde bulunan org.apache.commons.dbcp.BasicDataSource sınıfının kullanılması tavsiye edilir. Bu sınıf, Struts paketiyle birlikte gelmeyebilir. Bu sınıfa http://jakarta.apache.org/commons/index.html adresinden, daha spesifik olarak da http://jakarta.apache.org/site/binindex.cgi adresinden ulaşılabilir. Commons DBCP adlı ürünü indirmeniz gerekir. Windows için .zip dosyasını indirebilirsiniz. Bu dosya, kütüphanenin kaynak kodunu ve ilgili .jar dosyasını içerir. Bu dosyayı .zip arşivinden çıkararak uygulamanın WEB-INF/lib klasörüne yerleştirmelisiniz. Ayrıca, kullanılan SGBD sürücüsünü de aynı klasöre yerleştirmelisiniz:

Bu kaynak kodunu kullanmak için, /liste eyleminin kodundaki bir komutu değiştiriyoruz:
Bu sefer, pgdbarticles adlı veri kaynağını, c.a.d olarak belirleyerek Postgres veri kaynağını talep ediyoruz.
Artık tek yapmamız gereken, tümünü derlemek, Tomcat'i başlatmak ve URL http://localhost:8080/listarticles/liste.do adresini çağırmak:

9.8. Sonuç
Bir veritabanına erişmek için bağlantı havuzunun nasıl kullanılacağını gösterdik. Burada, MVC mimarisine uymadığımızı belirtelim. Aslında, /liste eylemi verilere erişmek için SQL sorgularını kendisi gerçekleştiriyor. Bu eylemin, verilerin bir SGBD'ten alınacağını gizleyecek bir ara iş sınıfına başvurması daha uygun olurdu. Muhtemelen bu durumda bağlantı havuzunu iş sınıfı oluştururdu ve Struts yapılandırma dosyasında bunu belirtmeye gerek kalmazdı. Bu bir ipucu: Yapılandırma dosyasında bir <data-sources> bölümünün bulunması, uygulamamızın MVC mimarisine uymadığı anlamına gelebilir.





