3. Java servletlerine ve JSP sayfalarına giriş
Bu bölümde çeşitli servlet ve JSP sayfalarına ilişkin örnekler yer almaktadır. Bu örnekler Tomcat sunucusu ile test edilmiştir. Sunucu 8080 numaralı bağlantı noktasında çalışmaktadır. Ana sayfanın bağlantılarını takip ederek servlet ve JSP sayfalarına ilişkin örneklere erişilebilir. Aşağıdaki örneklerin çoğu Tomcat örneklerinden alınmıştır. Bunları test etmek için Tomcat'i başlatmanız, bir tarayıcıyla URL http://localhost:8080 adresine gitmeniz ve servlet bağlantılarını takip etmeniz yeterlidir.
![]() | ![]() |
3.1. Java Servlet'leri
3.1.1. Bir web istemcisine HTML içeriği göndermek
Yukarıdaki Hello World örneğini inceleyeceğiz. Servlet şu şekildedir:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class HelloWorld extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World!</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Hello World!</h1>");
out.println("</body>");
out.println("</html>");
}
}
Bu servlet çalıştırıldığında aşağıdaki görüntü elde edilir:

Aşağıdaki noktalara dikkat edilmelidir:
- Servletler için özel sınıfların içe aktarılması gerekir:
import javax.servlet.*;
import javax.servlet.http.*;
javax.servlet kütüphanesi, JDK ile her zaman standart olarak birlikte gelmez. Bu durumda, kütüphaneyi doğrudan Sun'ın web sitesinden indirebilirsiniz.
- Bir servlet, HttpServlet sınıfından türetilir
public class HelloWorld extends HttpServlet {
- Servlete yapılan bir GET isteği, doGet yöntemi tarafından işlenir
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
- Aynı şekilde, servlete yapılan POST isteği, doPost yöntemi tarafından işlenir
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
- HttpServletRequest request nesnesi, web istemcisi tarafından yapılan isteğe erişim sağlamamıza olanak tanıyan nesnedir. Servletin yanıtı, HttpServletResponse response nesnesi aracılığıyla verilecektir.
- response nesnesi, istemciye gönderilecek HTTP başlıklarını ayarlamamızı sağlar. Örneğin, Content-type: text/html başlığı burada şu şekilde ayarlanır:
- Yanıtı istemciye göndermek için servlet, response nesnesi tarafından sağlanan bir çıkış akışını kullanır:
- Bu çıkış akışı elde edildiğinde, HTML kodu bu akışa yazılır ve böylece istemciye gönderilir:
out.println("<html>");
out.println("<body>");
out.println("<head>");
out.println("<title>Hello World!</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Hello World!</h1>");
out.println("</body>");
out.println("</html>");
3.1.2. Web istemcisi tarafından gönderilen parametreleri alma
Aşağıdaki örnek, bir servletin web istemcisi tarafından gönderilen parametreleri nasıl alabileceğini gösterir. Bir giriş formu:

Servlet tarafından gönderilen yanıt:

Servlet'in kaynak kodu şöyledir:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class myRequestParamExample extends HttpServlet {
String title="Récupération des paramètres d'un formulaire";
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<head>");
out.println("<title>" + title + "</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
out.println("<h3>" + title + "</h3>");
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
if (firstName != null || lastName != null) {
out.println("firstname= " + firstName + "<br>");
out.println("lastname= " + lastName);
} else {
out.println("pas de paramètres");
}
out.println("<P>");
out.print("<form action=\"RequestParamExample\" method=\"POST\">");
out.println("firstname= <input type=text size=20 name=firstname>");
out.println("<br>");
out.println("lastname= <input type=text size=20 name=lastname>");
out.println("<br>");
out.println("<input type=submit>");
out.println("</form>");
out.println("</body>");
out.println("</html>");
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
doGet(request, response);
}
}
Önceki örneğe kıyasla aşağıdaki yeniliklere dikkat edilmelidir:
- Tarayıcı tarafından gönderilen parametreler şu şekilde alınır:
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
request.getParameter("nomParamètre") yöntemi, nomParamètre parametresi web istemcisi tarafından gönderilen parametreler arasında yer almıyorsa, null işaretçisini döndürür.
- Form, tarayıcının parametreleri POST yöntemi ile göndermesi gerektiğini belirtir
- Alınan parametreler, servletin doPost yöntemi tarafından işlenecektir. Burada bu yöntem, yalnızca doGet yöntemini çağırmaktadır. Dolayısıyla bu servlet, ister GET ister POST tarafından gönderilmiş olsun, form değerlerini işler.
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
doGet(request, response);
}
3.1.3. Bir web istemcisi tarafından gönderilen HTTP başlıklarını alma
Aşağıdaki servlet, web istemcisi tarafından gönderilen HTTP başlıklarını nasıl alacağınızı gösterir:

Servletin kaynak kodu şöyledir:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class RequestHeaderExample extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
Enumeration e = request.getHeaderNames();
while (e.hasMoreElements()) {
String name = (String)e.nextElement();
String value = request.getHeader(name);
out.println(name + " = " + value);
}
}
}
Dikkat edilmesi gereken noktalar:
- Tarayıcı tarafından bir dizi halinde gönderilen HTTP başlıklarına erişimimizi sağlayan, request nesnesi ve getHeaderNames yöntemidir:
- request.getHeader("başlık") yöntemi, belirli bir HTTP başlığını elde etmemizi sağlar. Yukarıdaki örnek, bunlardan birkaçını göstermektedir. Burada sunulan başlıkların tarayıcı tarafından gönderildiğini unutmayalım. Sunucunun da kendi HTTP başlıkları vardır ve bunlar bazen tarayıcının başlıklarını tekrarlar. Tarayıcı tarafından gönderilen HTTP başlıklarının amacı, sunucuya tarayıcının yetenekleri hakkında bilgi vermektir.
Başlık | Anlamı |
tarayıcının kimliği | |
Tarayıcı tarafından desteklenen MIME formatları. Dolayısıyla image/gif, tarayıcının GIF formatındaki görüntüleri işleyebildiğini gösterir. | |
hote:port formatında. Tarayıcının hangi makineye ve hangi bağlantı noktasına bağlanmak istediğini gösterir. | |
tarayıcının, sunucu tarafından gönderilen belgeler için kabul ettiği kodlama biçimi. Dolayısıyla, bir sunucuda normal, sıkıştırılmamış bir belge ile gzip sıkıştırma biçimine sahip bir belge varsa ve tarayıcı gzip biçimini işleyebileceğini belirtmişse, sunucu bant genişliğinden tasarruf etmek için belgeyi gzip biçiminde gönderebilir. | |
tarayıcı tarafından desteklenen diller. Bir sunucuda aynı belgenin birden fazla dilde kopyası varsa, sunucu tarayıcı tarafından desteklenen dildeki kopyayı gönderir. | |
tarayıcı tarafından talep edilen URL | |
tarayıcı tarafından talep edilen bağlantı modu. Keep-alive, sunucunun talep edilen sayfayı tarayıcıya gönderdikten sonra bağlantıyı kesmemesi gerektiği anlamına gelir. Tarayıcı, alınan sayfanın örneğin resimlere yönlendiren bağlantılar içerdiğini tespit ederse, yeni bir bağlantı kurmaya gerek kalmadan sunucuya yeni istekler gönderebilir. Sayfanın tüm öğelerini aldıktan sonra, bağlantıyı kapatma inisiyatifini tarayıcı üstlenecektir. |
3.1.4. Çalışma ortamı bilgilerini alma
Aşağıdaki servlet, servletin çalışma ortamı bilgilerine nasıl erişileceğini gösterir. Bu bilgilerden bazıları tarayıcı tarafından HTTP başlıkları şeklinde gönderilir ve bu nedenle önceki yöntemle alınabilir.

Servlet kodu şöyledir:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class RequestInfo extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<head>");
out.println("<title>Request Information Example</title>");
out.println("</head>");
out.println("<body>");
out.println("<h3>Request Information Example</h3>");
out.println("Method: " + request.getMethod());
out.println("Request URI: " + request.getRequestURI());
out.println("Protocol: " + request.getProtocol());
out.println("PathInfo: " + request.getPathInfo());
out.println("Remote Address: " + request.getRemoteAddr());
out.println("</body>");
out.println("</html>");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
doGet(request, response);
}
}
Buradaki bilgiler çeşitli yöntemlerle elde edilmiştir:
out.println("Method: " + request.getMethod());
out.println("Request URI: " + request.getRequestURI());
out.println("Protocol: " + request.getProtocol());
out.println("PathInfo: " + request.getPathInfo());
out.println("Remote Address: " + request.getRemoteAddr());
Kullanılabilir yöntemlerden bazılarının listesi ve anlamları aşağıdaki gibidir:
yöntem | anlam |
web sunucusunun adı | |
web sunucusunun çalışma bağlantı noktası | |
tarayıcının isteğini göndermek için kullandığı GET veya POST yöntemi | |
tarayıcının isteğini gönderdiği istemci makinesinin adı | |
aynı makinenin IP adresi | |
tarayıcı tarafından gönderilen içerik türü (http başlığı Content-type) | |
tarayıcı tarafından gönderilen karakter sayısı (http başlığı Content-length) | |
tarayıcı tarafından istenen http protokolünün sürümü | |
Tarayıcı tarafından istenen URI. http://hote:port/URI dosyasındaki hote:port tanımlamasından sonra gelen URL kısmına karşılık gelir |
3.1.5. JBuilder ile bir servlet oluşturma ve Tomcat ile dağıtma
Şimdi bir Java servlet'inin nasıl oluşturulacağını ve çalıştırılacağını açıklayacağız. İki araç kullanacağız: servlet'i derlemek için JBuilder ve çalıştırmak için Tomcat. Tomcat tek başına yeterli olabilir. Ancak, sınırlı hata ayıklama özellikleri sunar. Sunucu tarafından alınan parametreleri görüntüleyen, daha önce geliştirilen örneği tekrar ele alıyoruz. Servlet öncelikle aşağıdaki giriş formunu gönderir:

Servlet tarafından gönderilen yanıt:

Servletin kaynak kodu şöyledir:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class myRequestParamExample extends HttpServlet {
String title="Récupération des paramètres d'un formulaire";
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<head>");
out.println("<title>" + title + "</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
out.println("<h3>" + title + "</h3>");
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
if (firstName != null || lastName != null) {
out.println("firstname= " + firstName + "<br>");
out.println("lastname= " + lastName);
} else {
out.println("pas de paramètres");
}
out.println("<P>");
out.print("<form action=\"RequestParamExample\" method=\"POST\">");
out.println("firstname= <input type=text size=20 name=firstname>");
out.println("<br>");
out.println("lastname= <input type=text size=20 name=lastname>");
out.println("<br>");
out.println("<input type=submit>");
out.println("</form>");
out.println("</body>");
out.println("</html>");
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
doGet(request, response);
}
}
- JBuilder ile myRequestParamExample adlı bir proje oluşturun ve önceki myRequestParamExample.java programını bu projeye ekleyin.
- Derleme sırasında şu sorunla karşılaşabilirsiniz: JBuilder dosyanız, servletlerin derlenmesi için gerekli olan javax.servlet kütüphanesine sahip olmayabilir. Bu durumda, JBuilder'ı ek sınıf kütüphanelerini kullanacak şekilde yapılandırmanız gerekir. Bu işlem, bu belgenin eklerinde JBuilder 7 için açıklanmıştır. Burada kısmen özetliyoruz:
- Tools/Configure JDKs seçeneğini etkinleştirin veya (Options/Configure JDK)

Yukarıdaki JDK Ayarlar bölümünde, normalde Name alanında JDK 1.3.1 sürümü bulunur. Daha yeni bir JDK sürümünüz varsa, Change düğmesini kullanarak bu sürümün kurulum dizinini belirtin. Yukarıda, JDK 1.4 sürümünün kurulu olduğu E:\Program Files\jdk14 dizini belirtilmiştir. Artık JBuilder, derleme ve çalıştırma işlemleri için bu JDK sürümünü kullanacaktır. (Sınıf, Kaynak, Belgeler) bölümünde, JBuilder tarafından taranacak tüm sınıf kütüphanelerinin listesi bulunur; burada JDK 1.4 sürümünün sınıfları yer almaktadır. Bu sürümün sınıfları, Java ile web geliştirme yapmak için yeterli değildir. Diğer sınıf kütüphanelerini eklemek için Add düğmesini kullanır ve kullanmak istediğiniz ek .jar dosyalarını belirtirsiniz. .jar dosyaları sınıf kütüphaneleridir. Tomcat 4.x, web geliştirme için gerekli tüm sınıf kütüphanelerini beraberinde getirir. Bunlar, <tomcat>\common\lib dizininde bulunur; burada <tomcat>, Tomcat'in kurulum dizinidir:

Add düğmesi ile bu kütüphaneleri, JBuilder tarafından taranan kütüphane listesine tek tek ekleyeceğiz:

Artık J2EE standardına uygun Java programlarını, özellikle de Java servlet'lerini derleyebiliriz. JBuilder yalnızca derleme için kullanılır; yürütme işlemi daha sonra Tomcat tarafından gerçekleştirilir.
- Artık myRequestParamExample.java programını derleyebilir ve myRequestParamExample.class servletini oluşturabilirsiniz. Bu servleti nereye yerleştirmelisiniz? Tomcat'in başlangıç yapılandırması değiştirilmediyse, servletlerin .class dosyaları <tomcat>\webapps\examples\WEB-INF\classes (Tomcat 4.x) dizinine yerleştirilmelidir.
- Tomcat'in çalıştığını kontrol edin ve bir tarayıcıdan http://localhost:8080/examples/servlet/myRequestParamExample adresini açın:

3.1.6. Örnekler
Aşağıdaki örneklerde, daha önce açıklanan yöntemi kullandık:
- JBuilder ile XX.java servlet kaynak kodunun derlenmesi
- XX.class servlet'inin <tomcat>\webapps\examples\WEB-INF\classes dizinine dağıtılması
- Tomcat başlatıldıktan sonra, bir tarayıcıdan URL adresine http://localhost:8080/examples/servlet/XX şeklinde erişin
3.1.6.1. Dinamik form oluşturma - 1
Örnek olarak, tek bir denetim içeren bir formun oluşturulmasını ele alacağız: bir liste. Bu listenin içeriği, bir diziden alınan değerlerle dinamik olarak oluşturulur. Gerçek hayatta bu değerler genellikle bir veritabanından alınır. Form şu şekildedir:

Yukarıdaki örnekte Envoyer komutunu çalıştırırsak, şu yanıtı alırız:

