Skip to content

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:

Image

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:
        response.setContentType("text/html");
  • Yanıtı istemciye göndermek için servlet, response nesnesi tarafından sağlanan bir çıkış akışını kullanır:
        PrintWriter out = response.getWriter();
  • 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:

Image

Servlet tarafından gönderilen yanıt:

Image

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
        out.print("<form action=\"RequestParamExample\" method=\"POST\">");
  • 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:

Image

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:
        Enumeration e = request.getHeaderNames();
  • 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ı
User-Agent
tarayıcının kimliği
Accept
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.
Host
hote:port formatında. Tarayıcının hangi makineye ve hangi bağlantı noktasına bağlanmak istediğini gösterir.
Accept-Encoding
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.
Accept-language
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.
Referer
tarayıcı tarafından talep edilen URL
Connection
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.

Image

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
getServerName()
web sunucusunun adı
getServerPort()
web sunucusunun çalışma bağlantı noktası
getMethod()
tarayıcının isteğini göndermek için kullandığı GET veya POST yöntemi
getRemoteHost()
tarayıcının isteğini gönderdiği istemci makinesinin adı
getRemoteAddr()
aynı makinenin IP adresi
getContentType()
tarayıcı tarafından gönderilen içerik türü (http başlığı Content-type)
getContentLength()
tarayıcı tarafından gönderilen karakter sayısı (http başlığı Content-length)
getProtocol()
tarayıcı tarafından istenen http protokolünün sürümü
getRequestURI()
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:

Image

Servlet tarafından gönderilen yanıt:

Image

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)

Image

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:

Image

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

Image

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:

Image

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:

Image

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

Image

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:

      <select name="cmbValeurs" size="1">

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:

Image

Peki yanıt farklı mı?

Image

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:

Image

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

Image

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:

  1. 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
  2. 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.
  3. 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.
  4. 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.
  5. 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:

Image

Şimdi MySQL sunucusunu başlatırsak, şu sayfa görüntülenir:

Image

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

Image

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:

Image

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:

    <form method="POST" action="http://localhost:8080/examples/servlet/parameters">

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:

Image

Girilen balises2.htm formu şuysa:

Image

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:

Image

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:

  1. 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.
  2. 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
      String areaSaisie=getParameter(request,"areaSaisie");
      String[] lignes=areaSaisie.split("\\r\\n");

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 method="GET" action="http://localhost:8080/examples/servlet/headers">

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:

Image

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:

    <form method="POST" action="http://localhost:8080/examples/servlet/headers">

Böylece şu yeni yanıtı elde ediyoruz:

Image

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:

Image

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:

Image

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

Image

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 -->
açıklama HTML. İstemciye gönderilir.
<%-- açıklama --%>
açıklama JSP. Müşteriye gönderilmez.
<%! déclarations, méthodes %>
Küresel değişkenleri ve yöntemleri tanımlar. Değişkenler tüm yöntemlerde kullanılabilir olacaktır
<%= expression %>
ifadenin değeri, HTML sayfasına
<% code Java %>
JSP sayfasının ana yönteminin bir parçası olacak Java kodu içerir
<%@ page attribut1=valeur1
attribut2=valeur2 … %>
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
HttpServletRequest request
Web istemcisinin isteğine (getParameter, getParameterNames, getParameterValues) erişim sağlayan nesne
HttpServletResponse response
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.
JspWriter out
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:

Image

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.
        JspWriter out = null;
...
            out = pageContext.getOut();
  • 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:

Image

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?

nom (tintin)
, JSP sayfasının ana yöntemine ait yerel bir değişkendir ve bu nedenle bu yöntem içinde bilinir
prenom (inconnu)
ise JSP sayfasının küresel bir değişkenidir ve bu nedenle ana yöntemde bilinir
sonChien (milou)
, JSP sayfasının genel bir yöntemidir ve bu nedenle ana yöntemden erişilebilir
afficheAmi (Haddock)
, 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:

  1. sayfadaki JSP kodu hatalı (örneğin, kullanılan jsp etiketlerinde hatalar)
  2. 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:

Image

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:

Image

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:

<personne>
    <prenom>Pierre</prenom>
  <nom>Lucas</nom>
  <age>28</age>
</personne>

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:

Image

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:

<personne><prenom>Pierre</prenom><nom>Lucas</nom><age>28</age></personne>

ve bunu IE6 ile görüntülersek, aynı görüntüyü elde ederiz:

Image

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:

Image

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:

Image

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:

Image

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:

Image

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.

Image

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:

Image

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:

Image

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

Image

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:

Image

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

Image

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:

Image

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:

Image

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:

Image

liste uygulamasının server.xml dosyasındaki yapılandırmasını hatırlayalım:

                <Context path="/liste" docBase="e:/data/serge/servlets/lstValeurs" />

/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:

Image

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:

title
servlet tarafından oluşturulan HTML belgesinin başlığı
DSNValeurs
servletin veri alacağı ODBC veritabanının adı DSN
admDbValeurs
önceki veritabanında okuma hakkına sahip bir kullanıcının adı
mdpDbvaleurs
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:

    <init-param>
        <param-name>...</param-name>
        <param-value>...</param-value>
    </init-param>
<param-name>
parametrenin adını tanımlamaya olanak tanır
<param-value>
önceki parametreye atanan değeri tanımlar

Servlet, aşağıdaki yöntemler aracılığıyla başlatma parametrelerine erişebilir:

[Servlet].getServletConfig()
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].getInitParameter("paramètre")
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:

Image

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:

Image

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

Image

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:

[Servlet].getServletContext()
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].getInitParameter("paramètre")
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:

Image

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:

Image

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:

Image

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:

Image

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:

Image

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].getRequestDispatcher(
String url)
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].forward
(ServletRequest request,
 ServletResponse response)
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.
[ServletRequest].setAttribute(String nom, Object obj)
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.
[ServletRequest].getAttribute(
String attribut)
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:

title
oluşturulacak HTML belgesinin başlığı
JSPerreur
hata sayfası JSP'in URL'i
JSPliste
sayı listesini içeren JSP sayfasının URL kodu
URLservlet
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  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ı ?
            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:

Image

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:

Image

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:

<jsp:forward page="URL" />

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:

Image

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:

Image

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:

public void init() throws ServletException{
}

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:

Image

İkinci sefer:

Image

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,

public void destroy(){
}

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:

 
  1. 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.
  2. 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.
  3. 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.
  4. 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.

Image

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

Image

Image

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.