Skip to content

10. MVC [personne] web uygulaması – sürüm 5

10.1. Introduction

Bu sürümde iki değişiklik yapıyoruz:

İlki, istemcinin sunucuya gerçekleştirmek istediği eylemi bildirmesi ile ilgilidir. Şimdiye kadar bu, istemcinin GET veya POST isteğinde [action] adlı bir parametre kullanılarak belirtiliyordu. Burada, eylem, aşağıdaki dizide gösterildiği gibi, istemci tarafından talep edilen URL’nin son öğesi ile belirtilecektir:

Image

[1] örneğinde, formun gönderildiği URL [/personne5/do/validationFormulaire]'tir. Denetleyicinin gerçekleştirilmesi gereken eylemi tanımasını sağlayan, URL'nin son öğesi olan [validationFormulaire]'tir. [2] örneğinde, [Retour au formulaire] bağlantısı tarafından tetiklenen POST eylemi, [/personne5/do/retourFormulaire] URL'sinde gerçekleştirilmiştir. Yine burada, URL'nin son öğesi olan [retourFormulaire], denetleyiciye gerçekleştirilmesi gereken eylemi belirtir.

Bu değişikliği, Struts veya Spring MVC gibi en yaygın web geliştirme çerçevelerinde kullanılan yöntem bu olduğu için yapıyoruz.