Yanıtı oluşturan URL kodunun, formu görüntüleyen kodla aynı olduğu dikkatinizi çekecektir. Burada, gönderdiği forma verilen yanıtı kendisi işleyen bir servlet bulunmaktadır. Bu, sık karşılaşılan bir durumdur. Formun HTML kodu şu şekildedir:
<html>
<head><title>Génération de formulaire</title></head>
<body>
<h3>Choississez un nombre</h3><hr>
<form method="POST">
<select name="cmbValeurs" size="1">
<option>zéro</option>
<option>un</option>
<option>deux</option>
<option>trois</option>
<option>quatre</option>
<option>cinq</option>
<option>six</option>
<option>sept</option>
<option>huit</option>
<option>neuf</option>
</select>
<input type="submit" value="Envoyer">
</form>
</body>
</html>
Form tarafından gönderilen değerlerin POST yöntemi ile gönderildiğine dikkat edilmelidir. Yanıtta yer alan HTML kodu:
<html>
<head><title>Voici ma réponse</title></head>
<body>
Vous avez choisi le nombre<h2>neuf</h2>
</body>
</html>
Bu formu ve yanıtı oluşturan servlet kodu şöyledir:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class gener1 extends HttpServlet{
// örnek değişkenleri
private String title="Génération d'un formulaire";
private final String[] valeurs={"zéro","un","deux","trois","quatre","cinq","six",
"sept","huit","neuf"};
private final String HTML1=
"<html>" +
"<head>" +
"<title>Génération de formulaire</title>"+
"</head>" +
"<body>" +
"<h3>Choississez un nombre</h3>"+
"<hr>" +
"<form method=\"POST\">";
private final String HTML2="<input type=\"submit\" value=\"Envoyer\">";
private final String HTML3="</form>\n</body>\n</html>";
// GET
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// müşteriye gönderilen belgenin türü bildirilir
response.setContentType("text/html");
// form gönderilir
PrintWriter out=response.getWriter();
// başlangıç
out.println(HTML1);
// açılır menü
out.println("<select name=\"cmbValeurs\" size=\"1\">");
for (int i=0;i<valeurs.length;i++){
out.println("<option>"+valeurs[i]+"</option>");
}//for
out.println("</select>");
// form sonu
out.println(HTML2+HTML3);
}//GET
// POST
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// kullanıcının seçimi alınır
String choix=request.getParameter("cmbValeurs");
if(choix==null) doGet(request,response);
// yanıt hazırlanıyor
String réponse="<html><head><title>Voici ma réponse</title></head>";
réponse+="<body>Vous avez choisi le nombre <h2>"+choix+"</h2></body></html>";
// müşteriye gönderilen belgenin türünü bildirilir
response.setContentType("text/html");
// form gönderilir
PrintWriter out=response.getWriter();
out.println(réponse);
}//POST
}//sınıflandırma
doGet yöntemi, formu oluşturmak için kullanılır. Listedeki içerik gibi dinamik bir kısım vardır; bu içerik burada bir tablodan alınmaktadır. doPost yöntemi ise yanıtı oluşturmak için kullanılır. Burada tek dinamik kısım, kullanıcının formdaki listeden yaptığı seçimin değeridir. Bu değer, request.getParameter("cmbValeurs") ile elde edilir; burada cmbValeurs, listenin adı olan HTML'tir:
Son olarak şu noktalara dikkat edilmelidir:
- <form> etiketinde <action> özniteliği bulunmadığından, tarayıcı form değerlerini formu oluşturan servlete gönderir. Bu durumda, tarayıcı formda girilen verileri, formu sağlayan URL'e gönderir.
- <form> etiketi, form verilerinin POST yöntemi ile gönderilmesi gerektiğini belirtir. Bu nedenle bu değerler, servletin doPost yöntemi tarafından alınır.
3.1.6.2. Dinamik form oluşturma - 2
Önceki örneği şu şekilde değiştirerek ele alalım. Sunulan form hala aynıdır:

Peki yanıt farklı mı?

Yanıtta, form geri gönderilir ve kullanıcının seçtiği sayı formun altında belirtilir. Ayrıca, bu sayı, liste görüntülendiğinde seçili olarak görünen sayıdır. Kullanıcı daha sonra başka bir sayı seçebilir:

ardından Envoyer komutunu verebilir. Şu yanıtı alır:

gener2.java adlı servletin kodu şöyledir:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class gener2 extends HttpServlet{
// örnek değişkenleri
private String title="Génération d'un formulaire";
private final String[] valeurs={"zéro","un","deux","trois","quatre","cinq","six",
"sept","huit","neuf"};
private final String HTML1=
"<html>" +
"<head>" +
"<title>Génération de formulaire</title>"+
"</head>" +
"<body>" +
"<h3>Choisissez un nombre</h3>"+
"<hr>" +
"<form method=\"POST\">";
private final String HTML2="<input type=\"submit\" value=\"Envoyer\"></form>\n";
private final String HTML3="</body>\n</html>";
// GET
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// kullanıcının olası seçimini alır
String choix=request.getParameter("cmbValeurs");
if(choix==null) choix="";
// müşteriye gönderilen belgenin türünü bildirilir
response.setContentType("text/html");
// form gönderilir
PrintWriter out=response.getWriter();
// başlangıç
out.println(HTML1);
// açılır menü
out.println("<select name=\"cmbValeurs\" size=\"1\">");
String selected="";
for (int i=0;i<valeurs.length;i++){
if(valeurs[i].equals(choix)) selected="selected"; else selected="";
out.println("<option "+selected+">"+valeurs[i]+"</option>");
}//for
out.println("</select>");
// formun devamı
out.println(HTML2);
if(! choix.equals("")){
// kullanıcının seçimi görüntüleniyor
out.println("<hr>Vous avez choisi le nombre <h2>"+choix+"</h2>");
}//eğer
// formun sonu
out.println(HTML3);
}//GET
// POST
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// GET'e yönlendirilir
doGet(request,response);
}//POST
}//sınıf
doGet yöntemi her şeyi yapar: müşteriye göndereceği formu oluşturur ve müşterinin geri gönderdiği değerleri işler. Dikkat edilmesi gereken noktalar şunlardır:
- cmbValeurs parametresinin bir değeri olup olmadığı kontrol edilir.
- Eğer varsa, liste içeriği oluşturulurken listenin her bir öğesi kullanıcının seçimi ile karşılaştırılır ve kullanıcının seçtiği öğeye selected özniteliği eklenir: <option selected>öğe</option>. Ayrıca, formun altında seçimin değeri görüntülenir.
3.1.6.3. Dinamik form oluşturma - 3
Önceki örnekle aynı sorunu ele alıyoruz, ancak bu sefer değerler bir veritabanından alınmaktadır. Örneğimizde bu veritabanının adı MySQL'tir:
- veritabanının adı dbValeurs'tir
- sahibi admDbValeurs olup, şifresi mdpDbValeurs'tir
- veritabanında tvaleurs adlı tek bir tablo bulunmaktadır
- Bu tablonun "değer" adlı tek bir tamsayı alanı vardır
E:\Program Files\EasyPHP\mysql\bin>mysql --database=dbValeurs --user=admDbValeurs --password=mdpDbVa
leurs
mysql> show tables;
+---------------------+
| Tables_in_dbValeurs |
+---------------------+
| tvaleurs |
+---------------------+
1 row in set (0.00 sec)
mysql> describe tvaleurs;
+--------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------+------+-----+---------+-------+
| valeur | int(11) | | | 0 | |
+--------+---------+------+-----+---------+-------+
mysql> select * from tvaleurs;
+--------+
| valeur |
+--------+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 6 |
| 5 |
| 7 |
| 8 |
| 9 |
+--------+
10 rows in set (0.00 sec)
MySQL dbValeurs veritabanı, ODBC sürücüsü aracılığıyla MySQL için erişime açılmıştır. Adı DSN (Veri Kaynağı Adı) odbc-valeurs'tur. Servlet kodu şöyledir:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
import java.util.*;
public class gener3 extends HttpServlet{
// sayfa başlığı
private final String title="Génération d'un formulaire";
// liste değerleri veritabanı
private final String DSNValeurs="odbc-valeurs";
private final String admDbValeurs="admDbValeurs";
private final String mdpDbValeurs="mdpDbValeurs";
// liste değerleri
private String[] valeurs=null;
// hata mesajı
private String msgErreur=null;
// kod HTML
private final String HTML1=
"<html>" +
"<head>" +
"<title>Génération de formulaire</title>"+
"</head>" +
"<body>" +
"<h3>Choisissez un nombre</h3>"+
"<hr>" +
"<form method=\"POST\">";
private final String HTML2="<input type=\"submit\" value=\"Envoyer\"></form>\n";
private final String HTML3="</body>\n</html>";
// GET
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// müşteriye gönderilen belge türü bildirilir
response.setContentType("text/html");
// çıkış akışı
PrintWriter out=response.getWriter();
// servlet'in başlatılması başarılı oldu mu?
if (msgErreur!=null){
// bir hata oluştu - bir hata sayfası oluşturulur
out.println("<html><head><title>"+title+"</title></head>");
out.println("<body><h3>Application indisponible ("+msgErreur+
")</h3></body></html>");
return;
}//if
// kullanıcının seçimini alınıyor
String choix=request.getParameter("cmbValeurs");
if(choix==null) choix="";
// form gönderiliyor
// başlangıç
out.println(HTML1);
// açılır menü
out.println("<select name=\"cmbValeurs\" size=\"1\">");
String selected="";
for (int i=0;i<valeurs.length;i++){
if(valeurs[i].equals(choix)) selected="selected"; else selected="";
out.println("<option "+selected+">"+valeurs[i]+"</option>");
}//for
out.println("</select>");
// formun devamı
out.println(HTML2);
if(! choix.equals("")){
// kullanıcının seçimi görüntüleniyor
out.println("<hr>Vous avez choisi le nombre <h2>"+choix+"</h2>");
}//eğer
// formun sonu
out.println(HTML3);
}//GET
// POST
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// GET'e yönlendirilir
doGet(request,response);
}//POST
// servletin başlatılması
public void init(){
// değer tablosunu bir veritabanından doldurur ODBC
// adı DSN: DSNvaleurs
Connection connexion=null;
Statement st=null;
ResultSet rs=null;
try{
// ODBC veritabanına bağlanma
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
connexion=DriverManager.getConnection("jdbc:odbc:"+DSNValeurs,admDbValeurs,mdpDbValeurs);
// Statement nesnesi
st=connexion.createStatement();
// değerleri almak için select sorgusunun yürütülmesi
rs=st.executeQuery("select valeur from Tvaleurs");
// değerler alınır ve dinamik bir tabloya yerleştirilir
ArrayList lstValeurs=new ArrayList();
while(rs.next()){
// değer listeye kaydedilir
lstValeurs.add(rs.getString("valeur"));
}//while
// listeyi tabloya dönüştürme
valeurs=new String[lstValeurs.size()];
for (int i=0;i<lstValeurs.size();i++){
valeurs[i]=(String)lstValeurs.get(i);
}
}catch(Exception ex){
// sorun
msgErreur=ex.getMessage();
}finally{
try{rs.close();}catch(Exception ex){}
try{st.close();}catch(Exception ex){}
try{connexion.close();}catch(Exception ex){}
}//try
}//başlat
}//sınıf
Dikkat edilmesi gereken önemli noktalar şunlardır:
- Bir servlet, public void init() imzasına sahip bir yöntemle başlatılabilir. Bu yöntem, yalnızca servletin ilk yüklenmesi sırasında yürütülür
- Bir servlet, yüklendikten sonra sürekli olarak bellekte kalır. Bu, bir istemciye hizmet verdikten sonra bile servletin bellekten kaldırılmadığı anlamına gelir. Böylece istemcilerin isteklerine daha hızlı yanıt verir.
- Servletimizde, bir veritabanında bir değer listesi aranmalıdır. Bu liste zaman içinde değişmediğinden, init yöntemi bu listeyi almak için ideal zamandır. Böylece veritabanına, servletin ilk yüklenmesi sırasında sadece bir kez erişilir; her istemci isteğinde değil.
- Veritabanına erişim başarısız olabilir. Servlet’imizdeki init yöntemi, başarısızlık durumunda msgErreur hata mesajını ayarlar. Bu mesaj, doGet yönteminde kontrol edilir ve bir hata olması durumunda doGet, bunu bildiren bir sayfa oluşturur.
- init yönteminin yazımı, Odbc-Jdbc sürücüleri kullanılarak geleneksel bir veritabanı erişimi kullanır. Gerekirse, okuyucunun JDBC veritabanı erişim yöntemlerini gözden geçirmesi önerilir.
Servlet çalıştırıldığında ve MySQL sunucusu başlatılmamışsa, aşağıdaki hata sayfası görüntülenir:
![]()
Şimdi MySQL sunucusunu başlatırsak, şu sayfa görüntülenir:

6 sayısını seçip "gönder" düğmesine basarsak:

3.1.6.4. Bir formdan değerleri almak
Daha önce karşılaştığımız bir örneği tekrar ele alalım, şu web formunu:

balises2.htm formunun HTML kodu şöyledir:
<html>
<head>
<title>balises</title>
<script language="JavaScript">
function effacer(){
alert("Vous avez cliqué sur le bouton Effacer");
}//sil
</script>
</head>
<body background="/images/standard.jpg">
...
<form method="POST" action="http://localhost:8080/examples/servlet/parameters">
<table border="0">
<tr>
<td>Etes-vous marié(e)</td>
<td>
<input type="radio" value="Oui" name="R1">Oui
<input type="radio" name="R1" value="non" checked>Non
</td>
</tr>
<tr>
<td>Cases à cocher</td>
<td>
<input type="checkbox" name="C1" value="un">1
<input type="checkbox" name="C2" value="deux" checked>2
<input type="checkbox" name="C3" value="trois">3
</td>
</tr>
<tr>
<td>Champ de saisie</td>
<td>
<input type="text" name="txtSaisie" size="20" value="qqs mots">
</td>
</tr>
<tr>
<td>Mot de passe</td>
<td>
<input type="password" name="txtMdp" size="20" value="unMotDePasse">
</td>
</tr>
<tr>
<td>Boîte de saisie</td>
<td>
<textarea rows="2" name="areaSaisie" cols="20">
ligne1
ligne2
ligne3
</textarea>
</td>
</tr>
<tr>
<td>combo</td>
<td>
<select size="1" name="cmbValeurs">
<option>choix1</option>
<option selected>choix2</option>
<option>choix3</option>
</select>
</td>
</tr>
<tr>
<td>liste à choix simple</td>
<td>
<select size="3" name="lst1">
<option selected>liste1</option>
<option>liste2</option>
<option>liste3</option>
<option>liste4</option>
<option>liste5</option>
</select>
</td>
</tr>
<tr>
<td>liste à choix multiple</td>
<td>
<select size="3" name="lst2" multiple>
<option selected>liste1</option>
<option>liste2</option>
<option selected>liste3</option>
<option>liste4</option>
<option>liste5</option>
</select>
</td>
</tr>
<tr>
<td>bouton</td>
<td>
<input type="button" value="Effacer" name="cmdEffacer" onclick="effacer()">
</td>
</tr>
<tr>
<td>envoyer</td>
<td>
<input type="submit" value="Envoyer" name="cmdRenvoyer">
</td>
</tr>
<tr>
<td>rétablir</td>
<td>
<input type="reset" value="Rétablir" name="cmdRétablir">
</td>
</tr>
</table>
<input type="hidden" name="secret" value="uneValeur">
</form>
</body>
</html>
Formdaki <form> etiketi şu şekilde tanımlanmıştır:
Tarayıcı, form değerlerini URL http://localhost:8080/examples/servlet/parameters adresine "gönderecektir"; bu adres, Tomcat tarafından yönetilen ve önceki formun değerlerini görüntüleyen bir servletin URL adresidir. parameters servlet'i doğrudan çağrılırsa, şu sonuçlar elde edilir:

Girilen balises2.htm formu şuysa:

ve (submit türündeki) Gönder düğmesine basılırsa, bu sefer parameters servleti parametrelerle çağrılır. Ardından şu yanıtı döndürür:

Bu yanıtta, forma girilen değerlerin yer aldığı açıkça görülmektedir. Servlet'in kodu şöyledir:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class parameters extends HttpServlet{
// örnek değişkenleri
String title="Récupération des paramètres d'un formulaire";
private String getParameter(HttpServletRequest request, String contrôle){
// request.getParameter değerini (denetim) döndürür; yoksa "" değerini döndürür
String valeur=request.getParameter(contrôle);
if(valeur==null) return ""; else return valeur;
}//getParameter
// GET
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException
{
// öncelikle form parametrelerini alırız
String R1=getParameter(request,"R1");
String C1=getParameter(request,"C1");
String C2=getParameter(request,"C2");
String C3=getParameter(request,"C3");
String txtSaisie=getParameter(request,"txtSaisie");
String txtMdp=getParameter(request,"txtMdp");
String areaSaisie=getParameter(request,"areaSaisie");
String[] lignes=areaSaisie.split("\\r\\n");
String cmbValeurs=getParameter(request,"cmbValeurs");
String lst1=getParameter(request,"lst1");
String[] lst2=request.getParameterValues("lst2");
String secret=getParameter(request,"secret");
// belgenin içeriğini belirtiriz
response.setContentType("text/html");
// belgeyi gönderiyoruz
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<head>");
out.println("<title>" + title + "</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
out.println("<h3>" + title + "</h3>");
out.println("<hr>");
out.println("<table border=\"1\">");
out.println("<tr><td>R1</td><td>"+R1+"</td></tr>");
out.println("<tr><td>C1</td><td>"+C1+"</td></tr>");
out.println("<tr><td>C2</td><td>"+C2+"</td></tr>");
out.println("<tr><td>C3</td><td>"+C3+"</td></tr>");
out.println("<tr><td>txtSaisie</td><td>"+txtSaisie+"</td></tr>");
out.println("<tr><td>txtMdp</td><td>"+txtMdp+"</td></tr>");
for(int i=0;i<lignes.length;i++)
out.println("<tr><td>areaSaisie["+i+"]</td><td>"+lignes[i]+"</td></tr>");
out.println("<tr><td>cmbValeurs</td><td>"+cmbValeurs+"</td></tr>");
out.println("<tr><td>lst1</td><td>"+lst1+"</td></tr>");
if(lst2==null)
out.println("<tr><td>lst2</td><td></td></tr>");
else
for(int i=0;i<lst2.length;i++)
out.println("<tr><td>lst2</td><td>"+lst2[i]+"</td></tr>");
out.println("<tr><td>secret</td><td>"+secret+"</td></tr>");
out.println("</body>");
out.println("</html>");
}
// POST
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException
{
// GET'e yönlendirir
doGet(request,response);
}
}
Bu kodda, daha önce başka bir örnekte sunulan teknikler yer almaktadır. İki noktaya dikkat çekmek gerekir:
- lst2 kontrolü, çoklu seçim listesidir ve bu nedenle birden fazla öğe seçilebilir. Örneğimizde de liste1 ve liste3 öğeleri seçilmiştir. lst2 değerleri, tarayıcı tarafından sunucuya lst2=liste1&lst2=liste3 biçiminde iletilmiştir. Java servlet'i, getParameterValues yöntemiyle bu değerleri bir dizide alabilir: burada request.getParameterValues("lst2"), 2 karakter dizisinden oluşan bir dizi sağlar.
- areaSaisie kontrolü, çok satırlı bir giriş alanıdır. request.getParameter("areaSaisie") komutu, alanın içeriğini tek bir karakter dizesi biçiminde verir. Bu dizgede, onu oluşturan farklı satırları almak istersek, String sınıfındaki split işlevini kullanabiliriz. Aşağıdaki kod
giriş alanındaki satırları alır. Bu satırlar \r\n karakterleriyle (0D0A) sonlanır.
Testleri yapmak için şunları yaptık:
- daha önce açıklandığı gibi parameters servletini JBuilder ile birlikte oluşturup derledik
- oluşturulan sınıfı <tomcat>\webapps\examples\WEB-INF\classes dizinine yerleştirdik; burada <tomcat>, Tomcat'in kurulum dizinidir.
- Yukarıda kodu verilen URL http://localhost:81/html/balises2.htm adresine erişin
- formu doldurup Envoyer düğmesine tıkladım.
3.1.6.5. Bir web istemcisinden HTTP başlıklarını alma
Daha önce verdiğimiz örneği tekrar alıyoruz, ancak form değerlerini gönderen web istemcisine yanıt olarak, onun aynı anda gönderdiği HTTP başlıklarını geri gönderiyoruz. Formumuzda tek bir değişiklik yapıyoruz:
Form değerleri, GET yöntemi ile <tomcat>\webapps\examples\WEB-INF\classes dizininde bulunan headers adlı bir Java servlet'e gönderilecektir. headers servleti, JBuilder ile birlikte oluşturulmuş ve derlenmiştir:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class headers extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
// belgenin türü belirlenir
response.setContentType("text/html");
// yazma akışı elde edilir
PrintWriter out = response.getWriter();
// başlık listesi görüntülenir HTTP
Enumeration e = request.getHeaderNames();
while (e.hasMoreElements()) {
String name = (String)e.nextElement();
String value = request.getHeader(name);
out.println("<b>"+name + "</b> = " + value + "<br>");
}
}//GET
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
//GET
doGet(request,response);
}//POST
}
URL http://localhost:81/html/balises2.htm sorgusu isteniyor ve formda herhangi bir değişiklik yapmadan Envoyer sorgusu gerçekleştiriliyor. Aşağıdaki yanıt alınır:

Tarayıcının Address alanında bulunan URL parametresine dikkat edelim; bu, parametrelerin iletilme şeklini (GET) göstermektedir. Aynı örneği tekrar ele alalım, ancak parametrelerin gönderilme şeklini (POST) değiştirerek:
Böylece şu yeni yanıtı elde ediyoruz:

HTTP, content-type ve content-length başlıklarının, POST ile yapılan bir gönderime özgü olduğu dikkat çekmektedir. Ayrıca, tarayıcının Address alanında form değerlerinin artık görünmediğine dikkat edilmelidir.
3.2. JSP Sayfaları
JSP sayfaları (Java Sunucu Sayfaları), web sunucu uygulamaları yazmanın başka bir yoludur. Aslında bu JSP sayfaları, çalıştırılmadan önce servletlere dönüştürülür ve bu noktada servlet teknolojisiyle karşılaşırız. JSP sayfaları, oluşturulan HTML sayfalarının yapısını daha iyi ortaya koymaya olanak tanır. Aşağıda bazı örnekler sunuyoruz; bunlardan bazılarına Tomcat ana sayfasındaki JSP bağlantısını takip ederek erişilebilir:
![]() | ![]() |
3.2.1. Ortam bilgilerini alma
Burada, daha önce bir servlet ile ele aldığımız bir örneği tekrar ele alıyoruz: bir servletin ortam değişkenlerini görüntülemek. Bu, JSP örnekleri içindeki snoop örneğidir:

JSP sayfasının kaynak kodu şu konumda bulunur: <tomcat>\jakarta-tomcat\examples\jsp\snp\snoop.jsp (Tomcat 3.x) veya <tomcat>\examples\jsp\snp\snoop.jsp (Tomcat 4.x)
<html>
<!--
Copyright (c) 1999 The Apache Software Foundation. All rights
reserved.
-->
<body bgcolor="white">
<h1> Request Information </h1>
<font size="4">
JSP Request Method: <%= request.getMethod() %>
<br>
Request URI: <%= request.getRequestURI() %>
<br>
Request Protocol: <%= request.getProtocol() %>
<br>
Servlet path: <%= request.getServletPath() %>
<br>
Path info: <%= request.getPathInfo() %>
<br>
Path translated: <%= request.getPathTranslated() %>
<br>
Query string: <%= request.getQueryString() %>
<br>
Content length: <%= request.getContentLength() %>
<br>
Content type: <%= request.getContentType() %>
<br>
Server name: <%= request.getServerName() %>
<br>
Server port: <%= request.getServerPort() %>
<br>
Remote user: <%= request.getRemoteUser() %>
<br>
Remote address: <%= request.getRemoteAddr() %>
<br>
Remote host: <%= request.getRemoteHost() %>
<br>
Authorization scheme: <%= request.getAuthType() %>
<hr>
The browser you are using is <%= request.getHeader("User-Agent") %>
<hr>
</font>
</body>
</html>
Aşağıdaki noktalara dikkat çekmek isteriz:
- Buradaki kod, HTML'e çok benziyor. Ancak burada, JSP diline özgü <%= ifade %> etiketleri bulunuyor. JSP derleyicisi, HTML metnindeki etiketlerin tamamını expression değeriyle değiştirir.
- Bu örnekte, servletler konusunda daha önce ele alınan request nesnesinin bir türevi olan request Java nesnesinin yöntemleri kullanılmaktadır. Dolayısıyla bu, bir HttpServletRequest nesnesidir. Böylece, <%= request.getRemoteHost() %> etiketi, HTML kodunda, isteği gönderen web istemcisinin makine adıyla değiştirilecektir.
- Aynı sonuca bir servlet ile de ulaşılabilir, ancak burada web sayfasının yapısı daha açık ve anlaşılırdır.
3.2.2. Web istemcisi tarafından gönderilen parametreleri almak
Burada, daha önce bir servlet ile incelediğimiz örneği tekrar ele alıyoruz. Tarayıcıya bir form sunulur:

Yukarıdaki isteğe yanıt olarak, tarayıcıya şu sayfa gönderilir:

JSP sayfasının kodu şöyledir:
<%
// ana prosedüre özgü yerel değişkenler
String title="Récupération des paramètres d'un formulaire";
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
%>
<!-- kod HTML -->
<html>
<head>
<title><%= title %></title>
</head>
<body bgcolor="white">
<h3><%= title %></h3>
<%
if (firstName != null || lastName != null) {
out.println("firstname= " + firstName + "<br>");
out.println("lastname= " + lastName);
} else {
out.println("pas de paramètres");
}
%>
<P>
<form method="POST">
firstname= <input type="text" size="20" name="firstname">
<br>
lastname= <input type="text" size="20" name="lastname">
<br>
<input type="submit">
</form>
</body>
</html>
- Önceki örnekte de gördüğümüz <%= ifade %> etiketine ek olarak, yeni bir etiket daha ortaya çıkıyor: <% Java komutları; %>. <% etiketi, Java kodunu başlatır. Bu kod, %> kod kapatma etiketiyle karşılaşıldığında sona erer.
- Yukarıdaki kodun tamamı (HTML + JSP) bir Java servlet'ine dönüştürülecektir. Bu kod, JSP sayfasının ana yöntemi olarak adlandırılan tek bir yöntem içine alınacaktır. Bu nedenle, JSP sayfasının başında bildirilen Java değişkenleri, HTML kodunu oluşturan diğer JSP kod bölümlerinde de tanınır: bu değişkenler ve kod bölümleri aynı Java yönteminin parçası olacaktır. Ancak JSP kodumuzda yöntemler olsaydı, yöntemler arasındaki yalıtım nedeniyle title, firstname ve lastname değişkenleri bu yöntemlerde tanınmazdı. Bunları küresel değişkenler haline getirmemiz veya yöntemlere parametre olarak aktarmamız gerekir. Bu konuya daha sonra tekrar döneceğiz.
- HTML koduna dinamik bölümler eklemek için iki yöntem mümkündür: <%= ifade %> veya out.println(ifade). out nesnesi, servlet örneklerinde görülen aynı isimli çıktı akışına benzer, ancak aynı türde değildir: bu bir JspWriter nesnesidir, PrintWriter değildir. Bu nesne, HTML akışına print ve println yöntemleriyle veri yazmaya olanak tanır.
- JSP sayfası, oluşturulan HTML sayfasının yapısını, eşdeğer servlet'ten daha iyi yansıtmaktadır.
3.2.3. JSP etiketleri
Aşağıda, bir JSP sayfasında karşılaşılabilecek etiketlerin listesi ve anlamları yer almaktadır.
etiket | anlam |
açıklama HTML. İstemciye gönderilir. | |
açıklama JSP. Müşteriye gönderilmez. | |
Küresel değişkenleri ve yöntemleri tanımlar. Değişkenler tüm yöntemlerde kullanılabilir olacaktır | |
ifadenin değeri, HTML sayfasına | |
JSP sayfasının ana yönteminin bir parçası olacak Java kodu içerir | |
JSP sayfası için öznitelikleri belirler. Örneğin: import="java.util.*,java.sql.*", JSP sayfası için gerekli kütüphaneleri belirtmek amacıyla extends="uneClasseParent", JSP sayfasının başka bir sınıftan türetilmesini sağlamak için |
3.2.4. JSP örtük nesneleri
Önceki örneklerde, iki adet bildirilmemiş nesneyle karşılaştık: request ve out. Bunlar, JSP sayfasının dönüştürüldüğü servlet içinde otomatik olarak tanımlanan nesnelerden ikisidir. Bunlara örtük veya önceden tanımlanmış nesneler denir. Bunların dışında başka nesneler de vardır, ancak response nesnesiyle birlikte en çok kullanılanlar şunlardır:
nesne | anlam |
Web istemcisinin isteğine (getParameter, getParameterNames, getParameterValues) erişim sağlayan nesne | |
Web sunucusunun istemcisine vereceği yanıtı oluşturmak için kullanılan nesne. Web istemcisine gönderilecek HTTP başlıklarını belirlemeye olanak tanır. | |
HTML kodunu istemciye göndermemizi sağlayan çıkış akışı (print, println) |
3.2.5. Bir JSP sayfasının servlet'e dönüştürülmesi
myRequestParamExample.jsp'teki JSP kodunu tekrar ele alalım:
<%
// ana prosedürün yerel değişkenleri
String title="Récupération des paramètres d'un formulaire";
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
%>
<!-- kod HTML -->
<html>
<head>
<title><%= title %></title>
</head>
<body bgcolor="white">
<h3><%= title %></h3>
<%
if (firstName != null || lastName != null) {
out.println("firstname= " + firstName + "<br>");
out.println("lastname= " + lastName);
} else {
out.println("pas de paramètres");
}
%>
<P>
<form method="POST">
firstname= <input type="text" size="20" name="firstname">
<br>
lastname= <input type="text" size="20" name="lastname">
<br>
<input type="submit">
</form>
</body>
</html>
Tarayıcı, Tomcat sunucusundan bu JSP sayfasını istediğinde, sunucu bunu bir servlet'e dönüştürür. İstenen URL sayfası
http://localhost:8080/examples/jsp/perso/intro/myRequestParamExample.jsp ise, Tomcat 4.x oluşturulan servleti <tomcat>\work\localhost\examples\jsp\perso\intro dizinine yerleştirir:

