This document was uploaded by user and they confirmed that they have the permission to share
it. If you are author or own the copyright of this book, please report to us by using this DMCA
report form. Report DMCA
Overview
Download & View Spring Mvc Uygulama Catisi Osunercan Wwwjavadilicom as PDF for free.
İçindekiler Giriş......................................................................................................................................................3 Belge İçeriği Hakkında....................................................................................................................3 Spring MVC..........................................................................................................................................3 Geliştirme Ortamının Hazırlanması.................................................................................................3 Kurulum......................................................................................................................................3 Uygulama Kılavuz Yapısının Oluşturulması...............................................................................4 Başlangıç (DispatcherServlet).........................................................................................................4 İlk Spring MVC Örneği...................................................................................................................5 Uygulamaya Başlıyoruz.................................................................................................................11 Ana Sayfa.......................................................................................................................................13 Form Kullanımı..............................................................................................................................15 Araç Girişi......................................................................................................................................17 Doğrulama (Validation).................................................................................................................23 Durdurucular (Interceptors)...........................................................................................................28 Sonuç..................................................................................................................................................31 Terimler Sözlüğü................................................................................................................................32 Kaynaklar............................................................................................................................................32
Giriş Spring, son dönemde J2EE uygulaması geliştirme alanında popülerlik kazanan ve yaygın olarak kullanılmaya başlanılan bir uygulama geliştirme çatısıdır (application framework). Uygulama geliştirmeyi ve denetimi zorlaştıran ağır (heavy weight) çözümlere alternatif olarak hafif (lightweight) bir yapı sunarken, aynı zamanda esnek ve modüler bir şekilde bir çok özelliği içerisinde barındırması Spring'e gösterilen ilgide önemli rol oynar. Spring, birbirinden bağımsız ve ihtiyaca göre kullanımına karar verilebilecek bir çok farklı özellik içerir. Bu özellikler çatıyı oluşturan yedi farklı birim tarafından sağlanır. Bu belge bunlardan Web MVC (Model View Controller / Model Görüntüm Denetim) biriminin kullanımını örneklemek amacı ile hazırlanmış olduğu için bu birimlerin tek tek ele alınmasına yer verilmeyecektir. Spring temel olarak, bileşenleri XML yapılandırma kütükleri aracılığıyla bütünleştirmeye dayalı bir yapı sunar. Bu yaklaşım esas olarak Denetim Çevrimi (Inversion of Control), diğer bir adıyla Bağımlılık İletimi (Dependency Injection), tasarım örüntüsünü kullanır. Buna göre, bileşenler arasındaki bağımlılıklar bileşenlerin kendileri yerine Spring tarafından ele alınır. Spring bileşenleri bir araya getirmek ve biçimlendirmek için Java çekirdeklerini (JavaBean) kullanır. Sınıfları kodlanan bu çekirdeklere dair isimlendirmelerin yapılması, gerekli ilk değer atamaları ve diğer çekirdeklerle aralarındaki bağımlılıkların tanımlanması XML yapılandırma kütüklerinin içerisinde yapılır. Spring, bu kütükleri okur ve buradaki tanımları kullanarak çekirdek olgularını gerekli yapılandırmaları gerçekleştirerek oluşturur. Bu işleyiş sayesinde uygulamadaki bileşenlerin yapılandırılması ve kullanımı kodun içine girmeye gerek kalmadan, yapılandırma kütükleri aracılığıyla son derece esnek ve kolay bir biçimde gerçekleştirilir. İleride ele alacağımız Web MVC birimi örneklerinde bunu çok daha somut şekilde görme ve inceleme olanağı bulacağız.
Belge İçeriği Hakkında... Bu belgede yoğun bir şekilde bilgiye yer vermek yerine, Spring MVC ile başlangıç düzeyinde basit bir uygulamanın geliştirilmesi örneklenmeye çalışılacaktır. Özellikle başlangıç aşamasında kavranılmakta zorlanılabilen kavramlara ve geliştirme sürecinde ortaya çıkabilen temel sorunlara yönelik çözümlere yer verilecektir. Bu belgede anlatılanların iyi kavranılabilmesi için temel J2EE bilgisine (JSP/Servlet, JSTL, JSP EL) yeteri kadar sahip olunması gerekmektedir. Spring MVC çatısının kullanımı tamamen giriş düzeyinde ele alınmış olup, bazı noktalarda atıflar bulunsa da okuyucunun Struts vb. bir çatıyı daha önce kullanmış veya biliyor olması gereksinimi yoktur. Belge içinde verilecek olan kodların tamamı çalıştırılarak denenmiş kodlar olmalarının yanısıra, okuyucuya kolaylık olması amacıyla, tekrar tekrar verilen kaynak (java) ve yapılandırma (xml) kütüklerinin içieriklerinin sadece güncellenen kısımları değil, her her seferinde tamamı verilecektir. Son olarak, MVC'nin Spring'in bir alt bölümü olduğundan hareketle metnin içerisinde bir çok yerde Spring MVC yerine sadece Spring ifadesine yer verilecektir, bunun bir kavram kargaşasına yer açmaması için hatırda tutulmasında fayda vardır.
Spring MVC Bu bölümde Spring MVC çatısının kullanımını baştan sona adım adım ilerleyerek geliştireceğimiz bir uygulama ile örnekleyeceğiz.
Geliştirme Ortamının Hazırlanması Kurulum Örnek uygulamamızı gerçekleştirmeye uygun bir çalışma ortamı hazırlayarak başlayacağız. Spring MVC ile bir J2EE uygulaması geliştirmeye başlamak için öncelikli ihtiyaçlarımız bir Java SDK'sı ve bir Servlet Kozası (Servlet Container) 'dır. Örnek uygulamamız jdk1.5.0 Java SDK'sı ve koza olarak da Apache Tomcat 5.5.9 üzerinde çalışacaktır. Kullanılabilecek değişik araçlardan bağımsız olması için derleme, yükleme vb. amacıyla herhangi bir araç kullanmayacağız. Siz isteğinize bağlı olarak Ant gibi bir araç veya seçtiğiniz bir IDE kullanarak bu işlemleri alışagelmiş olduğunuz bir şekilde gerçekleştirebilirsiniz. Bu nedenle bu işlemlere dair ayrıntılara yer verilmeyecektir.
Yukarıdaki kısım herhangi bir J2EE uygulaması için gerekli olan ortama ilişkin ihtiyaçlardı. Spring MVC'yi kullanabilmek için www.springframework.org/download.html adresinden Spring çatısını indirmeniz gerekmektedir. Burada karşınıza iki seçenek çıkacaktır: springframework<sürüm_no>.zip springframework<sürüm_no>withdependencies.zip İlk seçenek sadece Spring çatısını içerirken, ikinci seçenekle birlikte J2EE uygulaması geliştirmek için gereken diğer bir çok arşiv de gelir. Uygulamamızda springframework1.2.5withdependencies.zip kurulumu kullanılacak. Spring çatısını indirdikten sonra istediğiniz bir yere açtığınızda kurulum tamamlanmıştır. Uygulamamızı geliştirme aşamasında gerektikçe buradan Spring MVC çatısına ilişkin arşivleri uygulamamızın içine dahil edeceğiz.
Uygulama Kılavuz Yapısının Oluşturulması Uygulamamızı geliştirmeye gerekli kılavuzları oluşturarak başlayabiliriz. Uygulamamızın adı springornek olsun, bu durumda uygulamamız için kök kılavuzun adı da springornek olmalıdır. Öncelikle bir J2EE uygulaması için standart olan WEBINF kılavuzunu ve web.xml kütüğünü oluşturmamız gereklidir. <web-app version="2.4"> Kod 2.1 springornek/WEB-INF/web.xml J2EE standardı olarak sınıflar için classes kılavuzunu ve ekleyeceğimiz kütüphaneler için lib kılavuzunu oluşturalım. Biz Java kaynak kodlarını koymak üzere WEBINF'in altında bir src kılavuzu öngörüyoruz, siz kullanacağınız araca veya isteğinize göre size uygun seçimi tercih edebilirsiniz. Son olarak JSP sayfalarımızı koymak için WEBINF/jsp kılavuzunu oluşturalım. Bu şekilde JSP sayfaları dışarıdan doğrudan erişime kapatılır ve uygulamadan fiziksel olarak sistemde bulunmayan sayfalara işaret eden adreslerin (url) yönlendirilmesi yoluyla sistemden hizmet alınabilir. Gördüğünüz gibi Spring çatısını kullanmak için herhangi bir uygulamadan farklı bir yapıya ihtiyaç duyulmuyor. Spring'in aktif olarak kullanımı için yapılması gereken tek şey ileride açıklayacağımız üzere gerekli jar arşivlerini lib kılavuzunun içerisine koymak ve XML yapılandırma kütüklerinin içeriğini düzenlemek olacak.
Başlangıç (DispatcherServlet) Spring MVC, Spring çatısı içerisinde MVC (Model View Controller / Model Görünüm Denetim) mimarisinin gerçekleştirildiği birimdir. Bilindiği gibi MVC bir uygulamada kullanıcıya sunulan görüntü (view), veri (model) ve kullanıcıdan gelen taleplere karşılık olarak veriler üzerinde işlemleri gerçekleştiren denetim (controller) bölümlerini birbirinden ayırmayı öngören bir yaklaşımdır. Bu yaklaşımın J2EE uygulamalarındaki esaslarından birisi Ön Denetimci Servlet (Front Controller Servlet)'in gelen tüm HTTP isteklerini (request) karşılaması ve bu isteği tanımlanan eşlemelere (mapping) göre değerlendirip yanıtı (response) üretecek olan işleyicilere (handler) yönlendirmesidir. Spring MVC'de Ön Denetimci (Front Controller) Servlet olarak DispatcherServlet hizmet verir. Spring MVC'de işleyicilere karşılık olarak da Controller arayüzünü (interface) uygulayan (implement) sınıflardır. Artık Spring MVC'yi uygulamamızın içine dahil etmenin zamanı geldi. Bunun için öncelikle Spring kurulumunuzun içindeki spring.jar (springframework1.2.5/dist/spring.jar) arşiv kütüğünü WEBINF/lib kılavuzunun içine kopyalayın. Spring kütüphanesini uygulamaya dahil ettiğimize göre artık Spring'e özel işlemler yapmaya başlayabiliriz. Yukarıda Spring'de Ön Denetimci olarak DispatcherServlet Servlet'inin işlev gördüğünden söz etmiştik. Bu nedenle ilk adım olarak uygulamaya gelen tüm istekleri bu Servlet'e yönlendirmeli ve böylece uygulamanın denetimini tamamen Spring'e bırakmalıyız. Bunu gerçekleştirebilmek için web.xml kütüğüne bir Servlet tanımı eklememiz gerekiyor (Kod 2.2). Görüldüğü üzere uygulamamızın adı olan springornek adı ile bir Servlet tanımı ekliyoruz ve Servlet sınıfı olarak da DispatcherServlet'i belirtiyoruz. Ayrıca htm ile sonlanan tüm url'lerin bu Servlet'e yönlendirilmesi gerektiğini belirtiyoruz. Buna göre bu uygulamaya gelen (<sunucu>/springornek ile başlayan) ve htm ile sona eren url'ler Spring'in DispatcherServlet'i tarafından değerlendirilecek ve buna isteğe buna göre cevap verilecektir.
<web-app version="2.4"> <servlet> <servlet-name>springornek <servlet-class> org.springframework.web.servlet.DispatcherServlet 1 <servlet-mapping> <servlet-name>springornek *.htm Kod 2.2 springornek/WEB-INF/web.xml Yeri gelmişken DispatcherServlet'in davranışını belirleyen tanım ve yapılandırılmaların bulunduğu XML yapılandırma kütüğüne değinelim. Spring MVC çatısı bu yapılandırma kütüğü için
servlet.xml şeklinde bir adlandırma öngörmüştür. Bu durumda bizim yapılandırma kütüğümüzün adı springornekservlet.xml olmalıdır ve bu kütüğün springornek/WEBINF/ kılavuzunun altında bulunması gerekmektedir. Bu kütüğün henüz hiç bir tanım yapılmamış haldeyken görünümü Kod 2.3'de veriliyor. Kod 2.3 springornek/WEB-INF/springornek-servlet.xml İleride gerekli tüm tanımlamaları beans etiketleri arasına ekleyeceğimiz bean etiketleri ile bu kütükte yapacağız.
İlk Spring MVC Örneği Spring MVC kullanarak hazırlayacağımız bir sayfa için temel olarak iki kütüğe ihtiyacımız vardır. Bir görünüm (view) ve bir denetimci (controller). Spring MVC birden fazla görünüm teknolojisine destek vermektedir (JSP/JSTL, Tiles, Velocity, FreeMaker vs.). Bizim uygulamamızdaki tüm görünümler JSP (ve JSTL) ile oluşturulacaktır. Bu nedenle görünüm kelimesinin geçtiği noktalarda bir JSP sayfasından bahsediyor olacağız. Denetimciler (controller) daha önce söz edildiği üzere bir HTTP isteğini (request) değerlendiren ve buna göre bir yanıt (response) üretip, bu sonuca uygun bir sayfaya yönlendirme işini yapan sınıflardır. Spring MVC, isteklerin türüne göre en uygun ve en kolay kodlamayı sağlayabilmek için farklı denetim sınıfları içermektedir. Yani örneğin sadece metin ve bir takım bağlantılardan (link) oluşan bir sayfa için farklı, bir submit olayı sonucu üretilen ve form verisi taşıyan bir istek için farklı ve daha uygun bir sınıftan türetilen denetimciler kullanılabilir. Denetimci sınıfların en üst düzeydeki atası Controller arayüzüdür. Struts kullanmış olanlar için bunun Action'a karşılık geldiğini söyleyebiliriz. public interface Controller { ModelAndView handleRequest( HttpServletRequest request, HttpServletResponse response) throws Exception; } Kod 2.4 org.springframework.web.servlet.mvc.Controller Kod 2.4'te Controller sınıfının koduna yer verilmiştir. Controller arayüzü handleRequest()adlı yönetimi
sağlar. Bu arayüzü uygulayan sınıflarda bu yöntemin içerisinde istek (request) için yerine getirilmesi gerekenler kodlanır ve bu yöntem geriye bir org.springframework.web.servlet.ModelAndView nesnesi döndürülür. Bu nesne sınıf adından da anlaşıldığı gibi yanıt için gerekli olan veriyi (model) de görünümü (view) de taşır. Bunların bir arada gönderilmesinin sebebi kullanıcıya gösterilecek görünüme aynı zamanda sunacağı veriyi de sağlanmasıdır. Örneğin bir JSP sayfasının kullanıcının seçimi için listeleyeceği seçeneklerle ilgili veriye erişmesi gerekir (örneğin request nesnesi üzerinden). Bu nesnenin (ModelAndView nesnesi) oluşturulması ve kullanımını uygulamamızın içinde örnekleyeceğiz.
RequestUtils org.springframework.web.bind.RequestUtils sınıfı, HttpServletRequest bir nesnesinin parametrelerine parametrenin türünü belirterek erişim sağlayan static yöntemler içerir. Parametrelere HttpServletRequest nesnesinin üzerinden doğrudan erişmek yerine bu sınıfı kullanmak tavsiye edilen bir yöntemdir. Örnekler: String str = RequestUtils.getStringParameter(request, "string_param"); int i = RequestUtils.getIntParameter(request, "int_param", 0); Integer i = RequestUtils.getIntParameter(request, "integer_param");
Şu ana kadar açıkladıklarımıza dayanarak bir isteğin hangi aşamalardan geçerek bir yanıta dönüştüğünü sıralarsak, istek ilk önce DispatcherServlet tarafından ele alınır, bu Servlet ileride açıklayacağımız eşleme (mapping) yapılandırmasını kullanarak isteği bir denetimciye yönlendirir. Denetimci isteğe dair yapılması gereken işlemleri gerçekleştirdikten sonra bir ModelAndView nesnesi döndürür. Bu nesne hangi hangi sayfanın gösterileceği bilgisinin yanı sıra sunulacak veriye de sahiptir ve bunlardan üretilen bir yanıt (response) kullanıcıya döndürülür. Denetimciler ve diğer ayrıntılara girmeden önce artık “Merhaba Dünya!” mesajını gösteren bir ana sayfa yapmaya geçmeliyiz. Öncelikle sitenin girişi niteliğide olan bir index.jsp hazırlamalıyız. Bir J2EE web uygulamasında sitenin açılış sayfası (ana sayfası) web.xml kütüğüne welcomefile etiketi içerisnde verilir ve burada verilen sayfanın açılışta görüntülenmesi için kullanıcıların erişimine açık fiziksel bir kütüğe işaret ediyor olması gerekir. Bu nedenle index.jsp sayfasını WEB INF/jsp kılavuzuna değil doğrudan uygulamanın kök kılavuzuna koymalıyız (springornek/index.jsp). <web-app version="2.4"> <servlet> <servlet-name>springornek <servlet-class> org.springframework.web.servlet.DispatcherServlet 1 <servlet-mapping> <servlet-name>springornek *.htm <welcome-file-list> <welcome-file>index.jsp Kod 2.5 springornek/WEB-INF/web.xml Kod 2.5'te görüldüğü gibi web.xml kütüğünü günledikten sonra, Kod 2.6'daki index.jsp sayfasını kaydedip uygulamayı çalıştırdığınızda karşınıza “Merhaba Dünya!” yazan bir sayfa çıkması gerekir. Ancak daha önce söz ettiğimiz gibi JSP'lerimizin kullanıcıların doğrudan erişimine açık olmasını istemiyoruz ve ana sayfada da dahil tüm görünümlerin Spring tarafından arka planda oluşturulmasını ve kullanıcılara sadece sanal url'lerden (.htm uzantılı) haberdar olmasını istiyoruz. Ancak dışarıdan erişilebilir bir index.jsp'den vazgeçemeyeceğimize göre bu durumda çözüm index.jsp'nin hiç bir bilgi ya da görüntü içermeyip, isteği (request) başka bir sayfaya yönlendirmesidir (Kod 2.7).
Kod 2.6 springornek/index.jsp <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> Kod 2.7 springornek/index.jsp Artık index.jsp kendisine gelen istekleri springornek/index.htm adresine yönlendiriyor. Peki bu adres karşılığında ne yapılacak? Hangi sayfa görüntülenecek? Burada devreye Spring'in sağladığı Görünüm Çözlümleyici (View Resolver) ve İşleyici Eşleme (Handler Mapping) sınıfları giriyor. Daha önce denetimci (Controller) sınıfların gerekli işlemleri yerine getirdikten sonra bir ModelAndView nesnesi döndürdüğünden söz etmiştik. Spring'de görünümler (view) biricik String'ler ile ifade edilebilirler. Görünüm çözümleyiciler (view resolver) bu String'lere göre doğru görünümleri tespit edip yönlendirmelerin yapılmasını sağlarlar. Daha önce söylediğimiz gibi Spring birden fazla görünüm teknolojisini destekler ve bu nedenle çeşitli görünüm çözümleme sınıfları sunar. JSP teknolojisi kullanılıyorsa uygun olan görünüm çözümleme sınıfı org.springframework.web.servlet.view.UrlBasedViewResolver'dır. Bizim uygulamamızda olduğu gibi eğer JSP ve JSTL teknolojileri bir arada kullanılacaksa en uygun çözüm org.springframework.web.servlet.view.InternalResourceViewResolver sınıfını kullanmaktır. Görünüm çözümleyici sınıfın DispatcherServlet tarafından nesnesinin oluşturulup görünüm çözümlemede kullanılabilmesi için springornekservlet.xml yapılandırma kütüğüne bu sınıfa dair çekirdek (bean) tanımını ve ilk değerlerini vermemiz gerekir (Kod 2.8). <property name="viewClass"> org.springframework.web.servlet.view.JstlView <property name="prefix">/WEB-INF/jsp/ <property name="suffix">.jsp Kod 2.8 springornek/WEB-INF/springornek-servlet.xml Uygulama başlatıldığında yapılandırma kütüğüne eklediğimiz bu çekirdeğin nesnesi oluşturulur. Burada verilen ilk değerlere göre bir görünümü (view) ifade etmek için kullanılan String'in başına /WEBINF/jsp/ öneki (prefix) ve sonuna .jsp soneki (suffix) getirilerek görünüme dair gerçek adrese ulaşılabilir. Buna göre örneğin bir ModelAndView nesnesi oluştururken belirtilen önek ve sonekleri yazma zahmetine katlanmadan görünüm belirlenebilir. Örneğin /WEB INF/jsp/hello.jsp görünümüne sadece hello anahtarıyla erişilebilir. Ancak henüz sorduğumuz soruların cevabını bulamadık. Yani /springornek/index.htm adresinin nereyi gösterdiği kısmı henüz belirsizliğini koruyor. Öncelikle bu adrese karşılık gelen, bu isteği karşılayan bir görünümümüz ve bir denetimcimizin bulunması gerekir. Bu amaçla kısa bir mesaj içeren küçük bir sayfa yapalım. Bu küçük örnek için doğrudan Controller arayüzünü uygulayan bir sınıfımızın bulunması yeterli olacaktır. Denetimci sınıflar için
denetim adlı bir paket (package) oluşturalım ve burada ilk denetimcimizi oluşturalım. package denetim; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; public class BasitDenetimci implements Controller { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { return new ModelAndView("basit"); }
} Kod 2.9 springornek/WEB-INF/src/denetim/BasitDenetimci.java
Kod 2.9'da verilen BasitDenetimci sınıfı isteği (request) bir görünüme yönlendirmek dışında bir işlem yapmıyor. ModelAndView nesnesi oluşturulurken yapılandırıcısına sadece görünüm ismi veriliyor. Daha önce tanımladığımız görünüm çözümleyici (view resolver) “basit” adıyla tanımladığımız görünüme karşılık springornek/WEB INF/jsp/basit.jsp sayfasını getirecektir ve DispatcherServlet tarafından istek bu sayfaya yönlendirilecektir. Sayfa herhangi bir veriye ihtiyaç duymayacağı için ModelAndView nesnesi herhangi bir veri (model) eklemeden oluşturulup döndürülmektedir. Yazdığımız denetimci sınıfın DispatcherServlet tarafında tanınıp gerekli yönlendirmelerde kullanılabilmesi için onu yapılandırma kütüğüne eklememiz gerekmektedir (Kod 2.10). <property name="viewClass"> org.springframework.web.servlet.view.JstlView <property name="prefix">/WEB-INF/jsp/ <property name="suffix">.jsp Kod 2.10 springornek/WEB-INF/springornek-servlet.xml Bu tanımın eklenmesiyle birlikte uygulama çalıştırıldığında, BasitDenetimci sınıfının bir olgusu basitDenetimci adıyla Spring tarafından oluşturulacaktır. Bu nesne aynı zamanda gerektiğinde (örneğin yönlendirmelerin tanımlanmasında) bu adla çekirdek (bean) diğer tanımlamalarında da kullanılabilecktir. Oluşturacağımız sayfanın görünümünü oluşturan basit.jsp Kod 2.11'de verilmiştir. Şu anda basit bir mesaj sayfasını görüntülemek için gerekli her şey hazır durumda. Ancak tek eksik DispatcherServlet'in springornek/index.htm adresini BasitDenetimci denetimcisine yönlendirmesi. Bunun için Spring'in daha önce söz konusu ettiğimiz İşleyici Eşleme (Handler Mapping) işlevini kullanmalıyız.
Örnek Spring MVC uygulaması. Kod 2.11 springornek/WEB-INF/jsp/basit.jsp Spring MVC görünüm çözümleme konusunda olduğu gibi işleyici eşleme konusunda da çeşitli sınıflar sunar. Bu sınıfların çekirdek tanımlarına yapılandırma kütüğünde yer verilerek ve burada gerekli eşleştirmeler yapılarak uygulamada hangi url'nin hangi denetimci tarafından değerlendirileceğini belirlenir. Yani bir anlamda uygulamada kullanılan adreslerin tamamen soyut olması, başka bir deyişle fiziksel bir kütüğe işaret etmesine gerek kalmaması sağlanır. Bu işlevin getirdiği avantajlardan birisi de adresleri belirlemede uzantı vs. kısıtlamalarının bulunmamasıdır. Bizim uygulamamızdaki url'ler .htm uzantısı ile sonlanacaktır. Ancak bu bir tercihten öteye geçmemektedir örneğin istenirse hiç bir uzantı da kullanılmayabilir. Biz, uygulamamızda işleyici eşleme amacıyla org.springframework.web.servlet.handler paketindeki SimpleUrlHandlerMapping sınıfını kullanacağız. Bu sınıf, tanımlamalarda Ant stili (örneğin *, ** gibi sembollerle toplu olarak eşleştirmelere olanak verir) ifadelere izin veren ve güçlü özellikleri olan bir eşleme sınıfıdır. Başlangıç sayfası olarak yönlendirilen index.htm adresinin BasitDenetimci tarafından ele alınacağını ifade eden eşlemeyi Kod 2.12'deki gibi tanımlayabiliriz. <property name="mappings"> <props> <prop key="/index.htm">basitDenetimci <property name="viewClass"> org.springframework.web.servlet.view.JstlView <property name="prefix">/WEB-INF/jsp/ <property name="suffix">.jsp Kod 2.12 springornek/WEB-INF/springornek-servlet.xml SimpleUrlHandlerMapping türünde urlEsleme adında çekirdek oluşturuluyor. Bu çekirdeğin mappings adlı niteliğinin içine tüm eşlemelere yer verilir. Yeni bir eşleme ekleyeceğimizde yeni bir prop etiketi eklememiz yeterli olacaktır.
Şu anda çalışabilir bir örneği elde etmiş surumdayız. Uygulamanın başlangıç sayfası index.jsp, index.htm adresine yönlendirme yapar, bu adresin basitDenetimci denetimcisi tarafından ele alınacağına karar verilir, son olarak denetimci basit görünümüne (springormek/WEBINF/jsp/basit.jsp) yönlendirir ve bu sayfanın içeriğini tarayıcıda Resim 2.1'deli gibi görürüz.
Resim 2.1 Başlangıç Sayfası ModelAndView nesnesinin veri (model) kısmı bir harita mantığı ile çalışır. BasitDenetimci'yi biraz değiştirerek görünüme bilgi göndermesini sağlayalım (Kod 2.13). ModelAndView'e iki biçimde veri ekleyebildiğimizi görüyoruz. Bunlardan ilki ModelAndView nesnesinin yapılandırıcısına görünümün ardından anahtar kelime (bir String) ve veriyi (bir Object) parametre olarak vermektir. İkincisi ise benzer şekilde addObject yöntemini kullanmaktır. Bu yöntem kullanılarak ModelAndView nesnesine istenildiği kadar veri eklenilebilir. package denetim; import java.util.Date; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; public class BasitDenetimci implements Controller { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView mav = new ModelAndView( "basit", "mesaj", "Bu String türündeki mesaj verisi!"); mav.addObject("birSayi", new Integer(555)); mav.addObject("tarih", new Date()); return mav; }
} Kod 2.13 springornek/WEB-INF/src/denetim/BasitDenetimci.java
Bu durumda görünümü de gönderilen verileri görüntülemek amacıyla biraz değiştirmemiz gerekiyor (Kod 2.14). Görünüm içinden bu verilere istek (request) nitelikleri olarak erişilebilir. Niteliğe erişmek için ModelAndView nesnesine veriyi koyarken kullandığımız anahtar kelimeyi kullanabiliriz. Örneklerimizde JSP EL söz dizimini (syntax) kullanacağız ve örneğin “mesaj” anahtar kelimesini kullandığımız String türü veriye sayfanın herhangi bir yerinde ${mesaj} şeklinde erişebiliriz. Son değişikliklerden sonra uygulama çalıştırıldığında Resim 2.2'deki görüntü elde edilir. <%@ page contentType="text/html; charset=ISO-8859-9" %> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-9"> springornek
Hoşgeldiniz!
Örnek Spring MVC uygulaması.
<em><strong>Veriler:
Mesaj: <em>${mesaj} Bir sayı: <em>${birSayi} Tarih: <em>${tarih} Kod 2.14 springornek/WEB-INF/jsp/basit.jsp
Resim 2.2 Denetmicinin Gönderdiği Veriye Erişim
Uygulamaya Başlıyoruz Artık Spring MVC kullanarak basit web uygulaması geliştirmek için temel altyapımız hazır durumda olduğuna göre kendi uygulamamızı inşa etmeye başlayabiliriz. Bu esnada Spring'in form içeren sayfalarda form verilerinin kontrolünü kolaylaştıran, kullanıcı tarafından girilen verileri doğrulama (validation) işlemini uygulama kodundan ayıran ve yalınlaştıran, istek denetimciye ulaşmadan önce ve sonra yapılması gereken işlemlerin gerçekleştirilmesine olanak veren bir yapı (interceptors) sağlayan çeşitli işlevlerini inceleyeceğiz. Bunlar gibi bir çok işleve değinecek olmamıza rağmen takip etmeyi kolaylaştırmak ve karışıklığa sebep olmamak için olabildiğince az sayıda sayfaya yer vereceğiz. Uygulamamız, bir otoparka giriş yapan araçlara otopark gişesinde boş olan bir park yerinin verilmesi (sıradaki yer veya seçilen boş bir yer) ve park yeri verilen aracın plakasının ve park yerinin kaydedilmesi işlemlerini içerecektir. Önce
sayfaları hazırlarken kullanacağımız, araçlara ve otoparka dair verileri tutan ve bunlara erişim sağlayan iş mantığı sınıflarını kodlayarak başlayalım (Kod 2.15, 2.16) ve bu sınıfları ismantigi adlı bir paketin içerisinde toplayalım. package ismantigi; public class Arac { //plaka alanları int ilKodu; String harfKodu; int aracNo;
}
public int getAracNo() { return aracNo; } public void setAracNo(int aracNo) { this.aracNo = aracNo; } public String getHarfKodu() { return harfKodu; } public void setHarfKodu(String harfKodu) { this.harfKodu = harfKodu; } public int getIlKodu() { return ilKodu; } public void setIlKodu(int ilKodu) { this.ilKodu = ilKodu; } Kod 2.15 springornek/WEB-INF/src/ismantigi/Arac.java
package ismantigi; public class Otopark { public final static int ARAC_SAYISI = 10; private static Arac[] araclar = new Arac[ARAC_SAYISI]; private static int ilkBosYer = 0; static { for(int i = 0; i < ARAC_SAYISI; ++i) araclar[i] = null; } public static void aracParket(Arac arac, int parkYeri) { araclar[parkYeri] = arac; if(ilkBosYer == parkYeri) { int gecici = ilkBosYer; do { ilkBosYer = (ilkBosYer + 1) % ARAC_SAYISI; if(ilkBosYer == gecici) { //Boş yer yok ilkBosYer = -1; break; } } while(araclar[ilkBosYer] != null);//dolu Mu? } }
public static boolean doluMu(int parkYeri) { return araclar[parkYeri] != null; } public static boolean doluMu() { return ilkBosYer == -1; } public static Arac[] getAraclar() { return araclar; } public static int getIlkBosYer() { return ilkBosYer; } } Kod 2.16 springornek/WEB-INF/src/ismantigi/Otopark.java Arac sınıfı sadece aracın plakasını tutmaktadır. Plakanın alt alanlarını(il kodu, harf kodu ve araç no) ayrı ayrı tutarak girdi denetiminin daha kolay yapılmasını amaçlıyoruz. Uygulamamızda kaynak kodları karmaşıklaştırıp, şişireceği ve okuyucunun uygulamayı çalıştırmasını zorlaştıracağı için bir veri tabanı kullanmayacağız. Otopark sınıfını bunun boşluğunu doldurabilmek için ekliyoruz. Bu sınıfta park yerlerini ve buralara park eden araçları tutmak için bir Arac dizisi kullanıyoruz ve araçların park yerlerinin dizideki tutuldukları dizinleri olmasını öngörüyoruz. Bu durumda boş olan park yerlerine ilişkin dizinlerin değeri hiç bir araç bulunmadığına işaret edecek biçimde null olmaktadır. Bu sınıfta ilkBosYer adlı alan da anlaşılacağı üzere otoparkta boş durumda olan ilk noktayı göstermektedir. Uygulamamızda kullanıcı isterse bundan daha farklı boş bir yeri seçebileceğinden dolayı aracParket yönteminin içerisinde bu değişken sadece bir arttırılmak yerine otoparktaki ilk boş yerin bulunup bu değerin atanması işlemi gerçekleştiriliyor. Eğer otoparkta boş yer kalmamışsa bunu belirtmek için ilkBosYer değişkeninin değeri 1 yapılıyor.
Ana Sayfa Uygulamamız için ilk olarak bir ana sayfa yapalım. Bunu gerçekleştirmek için başlangıç amaçlı yazdığımız denetimci sınıf ve JSP sayfasına benzer şekilde yeni bir denetimci ve bir JSP sayfası ekleyebiliriz. Ana sayfada hangi park yerinde hangi aracın bulunduğunu listeleyebiliriz ve yeni araç girişinin yapabileceği sayfaya yönlendiren bir bağlantıya yer vermemiz gerekir. Amacımızı gerçekleştirebilmemiz için JSP sayfasının araçlar ve park yerleri bilgisine ihtiyacı vardır, bu nedenle denetimci sınıfın döndürdüğü ModelAndView nesnesinin içine bu bilgiyi eklemesi gerekir (Kod 2.17). package denetim; import ismantigi.Otopark; import import import import
public class AnasayfaDenetimci implements Controller { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
}
ModelAndView mav = new ModelAndView("anasayfa"); mav.addObject("araclar", Otopark.getAraclar()); return mav;
} Kod 2.17 springornek/WEB-INF/src/denetim/AnasayfaDenetimci.java
Denetimci sınıfı (AnasayfaDenetimci), denetim paketinin içine koyuyoruz. Bu sınıf, daha önce verileri tutmak için kullanacağımızı belirttiğimiz Otopark sınıfının araçları ve park yerlerini tuttuğu diziyi, geri döndürdüğü ModelAndView nesnesine ekliyor. Bu sınıfa ilişkin eklememiz gereken diğer bir nokta da görünümün (view) springornek/WEBINF/jsp/anasayfa.jsp olarak belirtilmiş olmasıdır. Bu durumda, anas ayfa olarak kullanacağımız JSP sayfasının adının anasayfa.jsp olması gerekiyor. Uygulamaya eklediğimiz yeni denetimciyi kullanabilmek için XML yapılandırma kütüğümüz olan springornek servlet.xml içinde tanımlamamız gerekiyor (Kod 2.18). <property name="mappings"> <props> <prop key="/index.htm">anasayfaDenetimci <prop key="/basit.htm">basitDenetimci <property name="viewClass"> org.springframework.web.servlet.view.JstlView <property name="prefix">/WEB-INF/jsp/ <property name="suffix">.jsp Kod 2.18 springornek/WEB-INF/springornek-servlet.xml Görüldüğü gibi artık index.htm adresi yeni yazacağımız ana sayfayı görüntülemek üzere anasayfaDenetimci'ye yönlendirilecek. Kod 2.19'da anasayfa.jsp'ye yer veriliyor. Bu sayfada AnasayfaDenetimci'nin araclar anahtarı ile ModelAndView nesnesine eklediği araç dizisini JSTL etiketleri ve JSP EL sözdizim kurallarını kullanarak erişiliyor. Bir döngüyle kılavuzun tüm elemanları geziliyor ve tüm park yeri numaralarına karşılık orada bulunan aracın plakası listeleniyor, eğer araç bilgisi null değerine sahipse ilgili park yeri numarasına karşılık Boş ifadesi kullanılıyor. Bu şekilde park numaralarının kullanımda olma durumu kullanıcı tarafından takibi kolaylaştırılıyor. Araç listesinin altında ise yeni bir araç kaydının yapılabilmesine yönelik bir bağlantıya yer veriliyor. Bu bağlantının adresi olan aracgiris.htm'yi daha ileride gerçekleştireceğiz. Şu anda araç ekleme sayfası aktif durumda olmadığı için tüm park yerleri boş (null) durumda bulunuyor (Resim 2.3). <%@ page contentType="text/html; charset=ISO-8859-9" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-9"> springornek
Spring MVC - Otopark Uygulaması
Araçlar
${i}.
${arac.ilKodu} ${arac.harfKodu} ${arac.aracNo}
<em>Boş
">Araç Girişi Kod 2.19 springornek/WEB-INF/jsp/anasayfa.jsp
Resim 2.3 Ana Sayfa
Form Kullanımı Daha önce Spring MVC'nin farklı ihtiyaçlara cevap verebilecek nitelikte farklı denetimci sınıf seçenekleri sunduğundan bahsetmiştik ve özellikle formlar içeren sayfalarda form verilerinin denetimi, değerlendirilmesi ve kullanılması konusunda kolaylıklar getiren form denetimci sınıfları vurgulamıştık. Uygulamamızda bunlardan çok kullanışlı olan ve tüm ihtiyaçlarımıza cevap veren org.springframework.web.servlet.mvc.SimpleFormController sınıfını kullanacağız. Örnekler üzerinde inceleyince daha iyi anlaşılacabilecek olmasına rağmen biraz daha derli toplu biçimde faydalı olabileceği için aşağıda bu sınıfın kullanımı için önemli olan bazı noktalar hakkında özet bilgi verilmektedir. SimpleFormController sınıfı formView ve successView adlı iki nitelik içerir. Bunlara genellikle XML
yapılandırma kütüğündeki denetimci tanımının içerisinde ilk değer ataması yapılır. Bu niteliklerden ilki denetimci tarafından denetlenecek olan formu içeren sayfaya ilişkin görünümün adıdır. Yani denetimciye yönelik bir istek geldiği zaman doğrudan, kullanılacak olan formu içeren bu görünüm görüntülenir . İkinci nitelik ise form işlemleri başarılı bir şekilde sonuçlanırsa yönlendirilecek olan görünümü belirlemek üzere öngörülmüştür. Bu görünüm formView niteliği örneğinde olduğu gibi otomatik olarak görüntülenmez, ancak geliştirici isterse bu nitelikle belirlenen görünüme yönlendirme yapar (ModelAndView ile kullanarak). Aslında successView niteliğinin kullanımının tercih edilmesinin nedeni değer atamasın XML içerisinde yapılabilmesi ve böylece gidilecek görünümün adının kodun içine gömülmesine gerek kalmamasıdır. SimpleFormController'ın XML içinde ilklendirilebilen çok önemli iki niteliği daha vardır; commandName ve commandClass. Bunları belirtmeden önce Spring MVC'deki komut (command) sınıflarının açıklanması gerekiyor. Spring MVC, bir formda kullanıcının girdiği verilerin doğrudan bir Java nesnesinin (komut nesnesi) nitelikleri ile ilişkilendirilmesine (bağlama / bind) sağladığı bir takım etiketler (tag) aracılığıyla izin verir ve bu sayede ilgili form alanının içeriği nesnenin niteliğinin değeri olarak kaydedilir. Komut nesneleri adı verilen bu nesnelerin kullanımı, form verilerinin istek (request) nesnesinden çıkartılıp başka bir Java nesnesine kaydedilmesi işini geliştiricinin yükümlülüğünden tamamen çıkartan çok pratik bir işlevdir. Ayrıca bu nesneler çeşitli amaçlara yönelik (örneğin verileri doğrulama (validation)) işlevlerde de Spring'in sağladığı yöntemler sayesinde doğrudan kullanılabilirler ve bu yapı geliştiriciye çok önemli kolaylıklar sağlar. Sözünü ettiğimiz commandName ve commandClass nitelikleri de form tarafından kullanılacak olan komut (command) nesnesinin adı ve sınıfıdır. Bu niteliklere genellikle yapılandırma kütüğünde ilk değer atamaları yapılır. Eğer commandName niteliğine burada yer verilmezse komut nesnesinin adı varsayılan olarak command olur ve nesneye görünümün içerisinden isimle erişim sağlanır. Komut nesnesinin sınıfını belirten commandClass niteliği yapılandırma kütüğünde belirlenmişse ihtiyaç olduğunda otomatik olarak bu sınıftan boş bir nesne oluşturulur ve kullanılır, buna alternatif bir çözüm ise denetimci sınıf içerisinde daha sonra açıklanacak olan formBackingObject yöntemininin yeniden yazılmasıdır(override). Komut nesnesi ile ilgili olarak vurgulanması gereken diğer önemli bir nokta değerinin null olmasına izin verilmemesidir. SimpleFormController sınıfı isteğin (request) değerlendirilip yönlendirilmesi sürecinin farklı noktalarında otomatik olarak çağrılan ve genellikle bu sınıftan türetilen denetimci sınıflar tarafından yeniden yazılan (override) yöntemler içerir. Bunlardan önemli olan bazılarını kısaca özetleyelim: •
Object formBackingObject(HttpServletRequest); Formun komut nesnesinin yapılandırma kütüğünde commandClass niteliği ile belirlenmesi durumunda bu sınıfın varsayılan yapılandırıcısı (default constructor) kullanılarak bir olgusunun oluşturularak formda kullanıldığını söylemiştik. Bu nitelik belirtilmiş olsun veya olmasın denetimci sınıfın içinde formBackingObject yönteminin yeniden yazılması durumunda bu yöntemin döndürdüğü nesne komut nesnesi olarak kullanılır. Bu sayede, komut nesnesine bir takım ilk değerler vermek suretiyle (örneğin veri tabanından gerekli veriler çekilerek) bu verilerin formların ilişkilendirildikleri (bağlandıkları) alanlarında varsayılan olarak görüntülenmesi sağlanabilir. Burada dikkat edilmesi gereken, yöntemin geriye null değer döndürmemesi şartıdır, aksi durumda bir çalışma zamanı hatası ortaya çıkar. Anlaşılacağı üzere bu daha form görünümü görüntülenmeden önce çağrılan bir yöntemdir.
•
Map referenceData(HttpServletRequest); Bu yöntem komut nesnesinin içinde taşınması gereksiz olan verilerin görünüme iletilmesi amacıyla kullanılır. Yani formla ilgisiz olan ama görünüm tarafından (görüntülenmek amacıyla) kullanılacak olan verilerin iletilmesini sağlar. Doğrudan Controller'dan türetilen denetimcilerin handleRequest yönteminde ModelAndView nesnesine verileri eklemesine benzetilebilir. Yöntemin döndürdüğü Map nesnesindeki tüm veriler yine bu nesnedeki anahtar sözcükleri kullanılarak görünüme (formView) geçirilirler. Yine anlaşılacağı üzere form görünümü görüntülenmeden önce çağrılan bir yöntemdir.
•
ModelAndView onSubmit(HttpServletRequest,HttpServletResponse,Object,BindException); Bu yöntem yeniden yazılması olmazsa olmazlardan biridir ve formdan bir submit isteği geldiğinde yapılması gerekenleri gerçekleştirildiği ve işlem sonucunda gidilmesi gereken sayfaya yönlendirmenin yine döndürülen ModelAndView nesnesi sayesinde yapıldığı yöntemdir. Form işlemlerinin tamamen sonuçlandığı yöntem olduğu söylenilebilir.
Bir form denetimci tarafından formun ele alınmasına ilişkin akışla ve sağlanan diğer yöntemlerle ilgili detaylı açıklamaları Spring kurulumunuzun docs/api kılavuzunun altında bulunan javadoc belgelerinde bulabilirsiniz. Bunun yanısıra, bu belgeleri geliştirme sırasında önemli bir başvuru kaynağı olarak kullanabilirsiniz.
Araç Girişi Yeni bir aracın otoparka girişinin gerçekleştirildiği sayfa aracın plakasına ilişkin üç alanın girilmesine ve uygun bir park yerinin seçilmesine olanak veren bir form içermelidir. İşlem gerçekleştirildikten sonra, verilerde bir hata yoksa, listenin son durumunu görmek üzere tekrar ana sayfaya dönülmesini öngörüyoruz. Bir form denetimcisi yazmadan önce komut sınıfını yazalım. Bu arada komut sınıfları için komut adlı bir paket oluşturduğumuza dikkat edin (Kod 2.20). Form üzerinde araca dair bilgilerle (örneğimizde sadece plaka alanları) aracın otoparkta hangi park yerine park edildiğine dair bilgiler girileceği için komut sınıfımızda (AracGirisi) bir Arac nesnesi ve park yeri için bir tam sayı bulunuyor. Tabi bu sınıfın komut sınıfı olarak kullanılabilmesi için niteliklerine okuma ve yazma izni veren JavaBean tanımına uygun erişim yöntemleri (set/get) gerçekleştirilmelidir. package komut; import ismantigi.Arac; public class AracGirisi { Arac arac; int parkYeri; public Arac getArac() { return arac; } public void setArac(Arac arac) { this.arac = arac; } public int getParkYeri() { return parkYeri; } public void setParkYeri(int parkYeri) { this.parkYeri = parkYeri; } } Kod 2.20 springornek/WEB-INF/src/komut/AracGirisi.java Kod 2.21'de araç girişi sayfasını ele almakta kullanacağımız AracGirisFormDenetimci sınıfına yer verilmiştir. Bu sınıfta daha önce sözünü ettiğimiz üç yönteme de yer verildiğini görüyoruz. package denetim; import ismantigi.Otopark; import komut.AracGirisi; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import import import import
} Kod 2.21 springornek/WEB-INF/src/denetim/AracGirisFormDenetimci.java
Bu yöntemlerden formBackingObject yöntemi komut sınıfı olan AracGirisi sınıfının nesnesini oluşturduktan sonra ilk değer atamaları yapmak amacıyla gerçekleştirilmiştir. Oluşturulan yeni AracGirisi nesnesinin parkYeri niteliğinin değeri Otopark sınıfının ilkBosYer niteliğinin değeri ile kurulmaktadır. Böylece JSP sayfasında varsayılan olarak bu değerin kullanıcıya sunulması sağlanacaktır ve kullanıcı isterse sadece plaka alanlarını doldurmakla yetinecek ve uygun park yeri seçimi yapmasına gerek kalmayacaktır. Yeniden yazılan diğer bir yöntem olan referenceData yöntemi ise form görünümünün ihtiyacı olan araç park yerleri verisinin gönderilmesi amacı gütmektedir. Görünüme yine Otopark sınıfında tutulan araç dizisi gönderilmektedir. Bu bilgi görünüm tarafından, kullanıcıya kolaylık sağlamak amacıyla, park yerlerini bunlardan dolu veye boş olanları ayırt edilebilecek biçimde farklı renklerde sunmak amacıyla kullanılacaktır. Son olarak onSubmit yöntemi form üzerinde ilgili düğmenin tıklanarak araç girişi olayının tetiklenmesi ile çağrılır. Bu yönteme gelen argümanlardan birinin Object türündeki command nesnesi olduğunu görüyoruz. Bu nesne, formda kullanılan komut nesnesidir ve ileride JSP sayfasını incelerken göreceğimiz üzere forma girilen verilerle araç ve park yeri niteliklerinin değerleri kurulmuş olarak bu yönteme gelir. Komut nesnesi Otopark sınıfının araç girişini kaydetmek amacıyla kullanılan aracParket yönteminin ihtiyacı olan araç ve park yeri verilerini sağlar. Gerçek bir uygulamada bunun yerine örneğin bir veri tabanı güncellemesi yapılabilirdi. Geri döndürülen ModelAndView nesnesine herhangi bir veri eklenmezken, bu nesnedeki görünümün successView niteliği ile belirlendiği görülüyor, bu niteliğin değeri daha önce söz edildiği gibi yapılandırma kütüğünde kurulması öngörülmektedir. SimpleFormController'dan türeyen sınıflar için bile bu niteliğe doğrudan erişim izni olmadığı için getSuccessView yöntemi kullanılmaktadır.
RedirectView Kod 2.21'de görünümün doğrudan görünüm adı ile belirtilmesi yerine görünüm adı ile oluşturulan bir RedirectView nesnesinin kullanıldığını görüyoruz. İlk kullanımda (görünüm adı kullanımı) isteğin (request) kontrolü aynen başka bir noktaya yönlendirilir veya devredilir (forward). Bu durumda eğer post yöntemini kullanan bir form bu şekilde yönlendirilmişse kullanıcı sayfayı her yenilediğinde aynı istek tekrar işletilir. Daha açık bir ifade ile kullanıcı ekranında artık form değil örneğin işlem sonucunu yansıtan bir sayfa vardır, ancak kullanıcı sayfayı yenilediği zaman üretilen istek form tarafından oluşturulan isteğin aynısıdır ve bu genellikle istenmeyen bir şekilde bir kez gerçekleştirilmesi gereken bir işlemin tekrar edilmesine neden olur. Kritik bir uygulamada bu önemli sakıncaları olabilir. Yeniden yönlendirme (redirect) yaklaşımının kullanılması ile yönlendirilen sayfaya gidilirken belirtilen url'ye tamamen yeni bir istek oluşturularak yönlendirme gerçekleşir. Yani form tarafından üretilen istekten tamamen bağımsız yeni bir istek oluşturularak yeni sayfaya gidilir. Bu kullanımda dikkat edilmesi
gereken nokta yönlendirme bir görünüm adı ile değil görünüme ilişkin adres ile yapılır ve successView niteliğinin değerinin bu göz önüne alınarak belirlenmesi gerekir.
Sonuç olarak, yapılandırma kütüğünde AracGirisFormDenetimci için eklenilen tanımlamaları Kod 2.22'de görebilirsiniz. İlk olarak aracGirisFormDenetimci adıyla tanımladığımız denetimciyi url eşleme kısmında aracgiris.htm adresi ile eşleştirildiğini vurgulayalım (ana sayfanın en altında bulunan bağlantıyı hatırlayın!). Bu denetimci tanımının içinde komut nesnesinin adının aracGiris olduğu ve bunun AracGirisi türünde olduğu görülüyor. Ayrıca formun aracgiris.jsp içerisinde bulunduğu, dolayısıyla bu denetimciye yönelik istekler geldiğinde bu sayfanın görüntülenmesi talebi belirtiliyor. Son olarak successView niteliği ile form işlemleri başarılı bir şekilde tamamlandığında yeniden yönlendirmenin (redirect) yapılacağı adresin bu XML kütüğü içerisinde belirlendiğini görüyoruz. <property name="sessionForm">true <property name="commandName">aracGirisi <property name="commandClass"> komut.AracGirisi <property name="formView">aracgiris <property name="successView">index.htm <property name="mappings"> <props> <prop key="/index.htm">anasayfaDenetimci <prop key="/basit.htm">basitDenetimci <prop key="/aracgiris.htm">aracGirisFormDenetimci <property name="viewClass"> org.springframework.web.servlet.view.JstlView <property name="prefix">/WEB-INF/jsp/ <property name="suffix">.jsp Kod 2.22 springornek/WEB-INF/springornek-servlet.xml Şimdi sıra aracgiris.jsp'yi gerçekleştirmeye geldi. Bu sayfada komut nesnesi niteliklerini form alanlarına bağlayabilmek (bind) için Spring'in etiket kütüphanesini kullanmamız gerekiyor, bunun için de yapılması gereken bir kaç küçük iş bulunuyor. Önce etiket kütüphanesi tanımlayıcısı kütüğü olan spring.tld kütüğünü kurulumunuzun dist kılavuzunun altından (örneğin benim için springframework1.2.5/dist/spring.tld) uygulamanızın WEBINF kılavuzunun içine
kopyalayın. Uygulamanın bu kütüphanenin kullanımına izin vermesi için web.xml kütüğüne de bir ekleme yapmamız gerekiyor (Kod 2.23). Artık bu etiket kütüphanesini bir JSP içerisinde kullanabilmek için tek satırlık bir kod yeterli olacaktır (taglib directive). Artık Kod 2.24'te verilen aracgiris.jsp'yi uygulamaya ekleyip yeniden çalıştırabilir ve sonucu aracgiris.htm adresinde görebilirsiniz (Resim 2.4). <web-app version="2.4"> <servlet> <servlet-name>springornek <servlet-class> org.springframework.web.servlet.DispatcherServlet 1 <servlet-mapping> <servlet-name>springornek *.htm <welcome-file-list> <welcome-file>index.jsp /spring/WEB-INF/spring.tld Kod 2.23 springornek/WEB-INF/web.xml <%@ page contentType="text/html; charset=ISO-8859-9" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="spring" uri="/spring" %> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-9"> springornek - Araç Girişi
Spring MVC - Otopark Uygulaması
Araç Girişi
">Ana Sayfa Kod 2.24 springornek/WEB-INF/jsp/aracgiris.jsp Gördüğünüz gibi sayfa plakanın ve park yerinin girilmesi için alanlar ve submit türünde, araç girişinin kaydedilmesini tetikleyen bir düğmeyi içermekte. Dikkat ettiyseniz form etiketinin içinde herhangi bir action niteliğine yer verilmemiştir, çünkü form zaten tamamen denetimcinin kontrolündedir ve düğmenin tıklanması halinde ne yapılması gerektiği de denetimci tarafından belirlenir (onSubmit yönteminin çalıştırılması gibi). Aslında bu JSP sayfasında spring:bind etiketileri ve bunların içinde kullanılan status adlı değişken dışında yenilik bulunmuyor. Plaka alanları text türündeki input alanlarından oluşuyor, park yeri numaraları ise bir select etiketi ile görüntüleniyor. Park yeri numaraları JSTL forEach etiketi kullanılarak araclar adlı (denetimcinin referenceData yöntemini hatırlayınıız) liste üzerinde dolaşırken sayaç olarak kullanılan bir i değişkeni ile select etiketinin içerisine bu park numarasına ilişkin option etiketi ekleniliyor. Araç listesinin kullanımı ise option etiketinin içeriği dikkatli incelenirse sıradaki aracın değeri null değilse – yani o park yeri dolu ise – bu seçeneğin gri renkte görüntülenmesi amacını taşıyor. Daha önce söz ettiğimiz bağlama işlemi spring:bind etiketi ile gerçekleştiriliyor. Bu etiketi kullanmak için <%@ taglib prefix="spring" uri="/spring" %> satırını eklemeyi unutmamanız gerekiyor. İsterseniz bu etiketin kullanımını satır satır inceleyelim. <spring:bind path="aracGirisi.arac.ilKodu"> satırı bağlamanın başlangıcıdır ve path niteliği ile ilgili form alanının komut nesnemiz olan aracGirisi'nin arac değişkeninin ilKodu niteliği ile bağlanacağını ifade ediyoruz. Input etiketi ile il kodunun girilebilmesi için 30 piksel genişliğinde text türünde bir alan tanımı yapıyoruz. Bu alanın adının ve değerinin belirlenmesinde status değişkeninin kullanıldığını görüyoruz. Bu değişken bind etiketinin içerisinde Spring tarafından tanımlanan bir değişkendir ve expression ve value ile örneklediğimiz bir takım nitelikler sağlar. Bunlardan expression çoğunlukla form alanının isimlendirmede kullanılan bir deyimi ifade eder. Genelde değeri komut nesnesinin bağlanılan niteliğinin adıdır, mesela örneğimizde arac.ilKodu değerine sahip olacaktır. Bu şekilde, geliştiricinin kendisinin belirleyeceği form alanı isimlerini daha sonra istek (request) nesnesinden verileri parametreler olarak çıkartırken hatırlaması zorunluluğu ortadan kalkmış oluyor.
Kullandığımız diğer nitelik olan value ise form alanına bir değer vermekte kullanılıyor. Bu niteliğin önemini kavramak için bir veri güncelleme sayfası düşünelim. Genelde veri güncelleme sayfalarında alanlara ilişkin daha önce girilmiş olan verilerin görüntülenmesi gerekir. Bunu gerçekleştirmek için ise daha çok eski verileri sayfaya parametre olarak göndermek, bu verilerin değerinin null veya anlamsız olup olmadığı kontrolünü yapmak ve sakıncası yoksa form alanlarının değeri olarak bu değerleri kullanmak gibi kodu gerçekten kabartan ve anlaşılmaz hale getiren eklemeler yapmamız gerekir. Tüm bu sorunları açıklamaya çalışığımız value niteliğinin yukarıdaki gibi kullanımı çözmektedir. Çünkü status.value değişkenine otomatik olarak komut nesnesinin ilgili niteliğinin değeri koyulur. İlk olarak artık bu veriyi sayfaya parametre olarak gönderme ihtiyacı ortadan kalkar, çünkü zaten elimizde olan komut nesnesi kullanılmaktadır. Diğer bir gelişme ise artık böyle bir parametrenin var olup olmadığı varsa değerinin null olup olmadığı kontrolüne gerek kalmaz. Çünkü bu kullanımda değerin null olup olmadığı Spring tarafından denetlenir, eğer değilse bu değer ilgili alanda görüntülenir. Bu satır bind etiketinin sonlandığı noktadır ve bağlama işlemi için gereken kod tamamlanmıştır. Bağlama işlemi ile birlikte formdan submit isteği üretildiği zaman form alanındaki değer komut nesnesinin ilgili niteliğinin değeri olarak kurulur ve komut nesnesine erişilen her yerden bu değere erişilir. Görüldüğü gibi artık örneğin form verisi kullanılarak veri tabanında yapılacak bir güncelleme için istek nesnesinin parametrelerini almak ve değişkenlerin içerisine koymak için satırlarca kod yazmanıza gerek yok. Çünkü her şey gereken komut nesnesinin içine yerleşmiş durumdadır. Bunu zaten denetimcinin onSubmit yönteminin içerisindeki Otopark.aracParket(aracGirisi.getArac(), aracGirisi.getParkYeri()); satırı ile örneklemiştik. Diğer ilginç ve güzel bir örnek de select alanını çevreleyen bind etiketinin kullanımıdır. Bu sefer komut nesnesinin parkYeri alanını select etiketi ile bağlıyoruz ve bu değer sonuç olarak seçilen değerle kuruluyor. Daha önce güncelleme sayfalarında görebileceğimizden söz ettiğimiz eski (veya varsayılan) değerin sayfada yüklenmesini de
Resim 2.4 Araç Girişi Sayfası
Doğrulama (Validation) Lütfen plakanın il kodu veya araç alanına bir tam sayı olmayan bir değer girerek veya boş bırakarak araç girişi yapmayı deneyin. İşlemin tamamlanamadığını ana sayfa yerine araç girişi sayfasında kaldığınızı görerek anlamış olmalısınız. Bu Spring tarafından otomatik olarak yapılan, beklenilen veri türü (tamsayı) ile girdinin veri türünün uyuşmaması nedeniyle işlemin gerçekleştirilmesine izin vermeyen veri doğrulaması (validation) nedeniyle olmuştur. Yukarıda açıklanan işlev aslında geliştiriciyi bir çok zahmetten kurtarmaktadır. Çünkü form verilerinin türlerinin kontrol edilmesi, dönüştürme sırasında fırlatılan aykırı durumların ele alınması ve kullanıcıya bu hatanın sonucu ile geri dönülmesi gibi hacim kaplayan bir çok kodlama işlemlerinin otomatikleşmesi sağlanıyor. Ancak biraz düşününce bunların yeterli olmadığı açıktır. Bir uygulamada iş mantığı veya veri tutarlılığı gibi bir çok konuda farklı denetimler gerekebilir, ayrıca bu denetimler sonucu fark edilen hataların giderilmesi veya tekrar edilmemesi için kullanıcıya mutlaka geri bildirimde bulunulması gerekmektedir. Tabi Spring'in hata denetimi desteği de bu kadarla kalmamakta, sözü edilen iki konuyla ilgili etkili çözümler sunulmaktadır. Spring'in MVC kısmından bağımsız olan org.springframework.validation paketi veri doğrulama işleminde kullanılır. Bu paketin içindeki Validator arayüzünden türetilen ve parametre olarak aldığı komut nesnesi üzerinde doğrulama işlemlerini yerine getirebildiği validate yöntemini gerçekleştiren sınıfların nesneleri bir form denetimcisinin validator niteliği olarak kullanılabilir. Tahmin ettiğiniz gibi bu tanımlamalar doğrulama yapan sınıf yazıldıktan sonra yapılandırma kütüğü üzerinde gerçekleştirilir. Kendi uygulamamızı göz önüne aldığımızda tür denetiminin dışında mantıksal denetimler yapmamız gerektiği açıktır. Bunları şu şekilde listeleyebiliriz: •
Plakanın il kodu kesimi 1 – 81 (Ocak 2006 itibarı ile) arasında bir tamsayı olmalıdır.
•
Plakanın araç numarası kesimi 1 – 9999 aralığında bir tamsayı olmalıdır.
•
Plakanın harf kodu kesimi ise 1 – 3 adet (büyük) harften ibaret olmalıdır.
•
Dolu bir park yerine başka bir araç park edilemez.
Uygulamamızda veri doğrulama amaçlı sınıflarımızı koyabileceğimiz dogrulama paketini oluşturduktan sonra Kod 2.25'te verilen ve bu kontrolleri gerçekleştiren Validator türevi sınıfı buraya kaydedebilirsiniz. package dogrulama; import ismantigi.Otopark; import komut.AracGirisi; import org.springframework.validation.Errors; import org.springframework.validation.Validator; public class AracGirisDogrulayici implements Validator { public boolean supports(Class c) { return c.equals(AracGirisi.class); } public void validate(Object command, Errors errors) { AracGirisi aracGirisi = (AracGirisi)command; if(Otopark.doluMu(aracGirisi.getParkYeri())) errors.rejectValue("parkYeri", "parkYeriDolu"); if(aracGirisi.getArac().getIlKodu() < 1 || aracGirisi.getArac().getIlKodu() > 81) errors.rejectValue("arac.ilKodu", "gecersizIlKodu"); if(aracGirisi.getArac().getHarfKodu().length() > 3) errors.rejectValue("arac.harfKodu", "harfKoduUzunlukHatasi"); if(!aracGirisi.getArac().getHarfKodu().matches("[A-Z]*"))
} Kod 2.25 springornek/WEB-INF/src/dogrulama/AracGirisDogrulayici.java İsterseniz bu kodu ele almadan önce doğrulama amalı sınıfımızın tanımlanıp AracGirisDenetimci ile bağlama etiketlerini eklememiz gereken yapılandırma kütüğünün son durumunu görüp doğrulamanın nasıl gerçekleştirildiğini açıklığa kavuşturalım (Kod 2.26). <property name="sessionForm">true <property name="commandName">aracGirisi <property name="commandClass">komut.AracGirisi <property name="validator"> <property name="formView">aracgiris <property name="successView">index.htm <property name="mappings"> <props> <prop key="/index.htm">anasayfaDenetimci <prop key="/basit.htm">basitDenetimci <prop key="/aracgiris.htm">aracGirisFormDenetimci <property name="viewClass"> org.springframework.web.servlet.view.JstlView <property name="prefix">/WEB-INF/jsp/ <property name="suffix">.jsp <property name="basename">mesajlar Kod 2.26 springornek/WEB-INF/springornek-servlet.xml Yapılandırma kütüğünde görüldüğü gibi öncelikle doğrulayıcı sınıf için bir çekirdek (bean) tanımlanıyor
(aracGirisDogrulayici). Sonra bu doğrulayıcı aracGirisDenetimci'nin validator niteliği tarafından işaret ediliyor. Dikkat ederseniz doğrudan bir değer vermek yerine çekirdeğe işaret edildiği için ref etiketi kullanılıyor. Artık form denetimcinin bir doğrulayıcısı vardır ve formdan bir submit isteği geldiğinde öncelikle bu doğrulayıcının validate yöntemi çağrılır ve sonuç olarak bir hata belirlenmişse istek geri çevrilerek form tekrar görüntülenir (ve sakıncası yoksa şifre alanı vs. değilse kullanıcı tarafından girilmiş olan veriler gösterilir). Şimdi doğrulayıcı sınıfın içeriğini tartışabiliriz. Bu sınıfta gerçekleştirilen ilk yöntem supports yöntemidir. Bu yöntem doğrulayıcıya verilen bir komut nesnesinin bu doğrulayıcı tarafından ele alınıp alanıamayacağını belirlemek için kullanılır. Onun için hemen her doğrulayıcı bu yöntemin içeriğini aynı şekilde fakat farklı bir komut sınıfı ile gerçekleştirir. Diğer yöntem olan validate'in iki argümanı vardır. Bunlardan Object tütündeki command komut nesnesidir ve görüldüğü gibi biz onu AracGirisi türüne çevirerek kullanıyoruz. Diğer argüman ise form üzerinde ortaya çıkan hataların tutulduğu errors nesnesidir. Bu nesnenin içeriği sadece bu yöntem tarafından belirlenmez, daha önce söz ettiğimiz gibi Spring'in otomatik olarak gerçekleştirdiği denetimlerle bulunan hatalar da bu nesnenin içinde bulunur. sonuç olarak bu nesneye kaydedilmiş hata(lar) varsa submit işlemi gerçekleştirilmez ve form yeniden görüntülenir. Yöntemin içerisinde yukarıda listelenen, iş mantığına dair bir takım kontroller yapılıyor ve eğer hatalı bir durum varsa bu errors nesnesinin içerisine rejectValue yöntemi çağrılarak ekleniyor. Bu yönteme verilen iki parametreden ilki komut nesnesinin hataya sebep olan niteliğinin adıdır. İkincisi ise ortaya çıkan hataya ilişkin kullanılan bir anahtar kelimedir. Bu anahtar örneğin görüntülenecek hata mesajının belirlenmesinde kullanılabilir. Spring'in ilgili javadoc belgeleri incelenirse Errors ve ValidationUtils sınıflarının sağladığı kullanışlı bir takım yöntemlerin daha bulunduğu görülebilir. Mesaj konusuna değinmişken yapılandırma kütüğüne eklediğimiz bir diğer çekirdek (bean) olan messageSource'a değinmemiz gerekiyor. Bu aslında Spring çatısının yine MVC'den bağımsız olarak sağladığı bir çözümdür ve org.springframework.context.support.ResourceBundleMessageSource sınıfının bir nesnesidir. Burada bu işlevin sadece konumuz kapsamında, örneğimiz içindeki kullanımına yer vereceğiz. Çekirdek tanımında yer alan basename niteliğine görüldüğü gibi mesajlar değeri atanıyor. Bu tanım uygulamada mesajların mesajlar.properties adlı kütüğün içinde bulunduğunu ifade eder. Kısaca açıklamak gerekirse (uzantısı .properties olan) properties kütükleri her satırda birbirinden “=” işareti ile birbirinden ayrılan anahtar değer çiftlerinden oluşan, sade ve pratik bir şekilde bu değerleri kaynak kodun içerisine gömülmekten kurtaran bir çözümdür ve sadece Spring tarafından değil Java tarafından her tür uygulamada kullanımı desteklenen bir standarttır. Biz içeriğini Kod 2.27'de görebileceğiniz mesajlar.properties kütüğünü /WEBINF/classes kılavuzunun altına koyuyoruz ve yapılandırma kütüğündeki tanım sayesinde Spring tarafından anahtar kelimelere karşılık gelen mesajları içeren mesajKaynağı(messageSource) olarak algılanmasını sağlıyoruz. Dikkat edilmesi gereken bir nokta standartlar gereği bu kütükte yer alan bazı Türkçe karakterlerin algılanamaması nedeniyle onlara Unicode değerleri ile yer veriyoruz (İ=\u0130, ı=\u0131, Ş=\u015E, ş=\u015F, Ğ=\u011E, ğ=\u011F). typeMismatch=Geçersiz veri! typeMismatch.ilKodu=\u0130l kodu bir tamsay\u0131 olmal\u0131! typeMismatch.aracNo=Araç no bir tamsay\u0131 olmal\u0131! parkYeriDolu=Seçti\u011Finiz park yeri dolu! gecersizIlKodu=\u0130l kodu 1-81 aras\u0131nda olmal\u0131! harfKoduUzunlukHatasi=Harf kodu en fazla 3 karakter içerebilir! harfKoduKarakterHatasi=Harf kodu yaln\u0131z A..Z aras\u0131ndaki karakterleri içerebilir! gecersizAracNo=Araç no 1-9999 aras\u0131nda olmal\u0131! Kod 2.27 springornek/WEB-INF/classes/mesajlar.properties Burada söz edilmesi gereken bir nokta da Spring tarafından tanımlanan typeMismatch anahtarıdır. Kod 2.27'de bizim belirlediğimiz anahtarlardan biri olmayan bu anahtar bir tür dönüşümü hatası ortaya çıktığı zaman Spring tarafından üretilir. typeMismatch tek başına tüm tür dönüşümü hatalarına karşılık gelirken, istenirse niteliğe özel hata mesajlarına yer verebilmek için typeMismatch.ilKodu örneği gibi bir kullanım tercih edilebilir. Komut nesnesini kullanarak veri denetimini nasıl yapabileceğimizi gördük. Hataların kullanıcıya bildirilmesinde ise yine Spring etiketlerine başvuracağız. Biz örneğimizde spring:bind etiketinin yanısıra spring:hasBindErrors etiketini kullanarak hata geri bildirimini örnekleyeceğiz. Örneğimizde yer almayacak olsa da hasBindErrrors'un sağladığı errors değişkeninin (bind etiketinin status değişkeninin bir benzeri) errorCount, allErrors gibi niteliklerinin de faydalı kullanımları olabileceğini hatırlatmak gerekir. Tüm Spring etiketleri hakkında detaylı bilgi için Spring kurulumunuzun docs/taglib kılavuzu altındaki belgelerden yararlanabilirsiniz. Şimdi biz üzerine bazı eklemeler yaparak geliştirdiğimiz aracgiris.jsp'de kullanıcıya yönelik hata
bildirimini nasıl ele aldığımızı görelim (Kod 2.28). <%@ page contentType="text/html; charset=ISO-8859-9" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="spring" uri="/spring" %> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-9"> springornek - Araç Girişi
Spring MVC - Otopark Uygulaması
Araç Girişi
<spring:hasBindErrors name="aracGirisi">
Lütfen hatalı girişleri düzeltiniz!
">Ana Sayfa Kod 2.28 springornek/WEB-INF/jsp/aracgiris.jsp Görüldüğü gibi plaka alanlarına dair hataların listesi tablonun plaka alanlarının bulunduğu hücresinde, park yerine dair hata mesaj(lar)ı da park yerine dair hücrede görüntüleniyor. Hata mesajlarını göstermede bind etiketinin sağladığı status değişkeninin daha önce söz etmediğimiz errorMessages niteliğinden yararlanıyoruz. Bu nitelik liste türündedir ve mesajlar bu liste üzerinde dolaşılarak görüntülenir. Plaka alanlarına ilişkin hataların görüntülendiği <spring:bind path="aracGirisi.arac.*"> ${error} kısımda komut nesnesinin ara niteliğinin tüm niteliklerine (arac.*; plaka alanları) dair bir bağlama (bind) işlemi yapılıyor. Buradaki komut nesnesi niteliklerini herhangi bir form alanına bağlama işlemi yoktur, sadece onlara ilişkin hata mesajlarına erişebilmek amacı güdülmektedir. Park yeri seçimi ile ilgili hatalar ise ${error} satırları ile görüntüleniyor. Dikkat ederseniz burada yeni bir bind etiketi kullanılmıyor, çünkü parkYeri niteliğini form alanı ile bağlamak için açılan etiket henüz kapatılmadı ve varsa ona ilişkin hatalara burada status.errorMessages üzerinden erişilebiliyor. Son olarak <spring:hasBindErrors name="aracGirisi">
Lütfen hatalı girişleri düzeltiniz!
satırlarında hasBindErrors etiketinin sanki bir if deyimi gibi davranarak, komut nesnesinin herhangi bir niteliği için girdi hatası bulunmuşsa bunların giderilmesini öneren bir mesaj görüntülenmesinde kullanımı örneklenmektedir. Resim 2.5'te hata geri bildirimine ilişkin bir örnek ekran görüntüsü bulunmaktadır.
Resim 2.5 Veri Doğrulama Hata Geri Bildirimi
Durdurucular (Interceptors) Durdurucu kavramı Spring'in işleyici eşleme (handler mapping) mekanizması ile birlikte düşünülen bir işlevdir. Bir isteği uygun denetimciye yönlendiren işleyici eşleme nesnesinin (handler mapping) içerisinde org.springframework.web.servlet.HandlerInterceptor arayüzünü gerçekleştiren durdurucu sınıflarının nesneleri bulunabilir. Bu arayüz preHandle, postHandle ve afterCompletion yöntemlerini sağlar. Bunlardan preHandle uygun denetimci çalıştırılmadan önce, postHandle denetimci çalıştırıldıktan sonra, ama görünüme yönlendirilmeden önce, afterCompletion ise istek tamamen gerçekleştirildiğinde çağrılır. Uygulamamızda durdurucuları örneklemek için otoparkta yeni araç girişi için boş yer kalmadığı zaman araç giriş sayfasına gelen isteklerin değerlendirilmeden ana sayfaya yönlendirilmesi senaryosunu ön görüyoruz. Bu durumda durdurucunun işlemleri preHandle yönteminin içinde gerçekleştirmesi gerektiği ortaya çıkıyor. Çünkü bir denetimci (aracGirisFormDenetimci) çalıştırılmadan önce onun çalıştırılıp çalıştırılamayacağınca karar verilmesi söz konusu. Ancak burada ortaya çıkan bir problem daha var; tüm denetimciler aynı işleyici eşleme nesnesi tarafından ele alındığı için tüm denetimcilere gelen istekler durdurucu tarafından park yeri kalıp kalmadığı sorgusuyla karşı karşıya kalacaklardır. Bunu çözebilmek için içerisinde sadece aracGirisDenetimci'sinin eşlemesinin ve durdurucu tanımının yer aldığı yeni bir işleyici eşleme tanımına ihtiyacımız olacaktır. Kod 2.29'da durdurucu sınıfın içeriğine yer verilmiştir. package denetim; import ismantigi.Otopark; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView;
public void setHataSayfasi(String hataSayfasi) { this.hataSayfasi = hataSayfasi; } Kod 2.29 springornek/WEB-INF/src/denetim/AracGirisDurdurucu.java
Gördüğünüz gibi preHandle yönteminin içerisinde Otopark sınıfının doluMu yöntemi çağrıılıyor ve otoparkın dolu olup olmadığı denetleniyor. Eğer dolu ise araç giriş sayfasını görüntüleyecek olan denetimci çalıştırılmamalıdır, bu nedenle geriye false döndürülmektedir. Tabi denetimcinin çalıştırılmaması durumunda görüntülenecek olan sayfanın beirlenmesi gerekmektedir. Bu amaçla eğer otopark dolu ise hataSayfasi niteliğinde tutulan adrese (yeniden yönlendirme / redirect yapıldığı için bir adres verilmesi gerekiyor) yönlendirme gerçekleştiriliyor. Bu niteliğin tutulmasının sebebi gidilecek sayfayı kodun içi yerine, yapılandırma kütüğüne yazmanın tercih edilmesidir. Eğer otopark dolu değilse hiç bir şey yapılmasına gerek yoktur ve true döndürülür, bu da aracGirisDenetimci'nin çalıştırılmasına izin verir. Kod 2.30'da yapılandırma kütüğünde yapılan değişiklikleri görebilirsiniz. <property name="sessionForm">true <property name="commandName">aracGirisi
<property name="mappings"> <props> <prop key="/index.htm">anasayfaDenetimci <prop key="/basit.htm">basitDenetimci <property name="hataSayfasi">index.htm <property name="interceptors"> <list> <property name="mappings"> <props> <prop key="/aracgiris.htm">aracGirisFormDenetimci <property name="viewClass"> org.springframework.web.servlet.view.JstlView <property name="prefix">/WEB-INF/jsp/ <property name="suffix">.jsp <property name="basename">mesajlar Kod 2.30 springornek/WEB-INF/springornek-servlet.xml Artık aracGirisFormDenetimci'ye gelen istekler urlEsleme adlı işleyici eşleme nesnesi tarafından ele alınmıyor, onun yerine aracGirisUrlEsleme adlı yeni eklediğimiz nesne kullanılıyor. Bu nesne işleyici eşleme özelliğinin yanı sıra aracGirisiDurdurucu'nun da dikkate alınmasından sorumlu tutuluyor. Dikkat edilmesi gereken diğer bir husus da aracGirisiDurdurucu'nun haftaSayisi niteliğinin değerinin burada anasayfa.htm olarak belirlenmesidir. Son değişikliklerin ardından uygulamayı çalıştırıp, otopark tamamen doluncaya kadar araç girişi yapar ve ardından ana sayfadaki araç girişi bağlantısını tekrar tıklarsanız araç girişi sayfasına yönlendirilmediğinizi, hala ana sayfada kalmaya devam ettiğinizi görebilirsiniz.
Sonuç Eğer belgeyi baştan sona dikkatlice, örnekleri çalıştırarak ve hatta üzerinde oynamalar yaparak okuduysanız artık Spring MVC çatısının temel kavram ve işlevleri hakkında önemli derecede fikir sahibi olduğunuzu söyleyebiliriz. Başlangıç düzeyinde hazırlanan bu belgede, Spring MVC ile acısız bir şekilde tanışılması hedefiyle, önemli kavramlara ve öğrenme döneminde sorun çıkartabileceği düşünülen noktalara öncelik tanıyarak yer verilmeye çalışıldı. Belgenin içerisinde de sık sık belirtildiği gibi burada bir çok konuda Spring MVC'nin sağladığı tüm seçeneklere yer vermek yerine en sık kullanılanara değinilmeye ve örneklerde bunların kullanımına özen gösterildi. Böyle bir tercih yapılmasının sebebi öğrenme döneminde kafa karışıklığının ortaya çıkmasından sakınmaktı. Ancak şu andan itibaren sağlanılan tanışıklılık sayesinde başvuru belgesi (reference manual), javadoc belgeleri vb. geniş kapsamlı kaynaklardan yararlanmakta zorluk çekilmeyeceği ön görülebilir. Bundan sonraki aşamada uygulamaya burada yer vermediğimiz araç çıkışı işlevini sağlayan bir sayfayı eklemek ve veri üzerindeki işlemlerin bir veri tabanına taşımak faydalı denemeler olabilir. Spring'in sağladığı esnek ve yapılandırılabilir yapı sayesinde Spring MVC'nin gücü Spring'in veri tabanı desteği veya daha farklı bir çok konuda sağladıkları ile birleştirilerek çok yetenekli uygulamalar ortaya çıkartılabilir. Spring'in Hibernate benzeri veri tabanı teknolojilerini, çeşitli görünüm teknolojilerini ve hatta Struts'la birlikte çalışmayı ve daha bir çok farklı teknolojiyi desteklediğini de göz önüne aldığımızda ufkunun ne kadar geniş olduğu ve kullanım yaygınlığının daha uzun süre artarak devam edeceği ortaya çıkıyor. Bu durumda henüz işin başında olduğumuzu söylemek sanırım yanlış olmaz.