Uygulamadaki tüm URL’ler [/personne5/do/action] biçiminde olacaktır. [/personne5] uygulamasının [web.xml] dosyası, bu uygulamanın [/do/*] biçimindeki URL’leri kabul ettiğini gösterecektir:


    <servlet-mapping>
        <servlet-name>personne</servlet-name>
        <url-pattern>/do/*</url-pattern>
</servlet-mapping>

Denetleyici, gerçekleştirilecek eylemin adını şu şekilde alacaktır:

         // yürütülecek eylem alınır
String action=request.getPathInfo();

[request] nesnesinin [getPathInfo] yöntemi, istek URL'sinin son öğesini verir.

İkinci değişiklik, iki istek/yanıt döngüsü arasında kullanıcı tarafından yapılan girişlerin nasıl saklanacağına ilişkindir. Şu anda bu bilgiler bir oturumda saklanmaktadır. Kullanıcı sayısı fazla ve her biri için saklanacak veri miktarı çok fazla ise bu yöntem bazı dezavantajlar doğurabilir. Zira her kullanıcının kendine ait bir oturumu vardır. Ayrıca, kullanıcıya oturumu kapatma seçeneği sunulmadığı sürece, oturum kullanıcı ayrıldıktan sonra da bir süre aktif kalır. Dolayısıyla, 1000 baytlık 1000 oturum, 1 MB bellek kaplar. Bu, makul bir gereksinimdir ve aynı anda 1000 aktif oturuma sahip çok az uygulama vardır.

Bununla birlikte, oturumun yerine kullanılabilecek, bellek açısından daha az kaynak tüketen alternatifler mevcuttur ve bunları bilmek faydalıdır. Burada çerez yöntemini kullanacağız. Bunu bir örnekle açıklayalım.


Adım 1: Kullanıcı bir formu gönderir:


Bu istek/yanıt döngüsü, istemci ile sunucu arasında aşağıdaki HTTP alışverişlerine yol açar:

[1] : [demande du client]

POST /personne5/do/validationFormulaire HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: fr-fr,fr;q=0.8,en;q=0.6,en-us;q=0.4,de;q=0.2
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost:8080/personne5/do/form
Cookie: JSESSIONID=6C6F4D112803A7E3696D41F5750CEDE7
Content-Type: application/x-www-form-urlencoded
Content-Length: 24

txtNom=pauline&txtAge=18

Bu, klasik bir POST örneğidir. Burada dikkat çekecek özel bir durum yoktur; ancak oturum kullanılmayacak olmasına rağmen web sunucusu yine de bir oturum oluşturmaktadır. Bunu, tarayıcının 11. satırda sunucuya geri gönderdiği ve daha önce sunucudan aldığı oturum jetonundan görebiliriz.

[2] : [réponse du serveur]

1
2
3
4
5
6
7
HTTP/1.x 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: nom=pauline
Set-Cookie: age=18
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 547
Date: Mon, 22 May 2006 08:03:51 GMT
  1. ve 4. satırlarda, HTTP ve [Set-Cookie] başlıklarının istemci tarayıcısına gönderildiği görülmektedir; bunlardan biri isim (3. satır), diğeri ise yaş (4. satır) içindir. Bu çerezlerin değerleri, yukarıdaki POST ve [1] başlıklarının 14. satırında gönderilen değerlerdir.

Adım 2: Forma geri dönüş


Image

Bu istek/yanıt döngüsü, istemci ile sunucu arasında aşağıdaki HTTP alışverişlerine yol açar:

[1] : [demande du client]

POST /personne5/do/retourFormulaire HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: fr-fr,fr;q=0.8,en;q=0.6,en-us;q=0.4,de;q=0.2
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost:8080/personne5/do/validationFormulaire
Cookie: nom=pauline; age=18; JSESSIONID=6C6F4D112803A7E3696D41F5750CEDE7
Content-Type: application/x-www-form-urlencoded
Content-Length: 0

Burada, [Retour au formulaire] bağlantısına tıklanmasıyla tetiklenen POST'i görüyoruz. 11. satırda, tarayıcının Http başlığı aracılığıyla aldığı [nom, age, JSESSIONID] çerezlerini sunucuya geri gönderdiğini görüyoruz. Bu, çerezlerin çalışma prensibidir. İstemci, tarayıcının kendisine gönderdiği çerezleri tarayıcıya geri gönderir. Bu örnekte, denetleyici [pauline, 18] değerlerini alacak ve bunları [2] sayfasında görüntülenen [formulaire] görünümünün [txtNom, txtAge] alanlarına yerleştirmelidir.

[2] : [réponse du serveur]

1
2
3
4
5
HTTP/1.x 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 2341
Date: Mon, 22 May 2006 08:16:47 GMT

Burada, bu yanıtta sunucunun çerez göndermediği gerçeği dışında özellikle belirtilmesi gereken bir durum yoktur. Bu, tarayıcının bir sonraki iletişimde sunucudan aldığı tüm çerezleri geri göndermesini engellemeyecektir, ancak bunun bir faydası yoktur. Dolayısıyla, istemci/sunucu iletişimlerindeki karakter akışının artması pahasına, sunucunun kullanılabilir belleği üzerindeki yük azaltılır.

10.2. Eclipse Projesi

[/personne5] web uygulamasının Eclipse projesi [mvc-personne-05]'i oluşturmak için, 6.2. paragrafında açıklanan prosedürü izleyerek [mvc-personne-04] projesini kopyalayacağız.

10.3. [personne5] web uygulamasının yapılandırılması

/personne5 uygulamasının web.xml dosyası şu şekildedir:


<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>mvc-personne-05</display-name>
    <!--  ServletPersonne -->
    <servlet>
        <servlet-name>personne</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletPersonne
        </servlet-class>
...
    </servlet>
    <!--  Eşleme ServletPersonne-->
    <servlet-mapping>
        <servlet-name>personne</servlet-name>
        <url-pattern>/do/*</url-pattern>
    </servlet-mapping>
    <!--  ana sayfalar -->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Bu dosya, birkaç ayrıntı dışında önceki sürümdekiyle aynıdır:

  • 6. satır: Web uygulamasının görüntüleme adı [mvc-personne-05] olarak değiştirilmiştir
  • 18. satır: Uygulama tarafından işlenen URL'ler [/do/*] biçimindedir. Önceden yalnızca [/main] URL'si işleniyordu. Artık işlenecek eylem sayısı kadar URL vardır.

[index.jsp] ana sayfası değişiyor:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>

<c:redirect url="/do/formulaire"/>
  • 5. satır: [index.jsp] sayfası, istemciyi [/personne5/do/formulaire] URL'sine yönlendirir; bu da denetleyiciye [formulaire] eylemini yürütmesini istemekle aynı anlama gelir.

10.4. Görünüm kodları

[formulaire, réponse, erreurs] görünümlerinde çok az değişiklik vardır. Tek değişiklik, gerçekleştirilecek eylemin artık eskisi gibi, gönderilen formlardaki [action] adlı gizli bir alanda tanımlanmamasıdır. Artık bu eylem, gönderilen formların hedef URL’sinde, <form> etiketinin [action] özniteliğinde tanımlanmaktadır:

[formulaire.jsp]:


...
<html>
  <head>
    <title>Personne - formulaire</title>
    <script language="javascript">
...
    </script>
  </head>
  <body>
    <center>
      <h2>Personne - formulaire</h2>
      <hr>
      <form name="frmPersonne" action="validationFormulaire" method="post">
...
      </form>
    </center>
  </body>
</html>
  • [13] satırı: Formun [action] parametresi, önceki sürümlerde bir süre ortadan kaybolduktan sonra yeniden ortaya çıkmıştır. Bu özniteliğin değerini anlamak için, uygulama tarafından işlenen tüm URL'lerin [/do/action] biçiminde olduğunu hatırlamak gerekir. [13] satırında, [action] özniteliğinin değeri, / ile başlamayan bir göreceli URL'dir. Bu nedenle tarayıcı, bu URL'yi o anda görüntülenen sayfanın URL'siyle tamamlayacaktır; dolayısıyla bu URL mutlaka [/do/action] biçiminde olacaktır. Son öğe, <form> etiketindeki [action] özniteliğinin göreceli URL'si ile değiştirilecek ve böylece [/do/validationFormulaire] URL'si, POST'in hedefi olarak belirlenecektir.
  • Gizli alan [action] kayboldu

[réponse.jsp]:


...

<html>
...
  <body>
      ...
    <form name="frmPersonne" action="retourFormulaire" method="post">
    </form>
    <a href="javascript:document.frmPersonne.submit();">
      ${lienRetourFormulaire}
    </a>
  </body>
</html>

  • [7] satırı: POST'in hedefi [/do/retourFormulaire] olacaktır
  • 7-8. satırlardaki formda [action] gizli alanı kayboldu.

[erreurs.jsp]:


...
<html>
...
  <body>
...
    <form name="frmPersonne" action="retourFormulaire" method="post">
    </form>
    <a href="javascript:document.frmPersonne.submit();">
      ${lienRetourFormulaire}
    </a>
  </body>
</html>

  • [6] satırı: POST'in hedefi [/do/retourFormulaire] olacaktır
  • Gizli alan [action], 6-7. satırlardaki formdan kaldırılmıştır.

Okuyucunun, önceki sürümlerde görülen ilkeye göre bu yeni görünümleri test etmesi önerilir.

10.5. [ServletPersonne] denetleyicisi

[/personne5] web uygulamasının denetleyicisi [ServletPersonne], aşağıdaki eylemleri işleyecektir:

No.
istek
kaynak
işlem
1
[GET /personne5/do/formulaire]
kullanıcı tarafından girilen URL
- boş [formulaire] görünümünü göndermek
2
[POST
/personne5/do/validationFormulaire]
[txtNom, txtAge] parametreleriyle
gönderildi
düğmeye tıklayın
[Envoyer] düğmesine tıklayın
[formulaire]
- [txtNom, txtAge] parametre değerlerini kontrol edin
- değerler yanlışsa, [erreurs(erreurs)] görünümünü gönderin
- değerler doğruysa, [reponse(nom,age)] görünümünü gönderin
3
[POST
/personne5/do/retourFormulaire]
gönderilen parametreler olmadan
[Forma
formuna geri dön] bağlantısına tıklayın
[réponse] ve [erreurs].
- en son girilen değerlerle önceden doldurulmuş [formulaire] görünümünü gönderin

[ServletPersonne] denetleyicisinin iskeleti, önceki sürümünkiyle aynıdır. [doValidationFormulaire, doRetourFormulaire, doGet] yöntemlerinde yapılan değişiklikleri gözden geçiriyoruz; [init, doInit, doPost] yöntemlerinde ise herhangi bir değişiklik yapılmamıştır.

10.5.1. [doGet] yöntemi

[doGet] yöntemi, önceki sürümlerdeki gibi yürütülecek eylemi aynı şekilde almamaktadır:

        @SuppressWarnings("unchecked")
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

         // servletin başlatılmasının nasıl gerçekleştiği kontrol edilir
        if (erreursInitialisation.size() != 0) {
...
        }
         // isteği gönderme yöntemi alınır
        String méthode=request.getMethod().toLowerCase();
         // yürütülecek eylemi alıyoruz
        String action=request.getPathInfo();
         // eylem?
        if(action==null){
            action="/formulaire";
        }
         // eylemin yürütülmesi
        if(méthode.equals("get") && action.equals("/formulaire")){
             // uygulamanın başlatılması
            doInit(request,response);
            return;
        }
        if(méthode.equals("post") && action.equals("/validationFormulaire")){
             // giriş formunun doğrulanması
            doValidationFormulaire(request,response);
            return;
        }
        if(méthode.equals("post") && action.equals("/retourFormulaire")){
             // giriş formuna geri dönüş
            doRetourFormulaire(request,response);
            return;
        }
         // diğer durumlar
        doInit(request,response);
    }
  • 12. satır: Yürütülecek eylem alınır. Bu eylem, [/action] biçimindedir.
  • 18-22. satırlar: GET isteği tarafından talep edilen [/formulaire] eyleminin işlenmesi
  • 23-27. satırlar: POST isteği ile talep edilen [/validationFormulaire] eyleminin işlenmesi
  • satır 28-32: POST isteği tarafından talep edilen [/retourFormulaire] eyleminin işlenmesi

10.5.2. [doValidationFormulaire] yöntemi

Bu yöntem, gönderilen öğeler içindeki [txtNom, txtAge] ile birlikte 2 numaralı [POST /personne5/do/validationFormulaire] isteğini işler. Kodu şöyledir:

// formun onaylanması
    void doValidationFormulaire(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException{
         // parametreler alınır
        String nom = request.getParameter("txtNom");
        String age = request.getParameter("txtAge");
         // bir çerezde saklanan parametreler
        response.addCookie(new Cookie("nom",nom));
        response.addCookie(new Cookie("age",age));
         // parametrelerin doğrulanması
        ...
    }

Yenilikler:

  • [doValidationFormulaire] yöntemi, yanıt olarak [réponse, erreurs] görünümlerinden birini gönderir. Yanıt ne olursa olsun, denetleyici bu yanıtın içine iki çerez ekler (8-9. satırlar). Bir çerez, [Cookie] nesnesiyle temsil edilir; bu nesnenin oluşturucusu, çerez anahtarı ve buna ilişkin değer olmak üzere iki parametre kabul eder.
  • 8. satır: "ad" adı için girilen değer, "ad" anahtarına sahip bir çereze eklenir
  • 9. satır: yaş için girilen değer, "age" anahtarına sahip bir çereze eklenir
  • [response.addCookie] yöntemi ile müşteriye gönderilen HTTP yanıtına bir çerez eklenir. Bu yanıt burada sadece hazırlanmaktadır. Gerçek anlamda ancak müşteriye gönderilen görünümün JSP sayfası çalıştırıldığında gönderilecektir.

10.5.3. [doRetourFormulaire] yöntemi

Bu yöntem, gönderilen öğe içermeyen 2 numaralı [POST /personne5/do/retourFormulaire] isteğini işler. Kod şöyledir:

         // önceden doldurulmuş formun görüntülenmesi
    void doRetourFormulaire(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
         // kullanıcının çerezlerini alıyoruz
        Cookie[] cookies=request.getCookies();
        String nom=null;
        String age=null;
        int nbCookies=0;
        for(int i=0;i<cookies.length && nbCookies<2;i++){
            if(cookies[i].getName().equals("nom")){
                nom=cookies[i].getValue();
                nbCookies++;
            }else{
                if(cookies[i].getName().equals("age")){
                    age=cookies[i].getValue();
                    nbCookies++;
                }
            }
        }
         // form şablonunun hazırlanması
        request.setAttribute("nom",nom);
        request.setAttribute("age",age);
         // form görüntüleniyor
        getServletContext().getRequestDispatcher((String)params.get("urlFormulaire")).forward(
                request, response);
        return;
    }

Yenilikler:

[doRetourFormulaire] yöntemi, en son yapılan girişlerle önceden doldurulmuş bir formun görüntülenmesini sağlamalıdır. Önceki sürümde bu veriler oturumda saklanıyordu. Bu sürümde ise, istemci-sunucu arasındaki iki iletişim arasında verileri saklamak için artık oturum yerine çerezler kullanılmaktadır. Müşteri formun onaylanmasını talep ettiğinde, duruma göre [réponse] veya [erreurs] görünümünü yanıt olarak aldı; bu görünüm, "nom" ve "age" adlı iki çerezle birlikte gönderildi. Bu iki görünümdeki [Retour au formulaire] bağlantısına tıklandığında, URL'de [/do/retourFormulaire] adresi üzerine POST oluşturulur ve tarayıcı, aldığı iki çerezi sunucuya geri gönderir.

  • 4-18. satırlar: "nom" ve "age" adlı çerezlerin değerleri alınır. Oldukça tuhaf bir şekilde, bir çerezin anahtarından değerini elde etmeyi sağlayan bir yöntem yoktur. Bu nedenle, alınan her bir çerezi tek tek incelemek zorundayız.
  • Bu işlem tamamlandıktan sonra, elde edilen iki değer, görüntülenmeleri için [formulaire] görünüm şablonuna (satır 20-21) yerleştirilir.

10.6. Tests

Eclipse projesini [personne-mvc-05]'e entegre ettikten sonra Tomcat'i başlatın veya yeniden başlatın, ardından [http://localhost:8080/personne5] URL'sini çağırın.