Bu isimde, URL sayfasının http://localhost:8080/examples/jsp/perso/intro/myRequestParamExample.jsp adresi olan JSP'i görüyoruz. Yukarıda, JSP sayfası için oluşturulan servletin Java koduna erişilebildiği görülmektedir. Örneğimizde bu kod şöyledir:
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;
public class myRequestParamExample$jsp extends HttpJspBase {
static {
}
public myRequestParamExample$jsp( ) {
}
private static boolean _jspx_inited = false;
public final void _jspx_init() throws org.apache.jasper.runtime.JspException {
}
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
JspFactory _jspxFactory = null;
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
String _value = null;
try {
if (_jspx_inited == false) {
synchronized (this) {
if (_jspx_inited == false) {
_jspx_init();
_jspx_inited = true;
}
}
}
_jspxFactory = JspFactory.getDefaultFactory();
response.setContentType("text/html;charset=ISO-8859-1");
pageContext = _jspxFactory.getPageContext(this, request, response,
"", true, 8192, true);
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
// ana prosedürün yerel değişkenleri
String title="Récupération des paramètres d'un formulaire";
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
out.write("\r\n\r\n<!-- code HTML -->\r\n<html>\r\n <head>\r\n <title>");
out.print( title );
out.write("</title>\r\n </head>\r\n <body bgcolor=\"white\">\r\n <h3>");
out.print( title );
out.write("</h3>\r\n ");
if (firstName != null || lastName != null) {
out.println("firstname= " + firstName + "<br>");
out.println("lastname= " + lastName);
} else {
out.println("pas de paramètres");
}
out.write("\r\n <P>\r\n <form method=\"POST\">\r\n firstname= <input type=\"text\" size=\"20\" name=\"firstname\">\r\n <br>\r\n lastname= <input type=\"text\" size=\"20\" name=\"lastname\">\r\n <br>\r\n <input type=\"submit\">\r\n </form>\r\n </body>\r\n</html>\r\n");
} catch (Throwable t) {
if (out != null && out.getBufferSize() != 0)
out.clearBuffer();
if (pageContext != null) pageContext.handlePageException(t);
} finally {
if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);
}
}
}
Oluşturulan kod oldukça karmaşıktır. Sadece aşağıdaki noktalara odaklanacağız:
- Servlet'in ana yöntemi şöyledir:
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
Servlet'in başlatılmasıyla birlikte bu yöntem çağrılır. Görüldüğü gibi, bu yöntem iki parametre alır: istemciden gelen request isteği ve web istemcisine yanıt oluşturmak için kullanılan bir response nesnesi.
- Ana yöntemde, JspWriter adlı bir out nesnesi tanımlanıp başlatılır. Bu nesne, HTML kodunu, out.print("codeHTML") komutları aracılığıyla istemciye göndermeyi sağlar.
- Java kodu
<%
// ana prosedürün yerel değişkenleri
String title="Récupération des paramètres d'un formulaire";
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
%>
servletin ana yöntemi olan _jspService'e aynen aktarılmıştır. <%… %> etiketleri içinde yer alan tüm kodlar için de durum aynıdır.
- JSP sayfasındaki HTML kodu, out.print("codeHTML") veya out.write(...) talimatlarının konusu. Örneğin
out.write("</title>\r\n </head>\r\n <body bgcolor=\"white\">\r\n <h3>");
- Bu örnekte, ana yöntem olan _jspService dışında başka yöntem yoktur.
3.2.6. JSP sayfasındaki yöntemler ve küresel değişkenler
Aşağıdaki JSP sayfasını ele alalım:
<%!
// önceki etiket, küresel değişkenler ve yöntemler bölümünü başlatır
// bu bölüm, servlet'te değiştirilmeden kullanılacaktır
// bir genel değişken
String prenom="inconnu";
// bir yöntem
private String sonChien(){
return "milou";
}//sonChien
// başka bir yöntem
private void afficheAmi(JspWriter out) throws Exception{
out.println("<p>Son ami s'appelle Haddock</p>");
}//afficheAmi
// servletin genel kısmının sonu
%>
<%
// önceki etiket, takip eden kodun kaydedileceğini belirtir
// servletin ana yöntemine kaydedileceğini belirtir
// ana yönteme özgü yerel değişken
String nom="tintin";
%>
<%-- kod HTML --%>
<html>
<head>
<title>Page JSP</title>
</head>
<body>
<center>
<h2>Page JSP</h2>
<p>Son nom est <%= nom %></p>
<p>Son prénom est <%= prenom %></p>
<p>Son chien s'appelle <%= sonChien() %></p>
<%
// arkadaşının adı
afficheAmi(out);
%>
</center>
</body>
</html>
Bu JSP sayfası, aşağıdaki web sayfasını oluşturur:

Yukarıdaki dört satırın nasıl oluşturulduğuna bir göz atalım:
<p>Son nom est <%= nom %></p>
<p>Son prénom est <%= prenom %></p>
<p>Son chien s'appelle <%= sonChien() %></p>
<%
// arkadaşının adı
afficheAmi(out);
%>
Yukarıdaki satırlar bir <%..%> etiketinin içinde yer almaktadır ve bu nedenle oluşturulacak servletin ana yöntemi olan _jspService'in bir parçası olacaktır. Bu satırlar, nom ve prenom değişkenlerine ve sonChien ile afficheAmi yöntemlerine nasıl erişiyor?
, JSP sayfasının ana yöntemine ait yerel bir değişkendir ve bu nedenle bu yöntem içinde bilinir | |
ise JSP sayfasının küresel bir değişkenidir ve bu nedenle ana yöntemde bilinir | |
, JSP sayfasının genel bir yöntemidir ve bu nedenle ana yöntemden erişilebilir | |
, JSP sayfasının genel bir yöntemidir ve bu nedenle ana yöntemden erişilebilir. out nesnesinin yönteme parametre olarak aktarıldığına dikkat edilmelidir. Bu, burada zorunludur. Zira out nesnesi, servletin ana yönteminde tanımlanmış ve başlatılmıştır; küresel bir değişken değildir. |
Şimdi, gereksiz kodlar çıkarıldıktan sonra, bu JSP sayfasından oluşturulan Java servlet koduna bir göz atalım:
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;
public class tintin$jsp extends HttpJspBase {
// önceki etiket, değişkenler ve genel yöntemler bölümünü başlatır
// bu bölüm, servlet'te değiştirilmeden kullanılacak
// bir küresel değişken
String prenom="inconnu";
// bir yöntem
private String sonChien(){
return "milou";
}//sonChien
// başka bir yöntem
private void afficheAmi(JspWriter out) throws Exception{
out.println("<p>Son ami s'appelle Haddock</p>");
}//afficheAmi
// servletin genel kısmının sonu
static {
}
public tintin$jsp( ) {
}
private static boolean _jspx_inited = false;
public final void _jspx_init() throws org.apache.jasper.runtime.JspException {
}
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
JspFactory _jspxFactory = null;
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
String _value = null;
try {
if (_jspx_inited == false) {
synchronized (this) {
if (_jspx_inited == false) {
_jspx_init();
_jspx_inited = true;
}
}
}
_jspxFactory = JspFactory.getDefaultFactory();
response.setContentType("text/html;charset=ISO-8859-1");
pageContext = _jspxFactory.getPageContext(this, request, response,
"", true, 8192, true);
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
out.write(" \r\n\r\n");
// önceki etiket, takip eden kodun kaydedileceğini belirtir
// servletin ana yöntemine kaydedileceğini belirtir
// ana yönteme özgü yerel değişken
String nom="tintin";
out.write("\r\n\r\n\r\n");
out.write("\r\n<html>\r\n <head>\r\n <title>Page JSP</title>\r\n </head>\r\n <body>\r\n <center>\r\n <h2>Page JSP</h2>\r\n <p>Son nom est ");
out.print( nom );
out.write("</p>\r\n <p>Son prénom est ");
out.print( prenom );
out.write("</p>\r\n <p>Son chien s'appelle ");
out.print( sonChien() );
out.write("</p>\r\n ");
// arkadaşının adı
afficheAmi(out);
out.write("\r\n </center>\r\n </body>\r\n</html>\r\n");
} catch (Throwable t) {
if (out != null && out.getBufferSize() != 0)
out.clearBuffer();
if (pageContext != null) pageContext.handlePageException(t);
} finally {
if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);
}
}
}
Yukarıda görüldüğü gibi, JSP <%! .. %> etiketleri arasında yer alan Java kodu tamamen alınmış ve servletin ana yöntemi olan _jspService'in bir parçası değildir. Bu bölümde bildirilen değişkenler, yöntemler için genel olan örnek değişkenleridir ve _jspService dışındaki yöntemlerin de burada tanımlanabileceği anlamına gelir.
// bu kısım, servlet içinde değiştirilmeden kullanılacaktır
// bir küresel değişken
String prenom="inconnu";
// bir yöntem
private String sonChien(){
return "milou";
}//sonChien
// başka bir yöntem
private void afficheAmi(JspWriter out) throws Exception{
out.println("<p>Son ami s'appelle Haddock</p>");
}//afficheAmi
// servletin genel kısmının sonu
3.2.7. Tomcat sunucusunda JSP sayfalarının dağıtımı ve hata ayıklaması
Bir JSP sayfası oluşturup bunu Tomcat sunucusunda kullanmak istediğimizde, sayfanın sunucu dizin yapısı içinde nereye yerleştirileceği sorusu ortaya çıkar. Bunu yapmanın çeşitli yolları vardır; bunlara daha sonra değineceğiz. Şimdilik, en basit yöntem, JSP sayfasını, <tomcat>\webapps\examples\jsp (Tomcat 4.x) dizin yapısı içindeki bir klasöre yerleştirmektir; burada <tomcat>, Tomcat'in kurulum dizinidir. Dolayısıyla, önceki örnekteki URL sayfası http://localhost:8080/examples/jsp/perso/tintin/tintin.jsp adresindeydi. Bu, tintin.jsp sayfasının <tomcat>\webapps\examples\jsp\perso\tintin klasöründe olduğu anlamına gelir.
JSP sayfası bir Java kaynak dosyasına dönüştürülür; daha sonra, JSP sayfasının URL dosyası bir tarayıcı tarafından istendiğinde bu dosya Tomcat tarafından derlenir. Derleme hataları ortaya çıkabilir. Tomcat, tarayıcıya verdiği yanıtta bu hataları bildirir. Özellikle .java dosyasındaki hatalı satırları belirtir. Hataların çeşitli nedenleri olabilir:
- sayfadaki JSP kodu hatalı (örneğin, kullanılan jsp etiketlerinde hatalar)
- JSP sayfasında yer alan Java kodu hatalı
İlk neden, sayfanın JSP kodunu kontrol ederek ortadan kaldırılabilir. İkinci neden ise Java kodunu kontrol ederek ortadan kaldırılabilir. Bunu, JSP sayfası için oluşturulan .java dosyasını, Tomcat'inkinden daha gelişmiş hata ayıklama özellikleri sunan JBuilder gibi bir araçla doğrudan derleyerek yapabilirsiniz.
3.2.8. Örnekler
Daha önce ele aldığımız, bir kullanıcının bir listeden bir sayı seçtiği ve sunucunun ona hangi sayıyı seçtiğini söylerken, aynı listeyi kullanıcı tarafından seçilen öğe seçili olarak geri gönderdiği servlet örneğini tekrar ele alıyoruz:

Bu sayfayı oluşturmak için servlet kodunu aldık ve şu şekilde değiştirdik:
- HTML kodunu üretmeyen Java kodunu olduğu gibi koruduk
- HTML kodunu üreten Java kodu, HTML ve JSP kodlarının bir karışımı haline getirildi
Böylece şu JSP sayfası elde edilir:
<%@ page import="java.sql.*, java.util.*" %>
<%!
// uygulamanın genel değişkenleri
// sayfanın başlığı
private final String title="Génération d'un formulaire";
// liste değerleri veritabanı
private final String DSNValeurs="odbc-valeurs";
private final String admDbValeurs="admDbValeurs";
private final String mdpDbValeurs="mdpDbValeurs";
// liste değerleri
private String[] valeurs=null;
// hata mesajı
private String msgErreur=null;
// sayfanın başlatılması JSP - yalnızca bir kez yürütülür
public void jspInit(){
// değer tablosunu bir veritabanından doldurur ODBC
// adı DSN: DSNvaleurs
Connection connexion=null;
Statement st=null;
ResultSet rs=null;
try{
// veritabanına bağlanma ODBC
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
connexion=DriverManager.getConnection("jdbc:odbc:"+DSNValeurs,admDbValeurs,mdpDbValeurs);
// Statement nesnesi
st=connexion.createStatement();
// değerleri almak için select sorgusunun yürütülmesi
rs=st.executeQuery("select valeur from Tvaleurs");
// değerler alınır ve dinamik bir tabloya yerleştirilir
ArrayList lstValeurs=new ArrayList();
while(rs.next()){
// değer listeye kaydedilir
lstValeurs.add(rs.getString("valeur"));
}//while
// listeyi tabloya dönüştürme
valeurs=new String[lstValeurs.size()];
for (int i=0;i<lstValeurs.size();i++){
valeurs[i]=(String)lstValeurs.get(i);
}
}catch(Exception ex){
// sorun
msgErreur=ex.getMessage();
}finally{
try{rs.close();}catch(Exception ex){}
try{st.close();}catch(Exception ex){}
try{connexion.close();}catch(Exception ex){}
}//try
}//başlatma
%>
<%
// code de _jspService exécuté à chaque requête cliente
// JSP sayfasının başlatılması sırasında bir hata mı oluştu?
if(msgErreur!=null){
%>
<!-- kod HTML -->
<html>
<head>
<title>Erreur</title>
</head>
<body>
<h3>Application indisponible (<%= msgErreur %></h3>
</body>
</html>
<%
// jspService'in sonu
return;
}//if
// kullanıcının olası seçimini alıyoruz
String choix=request.getParameter("cmbValeurs");
if(choix==null) choix="";
%>
<%-- hata yok - normal sayfanın kodu HTML --%>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h3>Choisissez une valeur</h3>
<form method="POST">
<select name="cmbValeurs">
<%
// değerlerin dinamik olarak görüntülenmesi
String selected="";
for (int i=0;i<valeurs.length;i++){
if(valeurs[i].equals(choix)) selected="selected"; else selected="";
out.println("<option "+selected+">"+valeurs[i]+"</option>");
}//for
%>
</select>
<input type="submit" value="Envoyer">
</form>
<%
// bir değer seçilmiş miydi?
if(! choix.equals("")){
// kullanıcının seçimi görüntülenir
%>
<hr>Vous avez choisi le nombre<h2><%= choix %></h2>
<%
}//if
%>
</body>
</html>
Aşağıdaki noktalara dikkat edelim:
- Servletin import komutları, <% page import="..." %> yönergesinin konusu olmuştur
- <%! ... %> etiketleri, uygulamanın küresel değişkenlerini ve Java yöntemlerini çevrelemektedir
- Servletin init yöntemi, servletin yüklenmesi sırasında tek seferlik olarak yürütülür; JSP sayfası için jspInit çağrılır. Bu iki yöntemin işlevi aynıdır. Bu nedenle, servletin init yöntemindeki kod burada aynen alınmıştır.
- Servletin, birden fazla yöntemde bilinmesi gereken örnek değişkenleri aynen alınmıştır. Bunlar temel olarak title, valeurs ve msgErreur değişkenleridir ve daha sonra JSP kodunda kullanılırlar.
- <% ... %> etiketleri, bir istemciden gelen istek sırasında yürütülecek olan _jspService yöntemine dahil edilecek Java kodunu çevreler.
- Servlet'te olduğu gibi, _jspService yöntemi, bir hata sayfası oluşturması gerekip gerekmediğini belirlemek için önce msgErreur değişkeninin değerini kontrol eder. Hata varsa, hata sayfasını oluşturur ve durur (return).
- Hata yoksa, değer listesini içeren formu oluşturur
- bunu yaptıktan sonra, kullanıcının bir sayı seçip seçmediğini kontrol eder; seçtiyse, oluşturulan sayfada bu sayıyı görüntüler
Servlet'e kıyasla ne kazanmış olduk? Şüphesiz, oluşturulan HTML koduna daha iyi bir bakış açısı. Ancak bu görünümü "kirleten" hâlâ çok fazla Java kodu var. Daha sonra, "delegasyon" adı verilen başka bir yöntemi göreceğiz; bu yöntemde Java kodunun büyük kısmını bir servlet'e yerleştirebileceğiz, JSP sayfası ise yalnızca HTML ve JSP kodlarını barındıracak. Böylece işleme kısmı ile sunum kısmı birbirinden net bir şekilde ayrılmış olur.
3.3. Tomcat sunucusunda bir web uygulamasının dağıtımı
Şimdi, Tomcat sunucusu ile Java web uygulamalarının nasıl dağıtılacağını anlatacağız. Aşağıda anlatılacaklar bu sunucuya özgü olsa da, başka bir J2EE konteyneri içinde bir Java web uygulamasının dağıtımı, şimdi açıklanacak olanlara benzer özellikler gösterecektir.
3.3.1. server.xml ve web.xml yapılandırma dosyaları
Şimdiye kadar, servletlerimizi ve sayfalarımızı JSP test etmek için
- servlet'leri <tomcat>\webapps\examples\WEB-INF\classes klasörüne yerleştirdik. Bu sayede servlet'lere URL http://localhost:8080/examples/servlet/nomServlet adresi üzerinden erişilebiliyordu.
- JSP dizin ağacındaki sayfalar. Bu sayfalara o zamanlar URL adresi üzerinden erişilebiliyordu: http://localhost:8080/examples/jsp/nomPageJSP
Bunun neden böyle olduğunu hiç açıklamamıştık. Tomcat sunucusunun yapılandırması, <tomcat>\conf klasöründe bulunan server.xml adlı bir metin dosyasında yapılır:

Bu metin dosyası aslında bir XML (eXtended İşaretleme Dili) dosyasıdır. Bir XML belgesi, tıpkı bir HTML belgesi gibi etiketler içeren bir metin belgesidir. Ancak, HTML dilindeki etiketler açıkça tanımlanmışken, XML dilindeki etiketler tanımlanmamıştır. Dolayısıyla aşağıdaki belge bir XML belgesidir:
XML belgesi, basitçe belirli etiketleme kurallarına uyan "etiketli" bir belgedir:
- <xx att1="val1" att2="val2" ....>metin</xx> biçiminde etiketlenmiş bir metin
- bir etiket tek başına olabilir ve <xx att1="val1" att2="val2" ..../> biçiminde olabilir
"atti" alanları xx etiketinin öznitelikleri olarak adlandırılır ve "vali" alanları ise bu özniteliklerle ilişkili değerlerdir. Bazı HTML belgeleri, geçerli XML belgeleri değildir. Örneğin, <br> etiketi geçerli bir XML etiketi değildir. Her XML etiketinin kapatılması gerektiği kuralına uymak için, geçerli bir etiket olması amacıyla <br/> şeklinde yazılması gerekir. HTML'in XHTML adlı bir varyantı, her XHTML belgesini geçerli bir XML belgesi haline getirmek amacıyla oluşturulmuştur. Bazı yeni tarayıcılar, XML dosyalarını görüntüleyebilmektedir. Dolayısıyla, yukarıdaki örnekte sunulan XML belgesine personne.xml adını verirsek ve bunu IE6 ile görüntülersek, aşağıdaki ekranı elde ederiz:

IE6, etiketleri tanır ve renklendirir. Ayrıca etiketler sayesinde belgenin yapısını da tanır. Dolayısıyla, aşağıdaki belgeye personne2.xml adını verirsek:
ve bunu IE6 ile görüntülersek, aynı görüntüyü elde ederiz:

IE6, belgenin yapısını ve içeriğini doğru bir şekilde tanımıştır. XML belgesinin en önemli özelliği işte budur: bir XML belgesinin yapısını ve içeriğini kolayca bulmak mümkündür. Bu işlem, XML adlı bir ayrıştırıcı programı ile gerçekleştirilir. XML belgeleri, web üzerinde belge alışverişinde standart haline gelme eğilimindedir. A makinesinin B makinesine bir DOC belgesi göndermesi gerektiğini varsayalım. DOC belgesi, bir DB-A veritabanında bulunan bilgilerden oluşturulur. B makinesi ise DOC belgesini bir DB-B veritabanında depolamalıdır. Alışveriş şu şekilde gerçekleşebilir:
- A makinesi, DB-A veritabanından verileri alır ve bunları XML metin belgesine yerleştirir
- XML belgesi ağ üzerinden B makinesine gönderilir
- B makinesi, alınan belgeyi bir XML ayrıştırıcısıyla analiz eder ve hem yapısını hem de verileri alır (örneğimizde IE6'in yaptığı gibi). Ardından, alınan verileri DB-B veritabanına kaydedebilir
XML dili hakkında daha fazla ayrıntıya girmeyeceğiz; bu dil tek başına bir kitap yazılmasını hak ediyor.
Burada Tomcat, XML server.xml dosyası ile yapılandırılmıştır. Bu dosyayı IE6 ile görüntülediğimizde, karmaşık bir belge ile karşılaşırız. Biz sadece şu satırlara odaklanacağız:

Burada ilgimizi çeken <Context ...> etiketidir. Bu etiket, web uygulamalarını tanımlamak için kullanılır. Bu etiketin iki özelliği dikkat çekicidir:
- path: web uygulamasının adı
- docBase: Uygulamanın bulunduğu klasörün adıdır. Burada göreceli bir ad kullanılmış: examples. Hangi klasöre göre göreceli? Cevap, yine server.xml dosyasında, bir sonraki satırda yer almaktadır:

Yukarıdaki satır web sunucusunu tanımlar:
- name: web sunucusunun adı
- appBase: dağıttığı belgelerin dizin yapısının kökü. Yine, burada göreceli bir adla karşılaşıyoruz: webapps. Bu ad, Tomcat sunucusunun kurulum dizini olan <tomcat>'e göredir. Dolayısıyla, söz konusu klasör <tomcat>\webapps'tir.
examples web uygulamasının belgeleri examples klasöründe bulunur (yukarıdaki docBase'e bakınız). Bu ad, sunucunun web dizin yapısının kök dizinine göredir: c.a.d. <tomcat>\webapps. Dolayısıyla bu, <tomcat>\webapps\examples klasörüdür. Bu klasörü daha yakından inceleyelim:

Burada, test etmek üzere servletlerimizi yerleştirdiğimiz WEB-INF\classes klasörünü görüyoruz. WEB-INF klasörü, web.xml adlı bir dosya içeriyor:

Bu dosya, examples web uygulamasını yapılandırmak için kullanılır. Şu an için bu dosyanın çok karmaşık detaylarına girmeyeceğiz. Sadece aşağıdaki birkaç satıra odaklanacağız:
<servlet>
<servlet-name>
servletToJsp
</servlet-name>
<servlet-class>
servletToJsp
</servlet-class>
</servlet>
<servlet> etiketi, bir web uygulaması içinde bir servlet tanımlamak için kullanılır. Burada söz konusu web uygulamasının examples olduğunu hatırlatalım. servlet etiketi burada iki başka etiket içerir:
- <servlet-name>servletToJsp</servlet-name>: servletin adını tanımlar
- <servlet-name>servletToJsp</servlet-name>: servlet istendiğinde çalıştırılacak sınıfın adını tanımlar. Bu örnekte, servlet ve sınıfı aynı adı taşır. Bu zorunlu değildir.
servletToJsp servleti, bir tarayıcı tarafından Tomcat sunucusuna nasıl istenir?
- Tarayıcı, URL'i şu şekilde ister: http://localhost:8080/examples/servlet/servletToJsp
- Tomcat, /examples/servlet/servletToJsp servlet yolunu analiz eder. Yolun ilk kısmını (/examples) bir web uygulamasının adı olarak yorumlar ve bu uygulamanın belgelerinin nerede depolandığını belirlemek için server.xml yapılandırma dosyasında arama yapar. Daha önce gördüğümüz gibi, bu klasör <tomcat>\webapps\examples'tir.
- Tomcat, servleti examples web uygulamasında bulmak için yolun geri kalan kısmını kullanır. /servlet/servletToJsp yolu, servletToJsp adlı servleti çalıştırması gerektiğini belirtir. Tomcat daha sonra, <tomcat>\webapps\examples\WEB-INF dizininde bulacağı examples uygulamasının web.xml yapılandırma dosyasını okuyacaktır. Bu dosyada, servletToJsp servlet'inin servletToJsp Java sınıfıyla ilişkili olduğunu görecektir (yukarıdaki web.xml dosyasına bakınız). Ardından, bu sınıfı examples, c.a.d web uygulamalarının <tomcat>\webapps\examples\WEB-INF\classes klasöründe arayacak <tomcat>\webapps\examples\WEB-INF\classes dizininde bulunan bu sınıfı bulur ve çalıştırır.

3.3.2. Örnek: liste web uygulamasının dağıtımı
Daha önce incelediğimiz ve kullanıcıya bir sayı listesi sunan, kullanıcının bu listeden bir sayı seçtiği bir servleti tekrar ele alıyoruz. Servlet daha sonra kullanıcıya seçtiği sayıyı teyit ediyordu:

Yukarıdaki tarayıcının Address alanında da görüldüğü gibi, servletin sınıf dosyası gener3 adını taşıyordu. Daha önce verilen açıklamalara göre:
- URL ve /examples/servlet/gener3, bunun gener3 adlı bir servlet olduğunu gösterir; bu servlet, examples adlı web uygulamasının
- examples uygulamasının web.xml dosyasında, gener3 adlı bir servletten bahseden hiçbir şey bulunmaz. Peki Tomcat onu nasıl buldu? web.xml dosyasının tamamını inceledikten sonra bile kesin bir cevap veremiyorum... Soru hala cevaplanmamış durumda...
gener3.class servletini, E:\data\serge\Servlets\lstValeurs klasöründe bulunan liste adlı bir web uygulamasında lstValeurs adıyla dağıtmayı seçiyoruz:

gener3.class dosyasını yukarıdaki WEB-INF\classes klasörüne yerleştiriyoruz:

server.xml dosyasına, manager web uygulamasını tanımlayan satırların üstüne aşağıdaki satırları ekleyerek liste web uygulamasını yapılandırıyoruz:
<!-- Kişisel: lstValeurs -->
<Context path="/liste" docBase="e:/data/serge/servlets/lstValeurs" />
<!-- Tomcat Yönetici Bağlamı -->
<Context path="/manager" docBase="manager" debug="0" privileged="true" />
<!-- Tomcat Örnekleri Bağlamı -->
<Context path="/examples" docBase="examples" debug="0" reloadable="true" crossContext="true">
........
Uygulama listesini tanımlayan satır, uygulamanın e:/data/serge/servlets/lstValeurs klasöründe bulunduğunu belirtir. Şimdi bu uygulamanın web.xml dosyasını tanımlamamız gerekiyor. Bu dosya, uygulamanın tek servletini tanımlayacaktır:
<?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>lstValeurs</servlet-name>
<servlet-class>gener3</servlet-class>
</servlet>
</web-app>
Yukarıdaki dosya, lstValeurs adlı servletin gener3.class sınıf dosyasıyla ilişkili olduğunu gösterir. Bu web.xml dosyası oluşturulmalı ve liste uygulamasının WEB-INF klasörüne kaydedilmelidir:

Yukarıdaki ekran görüntüsü, içine gener3.java kaynak dosyasının yerleştirildiği bir src klasörünü göstermektedir. Bu klasör mevcut olmayabilir. Mevcut örnekte herhangi bir işlevi yoktur. Testlere hazırız:
- Tomcat'i durdurun ve yeniden başlatın, böylece server.xml yapılandırma dosyasını yeniden okusun. Burada Windows kullanıyoruz. Unix'te ise Tomcat'i durdurmadan yapılandırma dosyasını yeniden okumaya zorlayabilirsiniz.
- Bir tarayıcıyla URL dosyasını isteyin: http://localhost:8080/liste/servlet/lstValeurs

Görüldüğü gibi, önceki URL dosyası, şimdiye kadar kullanılan tüm URL servlet dosyaları gibi servlet anahtar kelimesini içeriyor. Uygulamanın liste dosyasındaki web.xml dosyasında, lstValeurs servletini bir URL (url-pattern) şablonuyla ilişkilendirerek bundan vazgeçilebilir:
<?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>lstValeurs</servlet-name>
<servlet-class>gener3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>lstValeurs</servlet-name>
<url-pattern>/valeurs</url-pattern>
</servlet-mapping>
</web-app>
<servlet-mapping> etiketinde, /valeurs yolunu önceki satırlarda tanımlanan lstValeurs servlet'iyle ilişkilendiriyoruz. Yeni web.xml dosyasını kaydediyoruz ve URL ile http://localhost:8080/liste/valeurs'i çağırıyoruz:

3.3.3. Bir web uygulamasının genel sayfalarının dağıtımı
Az önce tek bir servletten oluşan bir web uygulamasının dağıtımını inceledik. Bir web uygulaması birçok bileşene sahip olabilir: servletler, JSP sayfaları, HTML dosyaları, Java applet’leri vb. Bu uygulama bileşenleri nereye yerleştirilir? Tomcat yapılandırma dosyası server.xml’teki uygulamanın docBase özniteliği ile tanımlanan web uygulamasının klasörü <application> ise, servletlerin <application>\WEB-INF\classes dizinine yerleştirildiğini görmüştük. Uygulamanın diğer bileşenleri, WEB-INF klasörü hariç, <application> klasörünün dizin yapısı içinde herhangi bir yere yerleştirilebilir. Daha önce incelediğimiz JSP ve listvaleurs.jsp uygulamalarını ele alalım:

Bu JSP sayfası, <tomcat>\webapps\examples\jsp\perso\listvaleurs klasörüne kaydedilmişti. Bu sayfa, daha önce dağıtılan liste uygulamasının bir bileşeni olabilir. listvaleurs.jsp dosyasını doğrudan bu uygulamanın klasörüne yerleştirelim:

liste uygulamasının server.xml dosyasındaki yapılandırmasını hatırlayalım:
/liste yoluyla başlayan tüm URL dosyaları, liste uygulamasının bir parçası olarak kabul edilir ve belirtilen klasörde aranır. Bir tarayıcıyla http://localhost:8080/liste/listvaleurs.jsp adresindeki URL dosyasını açalım:

Beklediğimiz JSP sayfasını aldık.
3.3.4. Bir servletin başlatma ayarları
Bir servletin, <application>\WEB-INF\web.xml dosyası ile yapılandırıldığını görmüştük; burada <application>, servletin ait olduğu web uygulamasının klasörüdür. Bu dosyaya servletin başlatma parametrelerini eklemek mümkündür. liste web uygulamasındaki lstValeurs servletimize geri dönelim; bu servletin yapılandırma dosyası şöyleydi:
<?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>lstValeurs</servlet-name>
<servlet-class>gener3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>lstValeurs</servlet-name>
<url-pattern>/valeurs</url-pattern>
</servlet-mapping>
</web-app>
Servlet ile ilişkili sınıf, gener3 sınıfıdır. Bu sınıfın kaynak kodunda birkaç sabitin tanımı bulunmaktadır:
public class gener3 extends HttpServlet{
// sayfanın başlığı
private final String title="Génération d'un formulaire";
// liste değerleri veritabanı
private final String DSNValeurs="odbc-valeurs";
private final String admDbValeurs="admDbValeurs";
private final String mdpDbValeurs="mdpDbValeurs";
Yukarıda tanımlanan dört sabitin anlamlarını hatırlayalım:
servlet tarafından oluşturulan HTML belgesinin başlığı | |
servletin veri alacağı ODBC veritabanının adı DSN | |
önceki veritabanında okuma hakkına sahip bir kullanıcının adı | |
kullanıcının şifresi |
DSNValeurs veritabanının yöneticisi, admDbValeurs kullanıcısının şifresini değiştirirse, servletin kaynak kodu değiştirilmeli ve yeniden derlenmelidir. Bu pek pratik değildir. Servlet yapılandırma dosyası web.xml, <init-param> etiketiyle servletin başlatma parametrelerinin tanımlanmasına izin vererek bize bir alternatif sunar:
parametrenin adını tanımlamaya olanak tanır | |
önceki parametreye atanan değeri tanımlar |
Servlet, aşağıdaki yöntemler aracılığıyla başlatma parametrelerine erişebilir:
Web programlamada kullanılan HttpServlet sınıfının türetildiği Servlet sınıfının yöntemi. Servletin yapılandırma parametrelerine erişim sağlayan bir ServletConfig nesnesi döndürür. | |
ServletConfig sınıfının, "paramètre" başlatma parametresinin değerini veren yöntemi |
liste uygulamasını aşağıdaki yeni web.xml dosyasıyla yapılandırıyoruz:
<?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>lstValeurs</servlet-name>
<servlet-class>gener3</servlet-class>
</servlet>
<servlet>
<servlet-name>lstValeurs2</servlet-name>
<servlet-class>gener5</servlet-class>
<init-param>
<param-name>title</param-name>
<param-value>Génération d'un formulaire</param-value>
</init-param>
<init-param>
<param-name>DSNValeurs</param-name>
<param-value>odbc-valeurs</param-value>
</init-param>
<init-param>
<param-name>admDbValeurs</param-name>
<param-value>admDbValeurs</param-value>
</init-param>
<init-param>
<param-name>mdpDbValeurs</param-name>
<param-value>mdpDbValeurs</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>lstValeurs</servlet-name>
<url-pattern>/valeurs</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>lstValeurs2</servlet-name>
<url-pattern>/valeurs2</url-pattern>
</servlet-mapping>
</web-app>
liste uygulamasında, gener5 sınıf dosyasına bağlı, lstValeurs2 adlı ikinci bir servlet tanımlıyoruz. Bu dosya, <application>\WEB-INF\classes dizinine yerleştirilmiştir:

lstValeurs2 servlet'inin dört başlatma parametresi vardır: title, DSNValeurs, admDbValeurs, mdpDbValeurs. Ayrıca, <servlet-mapping> etiketiyle bu servlet için /valeurs2 takma adı tanımlanmıştır. Böylece, liste uygulamasındaki lstValeurs2 servlet'ine URL ve http://localhost:8080/liste/valeurs2 üzerinden erişilebilecektir.
Servletin kaynak kodu, servletin başlatma parametrelerini almak üzere aşağıdaki şekilde değiştirilmiştir:
public class gener5 extends HttpServlet{
// sayfa başlığı
private String title=null;
// liste değerleri veritabanı
private String DSNValeurs=null;
private String admDbValeurs=null;
private String mdpDbValeurs=null;
...............
// servletin başlatılması
public void init(){
// servlet'in başlatma parametreleri alınır
ServletConfig config=getServletConfig();
title=config.getInitParameter("title");
DSNValeurs=config.getInitParameter("DSNValeurs");
admDbValeurs=config.getInitParameter("admDbValeurs");
mdpDbValeurs=config.getInitParameter("mdpDbValeurs");
//Tüm parametreler alındı mı?
if(title==null || DSNValeurs==null || admDbValeurs==null
|| mdpDbValeurs==null){
msgErreur="Configuration incorrecte";
return;
}
// değer tablosu bir veritabanından dolduruluyor ODBC
// adı DSN olan: DSNvaleurs
...............
Servleti test etmek için, Tomcat'ı yeniden başlatarak liste uygulamasının yeni yapılandırma dosyası web.xml'i dikkate almasını sağlamanız gerekir. Bir tarayıcı kullanarak, http://localhost:8080/liste/valeurs2 servlet'inin URL dosyasını çağırırız:

Servlet için gerekli başlatma parametrelerinden biri web.xml dosyasında yoksa, aşağıdaki sayfa görüntülenir:

3.3.5. Bir web uygulamasının başlatma parametreleri
Önceki örnekte, yalnızca lstValeurs2 servleti title, DSNValeurs, admDbValeurs ve mdpDbValeurs parametrelerine erişebilir. Aynı uygulamaya ait başka bir servlet olan liste’in, lstValeurs2 servletinin kullandığı veritabanındaki verilere ihtiyaç duyabileceği düşünülebilir. Bu durumda, yeni servletin web.xml dosyasının yapılandırma bölümünde DSNValeurs, admDbValeurs ve mdpDbValeurs parametrelerini yeniden tanımlamak gerekir. Başka bir çözüm ise, birden fazla servlet için ortak olan parametreleri artık servlet düzeyinde değil, uygulama düzeyinde tanımlamaktır. Uygulamanın yeni web.xml dosyası şu şekilde olur:
<?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>
<context-param>
<param-name>DSNValeurs</param-name>
<param-value>odbc-valeurs</param-value>
</context-param>
<context-param>
<param-name>admDbValeurs</param-name>
<param-value>admDbValeurs</param-value>
</context-param>
<context-param>
<param-name>mdpDbValeurs</param-name>
<param-value>mdpDbValeurs</param-value>
</context-param>
<servlet>
<servlet-name>lstValeurs</servlet-name>
<servlet-class>gener3</servlet-class>
</servlet>
<servlet>
<servlet-name>lstValeurs3</servlet-name>
<servlet-class>gener6</servlet-class>
<init-param>
<param-name>title</param-name>
<param-value>Génération d'un formulaire</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>lstValeurs</servlet-name>
<url-pattern>/valeurs</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>lstValeurs3</servlet-name>
<url-pattern>/valeurs3</url-pattern>
</servlet-mapping>
</web-app>
Yeni servlet’in adı lstValeurs3’tir; gener6 sınıf dosyasına bağlıdır ve /valeurs3 takma adıyla ilişkilendirilmiştir (servlet eşlemesi). title parametresi, servlet tanımında korunan tek parametredir. Diğer parametreler, uygulama yapılandırmasında <context-param> etiketleri içine yerleştirilmiştir. Bu etiket, belirli bir servlet veya JSP sayfasına değil, uygulamaya özgü bilgileri tanımlamak için kullanılır. Java servleti, genellikle bağlam parametreleri olarak adlandırılan bu parametrelere nasıl erişir? Bağlam bilgilerini elde etmek için kullanılabilen yöntemler, bir servlete özgü başlatma parametrelerini elde etmek için kullanılan yöntemlere çok benzerdir:
Web programlamada kullanılan HttpServlet sınıfının türetildiği Servlet sınıfının yöntemi. Uygulamanın yapılandırma parametrelerine erişim sağlayan bir ServletContext nesnesi döndürür | |
ServletContext sınıfının, "parameter" başlatma parametresinin değerini veren yöntemi |
gener6.java sınıfı, daha önce kullanılan gener5.java sınıfının Java kodunda yalnızca aşağıdaki değişiklikleri yapar:
// servletin başlatma parametreleri alınır
ServletConfig config=getServletConfig();
title=config.getInitParameter("title");
ServletContext context=getServletContext();
DSNValeurs=context.getInitParameter("DSNValeurs");
admDbValeurs=context.getInitParameter("admDbValeurs");
mdpDbValeurs=context.getInitParameter("mdpDbValeurs");
//Tüm parametreler alındı mı?
if(title==null || DSNValeurs==null || admDbValeurs==null
|| mdpDbValeurs==null){
msgErreur="Configuration incorrecte";
return;
}
// değerler tablosu bir veritabanından doldurulur ODBC
// adı DSN olan: DSNvaleurs
...............
Servlet'e özgü title parametresi, bir ServletConfig nesnesi aracılığıyla elde edilir. Uygulama düzeyinde tanımlanan diğer üç parametre ise bir ServletContext nesnesi aracılığıyla elde edilir. Bu sınıfı derleyip diğerleri gibi <application>\WEB-INF\classes dizinine yerleştiriyoruz:

Tomcat'i yeniden başlatarak uygulamanın yeni web.xml dosyasını dikkate almasını sağlıyoruz ve URL ile http://localhost:8080/liste/valeurs3'i çağırıyoruz:

3.3.6. Bir sayfanın başlatma parametreleri JSP
Bir servlet veya web uygulaması için başlatma parametrelerini nasıl tanımlayacağımızı gördük. Aynı şeyi bir sayfa için de yapabilir miyiz? Daha önce incelediğimiz sayfanın kodunun başına geri dönelim:
<%@ page import="java.sql.*, java.util.*" %>
<%!
// uygulamanın genel değişkenleri
// sayfa başlığı
private final String title="Génération d'un formulaire";
// liste değerleri veritabanı
private final String DSNValeurs="odbc-valeurs";
private final String admDbValeurs="admDbValeurs";
private final String mdpDbValeurs="mdpDbValeurs";
.........
Uygulamanın web.xml dosyasında tanımlanmış olan title, DSNValeurs, admDbValeurs ve mdpDbValeurs sabitleri burada yer almaktadır. DSNValeurs, admDbValeurs ve mdpDbValeurs sabitleri artık uygulama düzeyinde tanımlandığından, bu uygulamaya ait bir sayfa olan JSP'in bu sabitlere erişebileceği varsayılabilir. Durum böyledir. JSP sayfasının bir servlet’e dönüştürüleceğini biliyoruz. Bu servlet, getServletContext() yöntemi aracılığıyla bağlama erişebilecektir. Daha karmaşık olan durum ise title sabitidir. Çünkü bunu uygulama düzeyinde değil, servlet düzeyinde şu şekilde tanımladık:
<servlet>
<servlet-name>lstValeurs3</servlet-name>
<servlet-class>gener6</servlet-class>
<init-param>
<param-name>title</param-name>
<param-value>Génération d'un formulaire</param-value>
</init-param>
</servlet>
JSP sayfası için, artık sınıf dosyası kavramı bulunmadığından önceki sözdizimi geçerli değildir. Bununla birlikte, bir JSP sayfasının yapılandırma sözdizimi, bir servletinkine çok yakındır. Şu şekildedir:
<servlet>
<servlet-name>JSPlstValeurs</servlet-name>
<jsp-file>/listvaleurs2.jsp</jsp-file>
...
</servlet>
Aslında, JSP sayfası, kendisine bir ad (servlet-name) verilen bir servlet ile eşdeğerdir. Bu servlete bir sınıf dosyası atamak yerine, çalıştırılacak JSP sayfasının kaynak dosyası (jsp-file) atanır. Böylece, yukarıdaki birkaç satır, JSPlstvaleurs adlı ve JSP /listvaleurs2.jsp sayfasıyla ilişkilendirilmiş bir servlet tanımlar. /listvaleurs2.jsp yolu, uygulamanın kök dizinine göre belirlenir. Dolayısıyla, liste uygulamamızda, listvaleurs2.jsp dosyası, liste uygulamasının docBase klasöründe (bkz. server.xml) bulunur:

JSP sayfasının yapılandırması, uygulamanın web.xml dosyasında şu şekilde olacaktır:
<?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>
<context-param>
<param-name>DSNValeurs</param-name>
<param-value>odbc-valeurs</param-value>
</context-param>
<context-param>
<param-name>admDbValeurs</param-name>
<param-value>admDbValeurs</param-value>
</context-param>
<context-param>
<param-name>mdpDbValeurs</param-name>
<param-value>mdpDbValeurs</param-value>
</context-param>
.......
<servlet>
<servlet-name>JSPlstValeurs</servlet-name>
<jsp-file>/listvaleurs2.jsp</jsp-file>
<init-param>
<param-name>JSPtitle</param-name>
<param-value>Génération d'un formulaire</param-value>
</init-param>
</servlet>
..........
<servlet-mapping>
<servlet-name>JSPlstValeurs</servlet-name>
<url-pattern>/jspvaleurs</url-pattern>
</servlet-mapping>
<servlet-mapping>
........
</web-app>
JSP listvaleurs2.jsp sayfası, liste uygulamasının kök dizinine yerleştirilmiştir ve JSPlstValeurs (servlet-name) ile ilişkilendirilmiştir; bu servlet adı da /jspvaleurs (servlet-mapping) takma adıyla ilişkilendirilmiştir. Böylece JSP sayfamız, URL ve http://localhost:8080/liste/jspvaleurs adresleri üzerinden erişilebilir olacaktır.
Başlangıçtaki JSP sayfası, listvaleurs.jsp olarak değiştirilir ve jspInit() yönteminden dört başlatma parametresini alır:
<%!
// uygulamanın genel değişkenleri
// sayfa başlığı
private String title=null;
// liste değerleri veritabanı
private String DSNValeurs=null;
private String admDbValeurs=null;
private String mdpDbValeurs=null;
// liste değerleri
private String[] valeurs=null;
// hata mesajı
private String msgErreur=null;
// sayfanın başlatılması JSP - yalnızca bir kez yürütülür
public void jspInit(){
// servlet'in başlatma parametreleri alınır
ServletConfig config=getServletConfig();
title=config.getInitParameter("JSPtitle");
ServletContext context=getServletContext();
DSNValeurs=context.getInitParameter("DSNValeurs");
admDbValeurs=context.getInitParameter("admDbValeurs");
mdpDbValeurs=context.getInitParameter("mdpDbValeurs");
//Tüm parametreler alındı mı?
if(title==null || DSNValeurs==null || admDbValeurs==null
|| mdpDbValeurs==null){
msgErreur="Configuration incorrecte";
return;
}
// değer tablosu, ODBC veritabanından doldurulur
// adı DSN olan: DSNvaleurs
..............
JSP sayfası, başlangıç parametrelerini servletlerle aynı şekilde alır. Önceki dosya, liste web uygulamasının kök dizinine kaydedilir:

Tomcat sunucusu, uygulamanın yeni web.xml yapılandırma dosyasını yeniden okuması için yeniden başlatılır. Ardından URL http://localhost:8080/liste/jspvaleurs sayfası çağrılabilir:

3.3.7. Bir web uygulaması içinde servletler ve sayfalar arasındaki işbirliği (JSP)
Bir istemci bir web sunucusuna istek gönderdiğinde, yanıt birden fazla servlet ve sayfa tarafından oluşturulabilir JSP. Şimdiye kadar, yanıt tek bir servlet veya sayfa tarafından oluşturuluyordu JSP. JSP sayfasının, oluşturulan HTML belgesinin yapısını daha okunaklı hale getirdiğini gördük. Ancak bu sayfa genellikle çok fazla Java kodu içerir. Şu şekilde iyileştirme yapılabilir:
- bir veya birkaç servlete, yanıtın HTML kodunu oluşturmayan Java kodunu
- JSP sayfalarında yer alan, müşteriye yanıt olarak gönderilen çeşitli HTML belgelerini oluşturan kodu
Böylece Java kodu ile HTML kodunun ayrımını iyileştirmeyi umabiliriz. Bu yeni yapılandırmayı liste uygulamamıza uygulayacağız: bir Java servlet'i (lstValeurs4), başlangıçta veritabanındaki değerleri okumakla ve ardından müşterilerin isteklerini analiz etmekle görevlendirilecektir. Bu analiz sonucuna göre, müşterinin talebi bir hata sayfası olan erreur.jsp'e ya da sayı listesini gösteren liste.jsp sayfasına yönlendirilecektir. Dolayısıyla, liste uygulaması bir servlet ve iki JSP sayfasından oluşacaktır.
Bir servlet, bir istemciden aldığı isteği başka bir servlete veya JSP sayfasına nasıl iletebilir? Aşağıdaki yöntemleri kullanacağız:
ServletContext sınıfının, bir RequestDispatcher nesnesi döndüren yöntemi. url parametresi, istemcinin isteğinin iletilmek istendiği URL'in adıdır. Bu istek aktarımı yalnızca aynı uygulama içinde gerçekleştirilebilir. Ayrıca, url parametresi, bu uygulamanın web dizin yapısına göre göreceli bir yoldur. | |
RequestDispatcher arayüzünün yöntemi; bu yöntem, önceki URL yöntemine müşterinin request isteğini ve yanıtın oluşturulması için kullanılması gereken response nesnesini iletir. | |
Bir JSP servlet veya sayfası, bir isteği başka bir JSP servlet veya sayfasına ilettiğinde, genellikle müşterinin isteğinden başka, kendi isteği üzerindeki işlemlerinden elde ettiği bilgileri de bu servlet veya sayfaya iletmesi gerekir. ServletRequest sınıfındaki setAttribute yöntemi, istemcinin request nesnesine, (öznitelik, değer) şeklinde öznitelik eklemeye olanak tanır; burada attribut özniteliğin adı, valeur ise bu özniteliğin değerini temsil eden herhangi bir nesnedir. | |
bir isteğin öznitelik değerlerini almayı sağlar. Bu yöntem, bir isteğin iletildiği JSP servleti veya sayfası tarafından, isteğe eklenen bilgileri almak için kullanılacaktır. |
Formu işlemekle görevli servlet, web.xml dosyasında şu şekilde yapılandırılacaktır:
<?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>
<context-param>
<param-name>DSNValeurs</param-name>
<param-value>odbc-valeurs</param-value>
</context-param>
<context-param>
<param-name>admDbValeurs</param-name>
<param-value>admDbValeurs</param-value>
</context-param>
<context-param>
<param-name>mdpDbValeurs</param-name>
<param-value>mdpDbValeurs</param-value>
</context-param>
............
<servlet>
<servlet-name>lstValeurs4</servlet-name>
<servlet-class>gener7</servlet-class>
<init-param>
<param-name>title</param-name>
<param-value>Génération d'un formulaire</param-value>
</init-param>
<init-param>
<param-name>JSPerreur</param-name>
<param-value>/erreur.jsp</param-value>
</init-param>
<init-param>
<param-name>JSPliste</param-name>
<param-value>/liste.jsp</param-value>
</init-param>
<init-param>
<param-name>URLservlet</param-name>
<param-value>/liste/valeurs4</param-value>
</init-param>
</servlet>
...........
<servlet-mapping>
<servlet-name>lstValeurs4</servlet-name>
<url-pattern>/valeurs4</url-pattern>
</servlet-mapping>
.......
</web-app>
lstValeurs4 servlet'inin kendisine özgü dört başlatma parametresi olacaktır:
oluşturulacak HTML belgesinin başlığı | |
hata sayfası JSP'in URL'i | |
sayı listesini içeren JSP sayfasının URL kodu | |
JSPliste sayfasında sunulan formun action özniteliğiyle ilişkili olan URL. Bu URL, lstValeurs4 servletine ait olacaktır |
Servlet, /valeurs4 takma adına sahip olacak (servlet-mapping) ve dolayısıyla URL http://localhost:8080/liste/valeurs4 üzerinden erişilebilir olacaktır. Bu servlet, tam kaynak kodu aşağıdaki gibi olan gener7.java sınıf dosyasına bağlıdır:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
import java.util.*;
public class gener7 extends HttpServlet{
// sayfanın başlığı
private String title=null;
// liste değerleri veritabanı
private String DSNValeurs=null;
private String admDbValeurs=null;
private String mdpDbValeurs=null;
// görüntüleme sayfaları JSP
private String JSPerreur=null;
private String JSPliste=null;
// servlet'in URL'i
private String URLservlet=null;
// liste değerleri
private String[] valeurs=null;
// hata mesajı
private String msgErreur=null;
// -----------------------------------------------------------------
// GET
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// msgErreur,title ismi istek özniteliklerine eklenir
request.setAttribute("msgErreur",msgErreur);
request.setAttribute("title",title);
request.setAttribute("URLservlet",URLservlet);
// servlet yüklenirken bir hata mı oluştu?
if(msgErreur!=null){
// bir hata sayfasına yönlendiriliyor: JSP
getServletContext().getRequestDispatcher(JSPerreur).forward(request,response);
// son
return;
}
// Hata oluşmadı
// değerlerin listesi istek özniteliklerine ekleniyor
request.setAttribute("valeurs",valeurs);
// kullanıcının yaptığı seçimi (varsa) alınıyor
String choix=request.getParameter("cmbValeurs");
if(choix==null) choix="";
request.setAttribute("choix",choix);
// listeyi gösteren JSP sayfasına kontrol devrediliyor
getServletContext().getRequestDispatcher(JSPliste).forward(request,response);
// son
return;
}//GET
// -----------------------------------------------------------------
// POST
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// GET sayfasına yönlendirilir
doGet(request,response);
}//POST
// -----------------------------------------------------------------
// servletin başlatılması
public void init(){
// servlet'in başlatma parametreleri alınır
ServletConfig config=getServletConfig();
title=config.getInitParameter("title");
JSPerreur=config.getInitParameter("JSPerreur");
JSPliste=config.getInitParameter("JSPliste");
URLservlet=config.getInitParameter("URLservlet");
ServletContext context=getServletContext();
DSNValeurs=context.getInitParameter("DSNValeurs");
admDbValeurs=context.getInitParameter("admDbValeurs");
mdpDbValeurs=context.getInitParameter("mdpDbValeurs");
//Tüm parametreler alındı mı?
if(title==null || DSNValeurs==null || admDbValeurs==null
|| mdpDbValeurs==null || JSPerreur==null || JSPliste==null || URLservlet==null){
msgErreur="Configuration incorrecte";
return;
}
// değer tablosunu bir veritabanından dolduruyor ODBC
// adı DSN olan: DSNvaleurs
Connection connexion=null;
Statement st=null;
ResultSet rs=null;
try{
// ODBC veritabanına bağlanma
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
connexion=DriverManager.getConnection("jdbc:odbc:"+DSNValeurs,admDbValeurs,mdpDbValeurs);
// Statement nesnesi
st=connexion.createStatement();
// değerleri almak için select sorgusunun yürütülmesi
rs=st.executeQuery("select valeur from Tvaleurs");
// değerler alınır ve dinamik bir tabloya yerleştirilir
ArrayList lstValeurs=new ArrayList();
while(rs.next()){
// değer listeye kaydedilir
lstValeurs.add(rs.getString("valeur"));
}//while
// liste --> tablo dönüştürme
valeurs=new String[lstValeurs.size()];
for (int i=0;i<lstValeurs.size();i++){
valeurs[i]=(String)lstValeurs.get(i);
}
}catch(Exception ex){
// sorun
msgErreur=ex.getMessage();
}finally{
try{rs.close();}catch(Exception ex){}
try{st.close();}catch(Exception ex){}
try{connexion.close();}catch(Exception ex){}
}//try
}//başlatma
}//sınıf
Bu sınıftaki yenilik, hata durumunda istemcinin isteğinin JSPerreur sayfasına, aksi takdirde JSPliste sayfasına iletilmesidir. Sınıf, yanıtı kendisi oluşturmaz. Bunu JSP, JSPerreur ve JSPliste sayfaları üstlenir. Daha önce servlet, istemcinin isteğine (setAttribute) öznitelikler eklemişti:
- JSPerreur sayfasında bir hata oluştuğunda msgErreur hata mesajı
- görüntülenecek değerler (valeurs)), kullanıcı tarafından seçilen değer (choix), formun başlığı (title), URL (URLservlet) ve JSPliste sayfası için formun action özniteliği
Bu sınıf derlenir ve uygulamanın sınıfları arasına eklenir:

Bir hata mesajı görüntüleyen JSP sayfası şu şekilde yapılandırılmıştır:
<servlet>
<servlet-name>JSPerreur</servlet-name>
<jsp-file>/erreur.jsp</jsp-file>
<init-param>
<param-name>mainServlet</param-name>
<param-value>/valeurs4</param-value>
</init-param>
</servlet>
.........
<servlet-mapping>
<servlet-name>JSPerreur</servlet-name>
<url-pattern>/JSPerreur</url-pattern>
</servlet-mapping>
Hata sayfasıyla ilişkili JSP dosyası, erreur.jsp adını taşır ve uygulamanın kök dizininde bulunur:

Bu dosyanın takma adı /JSPerreur'tir; bu sayede URL http://localhost:8080/liste/JSPerreur adresi üzerinden erişilebilir. mainServlet adlı bir başlatma parametresine sahiptir ve bu parametrenin değeri, yukarıda açıklanan ana servletin takma adıdır. Bu takma adın, liste, uygulamasının kök dizinine göre göreceli olduğuna dikkat edilmelidir; aksi takdirde /liste/valeurs4. olurdu. erreur.jsp sayfasının kodu şöyledir:
<%
// _jspService kodu
// mainServlet başlatma parametresi alınır
String servletListValeurs=config.getInitParameter("mainServlet");
// msgErreur özniteliği alınır
String msgErreur=(String)request.getAttribute("msgErreur");
// Özellik geçerli mi?
if(msgErreur!=null){
%>
<!-- kod: HTML -->
<html>
<head>
<title>Erreur</title>
</head>
<body>
<h3>Application indisponible (<%= msgErreur %>)</h3>
</body>
</html>
<%
} else { // msgErreur özniteliği geçersiz - ana servlete geri dönülür
%>
<jsp:forward page="<%= servletListValeurs %>" />
<%
}
%>
Bu sayfa normalde önceki servlet tarafından çağrılmalı ve bu servlet, sayfaya msgErreur özniteliğini aktarmalıdır. Ancak, URL özniteliği biliniyorsa, sayfayı doğrudan çağırmaya engel olan bir şey yoktur. Ayrıca, msgErreur özniteliğinin eksik olduğu tespit edilirse, istek ana servlete iletilir. Burada, JSP sayfalarına özgü ve sözdizimi aşağıdaki gibi olan bir etiket kullanılır:
burada URL, istemcinin isteğinin aktarıldığı servletin URL değeridir. msgErreur özniteliği mevcutsa, hata sayfası görüntülenir.
Sayı listesini görüntüleyen JSP sayfası şu şekilde yapılandırılmıştır:
<servlet>
<servlet-name>JSPliste</servlet-name>
<jsp-file>/liste.jsp</jsp-file>
<init-param>
<param-name>mainServlet</param-name>
<param-value>/valeurs4</param-value>
</init-param>
.........
<servlet-mapping>
<servlet-name>JSPliste</servlet-name>
<url-pattern>/JSPliste</url-pattern>
</servlet-mapping>
Hata sayfasıyla ilişkili JSP dosyası, liste.jsp adını taşır ve uygulamanın kök dizininde bulunur:

Servletin takma adı /JSPliste olduğundan, URL http://localhost:8080/liste/JSPliste adresi üzerinden erişilebilir. mainServlet adlı bir başlatma parametresine sahiptir ve bu parametrenin değeri ana servletin takma adıdır. liste.jsp sayfasının kodu şöyledir:
<%-- değer listesini gösteren sayfa --%>
<%
// jspService kodu
// başlatma parametresi alınır
String servletListValeurs=config.getInitParameter("mainServlet");
// ana servlet'ten gelen isteğin özniteliklerini alıyoruz
String title=(String) request.getAttribute("title");
String[] valeurs=(String[]) request.getAttribute("valeurs");
String choix=(String) request.getAttribute("choix");
String URLservlet=(String) request.getAttribute("URLservlet");
// Özellikler geçerli mi?
if(title==null || valeurs==null || choix==null){
// geçersiz bir öznitelik var - kontrol servlet'e devrediliyor
%>
<jsp:forward page="<%= servletListValeurs %>" />
<%
}//eğer
%>
<%-- kod HTML --%>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h3>Choisissez une valeur</h3>
<form method="POST" action="<%= URLservlet %>">
<select name="cmbValeurs">
<%
// değerlerin dinamik olarak görüntülenmesi
String selected="";
for (int i=0;i<valeurs.length;i++){
if(valeurs[i].equals(choix)) selected="selected"; else selected="";
out.println("<option "+selected+">"+valeurs[i]+"</option>");
}//for
%>
</select>
<input type="submit" value="Envoyer">
</form>
<%
// bir değer seçilmiş miydi?
if(! choix.equals("")){
// kullanıcının seçimi görüntülenir
%>
<hr>Vous avez choisi le nombre<h2><%= choix %></h2>
<%
}//if
%>
</body>
</html>
Bu sayfa, erreur.jsp sayfası gibi çalışır. Normalde /liste/valeurs4 servleti tarafından çağrılmalı ve title, valeurs ve choix özniteliklerini almalıdır. Bu parametrelerden herhangi biri eksikse, kontrol URLservlet (/liste/valeurs4) servletine devredilir. Parametrelerin tümü mevcutsa, sayı listesi ve kullanıcı tarafından seçilmişse seçilen sayı görüntülenir.
Ana servletin URL'i çağrıldığında, şu sonuç elde edilir:

ve aşağıdaki kaynak kod (View/Source) ile birlikte:
<html>
<head>
<title>Génération d'un formulaire</title>
</head>
<body>
<h3>Choisissez une valeur</h3>
<form method="POST" action="/liste/valeurs4">
<select name="cmbValeurs">
<option >0</option>
<option >1</option>
<option >2</option>
<option >3</option>
<option >4</option>
<option >6</option>
<option >5</option>
<option >7</option>
<option >8</option>
<option >9</option>
</select>
<input type="submit" value="Envoyer">
</form>
</body>
</html>
Bu HTMl belgesi, JSP liste.jsp sayfası tarafından oluşturulmuştur. title, valeurs ve URLservlet özniteliklerinin başarıyla alındığı görülmektedir.
JSP servletleri ve sayfaları arasındaki işbirliğini özetlemek gerekirse, JSP sayfalarının burada çok kısa olduğunu ve HTML yanıtını doğrudan oluşturmaya katkıda bulunmayan Java kodunu içermediğini gözlemliyoruz. Böylece, oluşturulan belgelerin yapısı daha net bir şekilde görülmektedir.
3.4. JSP servletleri ve sayfalarının yaşam döngüsü
3.4.1. Yaşam döngüsü
Burada servletlerin yaşam döngüsüyle ilgileniyoruz. JSP sayfalarının yaşam döngüsü ise bundan kaynaklanmaktadır. İlk kez çağrılan bir servleti ele alalım. Bu durumda, web sunucusu tarafından bir sınıf örneği oluşturulur ve belleğe yüklenir. Ardından bu örnek, isteği işler. Bu işlem tamamlandıktan sonra, servlet bellekten kaldırılmaz. Sunucunun yanıt sürelerini optimize etmek amacıyla diğer istekleri karşılamak üzere bellekte kalır. Yeni istekleri karşılamadan yeterince uzun bir süre geçtikten sonra bellekten kaldırılır. Bu süre genellikle web sunucusu içinde yapılandırılabilir.
Bellekteyken, servlet aynı anda birden fazla isteği karşılayabilir. Web sunucusu, her istek için bir iş parçacığı oluşturur ve bu iş parçacıkları aynı servlet örneğini kullanır:
![]() |
Yukarıdaki tüm iş parçacıkları, servlet örneğinin değişkenlerini paylaşır. Servlet verilerinin bozulmasını önlemek için iş parçacıklarını senkronize etmek gerekebilir. Bu konuya daha sonra tekrar döneceğiz.
Bir servlet yüklendiğinde, servletin belirli bir yöntemi yürütülür:
JSP sayfası için bu yöntem
public void jspInit(){
}
yöntemi uygulanır. Aşağıda, jspInit yöntemini kullanan JSP sayfasına bir örnek verilmiştir:
<html>
<head>
<title>Compteur synchronisé</title>
</head>
<body>
Compteur= <%= getCompteur() %>
</body>
</html>
<%!
// JSP sayfasının genel değişkenleri ve yöntemleri
// örnek değişkeni
int compteur;
// sayaç artırma yöntemi
public int getCompteur(){
// sayaç artırılıyor
int myCompteur=compteur;
myCompteur++;
compteur=myCompteur;
// değerine geri getirilir
return compteur;
}
// sayfanın ilk yüklenmesinde yürütülen yöntem
public void jspInit(){
// sayaç başlatma
compteur=100;
}
%>
Önceki JSP sayfası, jspInit'teki bir sayacı 100'e sıfırlar. Servlete gelen sonraki her istek, bu sayacın değerini bir artırır ve ardından görüntüler:
İlk seferde:

İkinci sefer:

Yukarıda açıkça görüldüğü gibi, iki istek arasında servlet kapatılmamıştır; aksi takdirde ikinci istekte sayaç 101 olurdu. Servlet kapatıldığında,
yöntemi, varsa yürütülür. JSP sayfaları için ise
public void jspDestroy(){
}
Bu yöntemlerde, örneğin, ilgili init yöntemlerinde açılmış olan veritabanı bağlantılarını kapatabilirsiniz.
3.4.2. Bir servlet'e yapılan isteklerin senkronizasyonu
Bir sayacı artırıp bunu web istemcisine geri gönderen önceki JSP sayfasına geri dönelim. Eşzamanlı 2 istek olduğunu varsayalım. Bu istekleri yürütmek için iki iş parçacığı oluşturulur; bu iş parçacıkları aynı servlet örneğini, yani burada aynı sayacı kullanacaktır. Sayacı artıran kodu hatırlayalım:
public int getCompteur(){
// sayaç artırılır
int myCompteur=compteur;
myCompteur++;
compteur=myCompteur;
// geri verilir
return compteur;
}
Sayaç artışı kasıtlı olarak hatalı bir şekilde yazılmıştır. İki iş parçacığının yürütülmesinin şu şekilde gerçekleştiğini varsayalım:
![]() |
- T1 zamanında, TH1 iş parçacığı yürütülür. myCompteur'teki sayacı (=145) okur, ardından kesintiye uğrar ve işlemciyi kaybeder. Dolayısıyla, myCompteur'i artırmaya ve yeni değeri compteur'e kopyalamaya vakti olmamıştır.
- T2 zaman diliminde, TH2 iş parçacığı yürütülür. myCompteur'teki sayacı (=145) okur, ardından kesintiye uğrar ve işlemciyi kaybeder. Her iki iş parçacığının da farklı myCompteur değişkenlerine sahip olduğu unutulmamalıdır. Yalnızca yöntemler için genel olan örnek değişkenlerini paylaşırlar.
- T3 zaman diliminde, TH1 iş parçacığı kontrolü geri alır ve işlemi tamamlar. Böylece müşterisine 146 değerini döndürür.
- T4 zamanında, TH2 iş parçacığı kontrolü geri alır ve işini tamamlar. O da müşterisine 146 değerini döndürür, oysa 147 değerini döndürmesi gerekirdi.
Burada bir iş parçacığı senkronizasyon sorunu söz konusudur. TH1 sayacı artırmak istediğinde, diğer tüm iş parçacıklarının da bunu yapmasını engellemek gerekir. Bu sorunu vurgulamak için JSP sayfasını şu şekilde yeniden yazıyoruz:
<html>
<head>
<title>Compteur synchronisé</title>
</head>
<body>
Compteur= <%= getCompteur() %>
</body>
</html>
<%!
// sayfanın küresel değişkenleri ve yöntemleri JSP
// örnek değişkeni
int compteur;
// sayaç artırma yöntemi
public int getCompteur(){
// sayaç okunur
int myCompteur=compteur;
// 10 saniye duraklama
try{
Thread.sleep(10000);
}catch (Exception ignored){}
// sayaç artırılır
compteur=myCompteur+1;
// değer geri verilir
return compteur;
}
// sayfanın ilk yüklenmesinde yürütülen yöntem
public void jspInit(){
// sayaç başlatılır
compteur=100;
}
%>
Burada, sayacı okuduktan 10 saniye sonra iş parçacığının durmasını sağladık. Böylece iş parçacığı işlemciyi serbest bırakmalı ve başka bir iş parçacığı da artırılmamış bir sayacı okuyabilmelidir. Tarayıcıyla istek gönderdiğimizde, sonucu almadan önce 10 saniye beklemek dışında bir fark görmüyoruz.

Şimdi iki tarayıcı penceresi açıp, zaman aralığı yeterince kısa olacak şekilde iki istek gönderirsek:


Aynı sayaç değerini elde ederiz. Tarayıcı gibi manuel bir istemci yerine programlanmış bir istemci kullanarak sorunu daha iyi ortaya koyabiliriz. Aşağıda, şu şekilde çağrılan bir Perl istemcisi yer almaktadır:
program URL N
burada
URL, sayım servletinin URL'sidir
N, bu servlete yapılacak istek sayısı
İşte 5 istek için elde edilen sonuçlar; bunlar, iş parçacıkları arasındaki senkronizasyon sorununu açıkça göstermektedir: hepsi sayacın aynı değerini almaktadır.
DOS>java clientCompteurJSP http://localhost:8080/examples/jsp/perso/compteur/compteur2.jsp 5
Compteur=121
Compteur=121
Compteur=121
Compteur=121
Compteur=121
Java istemcisinin kodu aşağıdaki gibidir.
import java.net.*;
import java.util.regex.*;
import java.io.*;
public class clientCompteurJSP {
public static void main(String[] params){
// veriler
String syntaxe="Syntaxe : pg URL nbAppels";
// parametre kontrolü
if(params.length!=2){
System.err.println(syntaxe);
System.exit(1);
}//if
// URL
URL urlCompteur=null;
try{
urlCompteur=new URL(params[0]);
String query=urlCompteur.getQuery();
if(query!=null) throw new Exception();
}catch (Exception ex){
System.err.println(syntaxe);
System.err.println("URL ["+params[0]+" incorrecte");
System.exit(2);
}//try-catch
// çağrı sayısı
int nbAppels=0;
try{
nbAppels=Integer.parseInt(params[1]);
if(nbAppels<=0) throw new Exception();
}catch(Exception ex){
System.err.println(syntaxe);
System.err.println("Nombre d'appels ["+params[1]+" incorrect");
System.exit(3);
}//try-catch
// parametreler doğru - URL'e bağlantı kurulabilir
try{
getCompteurs(urlCompteur,nbAppels);
}catch(Exception ex){
System.err.println(syntaxe);
System.err.println("L'erreur suivante s'est produite : "+ex.getMessage());
System.exit(4);
}//try-catch
}//ana işlev
private static void getCompteurs (URL urlCompteur, int nbAppels)
throws Exception {
// nbAppels'i URL'e yönlendirir urlCompteur
// her seferinde web sunucusu tarafından döndürülen sayaç değerini görüntüler
// urlCompteur'ten vergi sunucusuna bağlanmak için gerekli bilgiler alınır
String path=urlCompteur.getPath();
if(path.equals("")) path="/";
String host=urlCompteur.getHost();
int port=urlCompteur.getPort();
if(port==-1) port=urlCompteur.getDefaultPort();
// URL'e çağrılar yapılır
Socket[] clients=new Socket[nbAppels];
for(int i=0;i<nbAppels;i++){
// sunucuya bağlanılır
clients[i]=new Socket(host,port);
// sunucuya bir yazma akışı oluşturulur
PrintWriter OUT=new PrintWriter(clients[i].getOutputStream(),true);
// URL istenir - başlıkların gönderilmesi HTTP
OUT.println("GET " + path + " HTTP/1.1");
OUT.println("Host: " + host + ":" + port);
OUT.println("Connection: close");
OUT.println("");
}//için
// yerel veriler
String réponse=null; // sunucudan gelen yanıt
// sunucunun HTML yanıtında aranan şablon
Pattern modèleCompteur=Pattern.compile("^\\s*Compteur= (\\d+)");
// doğru yanıtın şablonu
Pattern réponseOK=Pattern.compile("^.*? 200 OK");
// şablonla karşılaştırma sonucu
Matcher résultat=null;
for(int i=0;i<nbAppels;i++){
// her istemci, sunucunun kendisine gönderdiği yanıtı okur
// TCP istemcisinin giriş-çıkış akışları oluşturulur
BufferedReader IN=new BufferedReader(new InputStreamReader(clients[i].getInputStream()));
// yanıtın ilk satırı okunur
réponse=IN.readLine();
// HTTP satırı, doğru yanıt şablonuyla karşılaştırılır
résultat=réponseOK.matcher(réponse);
if(! résultat.find()){
// URL ile ilgili bir sorun var
throw new Exception("Client n° " + i + " - Le serveur a répondu : URL ["+ urlCompteur + "] inconnue");
}//if
// başlıklar bitene kadar yanıt okunur
while((réponse=IN.readLine())!=null && ! réponse.equals("")){
}//while
// başlıklar bitti HTTP - koda geçiyoruz HTML
// sayaç değerini almak için
boolean compteurTrouvé=false;
while((réponse=IN.readLine())!=null){
// satırı sayaç şablonuyla karşılaştırıyoruz
if(! compteurTrouvé){
résultat=modèleCompteur.matcher(réponse);
if(résultat.find()){
// sayaç bulundu
System.out.println("Compteur="+résultat.group(1));
compteurTrouvé=true;
}//eğer
}//if
}//while
// işlem tamamlandı
clients[i].close();
}//for
}//getCompteurs
}//sınıf
Yukarıdaki kodu açıklayalım:
- program iki parametre kabul eder:
- sayaçtaki JSP sayfasının URL kodu
- bu URL için oluşturulacak müşteri sayısı
- Program bu nedenle önce parametrelerin geçerliliğini kontrol eder: parametre sayısının tam olarak iki olup olmadığını, ilk parametrenin sözdizimsel olarak bir URL'e, ikinci parametrenin ise >0 bir tamsayıya benzeyip benzemediğini kontrol eder. URL'in sözdizimsel olarak doğru olup olmadığını kontrol etmek için, URL sınıfı ve bunun URL (String) yapıcı işlevi kullanılır; bu yapıcı, http://istia.univ-angers.fr gibi bir karakter dizisinden bir URL nesnesi oluşturur. Dize, sözdizimi açısından geçerli bir URL değilse bir istisna atılır. Bu, ilk parametrenin geçerliliğini kontrol etmemizi sağlar.
- Parametreler doğrulandıktan sonra, kontrol getCompteurs prosedürüne geçer. Bu yordam, nbAppels istemcileri oluşturacak ve bunların tümü aynı anda (veya neredeyse aynı anda) URL urlCompteur'e bağlanacaktır.
- İstemcilerin bağlanması gereken bağlantı noktası ve makine, URL ve urlCompteur: [URL]'ten alınır.getHost() işlevi makinenin adını, [URL].getPort() işlevi ise bağlantı noktasını sağlar.
- İlk döngü, her bir istemcinin:
- web sunucusuna bağlanmasını
- URL urlCompteur'i istemesine
Bu döngüde, istemci sunucunun yanıtını beklemez. Aslında, sunucunun neredeyse eşzamanlı istekler almasını sağlamak istiyoruz.
- İkinci bir döngü, her bir istemcinin sunucudan aldığı yanıtı almasına ve işlemesine olanak tanır. İşleme, yanıtta sayaç değerini içeren satırı bulmak ve bunu görüntülemekten ibarettir.
Daha önce ortaya çıkan sorunu (beş müşteriye de aynı sayaç değerinin gönderilmesi) çözmek için, sayacı okuma ve güncelleme gibi kritik bölüme girmeden önce sayım hizmetinin iş parçacıklarını aynı nesne üzerinde senkronize etmemiz gerekir. Yeni JSP sayfası şu şekildedir:
<html>
<head>
<title>Compteur synchronisé</title>
</head>
<body>
Compteur= <%= getCompteur() %>
</body>
</html>
<%!
// sayfanın küresel değişkenleri ve yöntemleri JSP
// örnek değişkenleri
int compteur;
Object verrou=new Object();
// sayaç artırma yöntemi
public int getCompteur(){
// kritik bölümü senkronize ediyoruz
synchronized(verrou){
// sayaç okunur
int myCompteur=compteur;
// 10 saniye durulur
try{
Thread.sleep(10000);
}catch (Exception ignored){}
// sayaç artırılıyor
compteur=myCompteur+1;
}//senkronize edildi
// geri verilir
return compteur;
}//getCompteur
// sayfa ilk yüklendiğinde yürütülen yöntem
public void jspInit(){
// sayaç başlatma
compteur=100;
}
%>
Çalıştırıldığında şu sonuçlar elde edilir:
dos>c:\perl\bin\perl.exe client2.pl http://localhost:8080/examples/jsp/perso/compteur/compteur3.jsp 5
Compteur= 104
Compteur= 106
Compteur= 105
Compteur= 107
Compteur= 108
Belgelere göre, web sunucusu bazen aynı servletin birden fazla örneğini oluşturabilir. Bu durumda, verrou değişkeni bir örneğe özgü olduğundan ve diğer örnekler tarafından bilinmediğinden, önceki senkronizasyon artık çalışmaz. Aynı durum compteur değişkeni için de geçerlidir. Bu değişkenleri tüm örnekler için genel hale getirmek için şu kod yazılmalıdır:
// sınıf değişkeni
static int compteur;
static Object verrou=new Object();
Kodun geri kalan kısmı değişmez.





