16. Spring'e Giriş MVC
16.1. Bir Web Uygulamasında Spring'in Yeri MVC
Spring MVC'i bir web uygulaması geliştirme sürecinde ele alalım. Çoğu zaman, bu uygulama aşağıdaki gibi çok katmanlı bir mimari üzerine inşa edilir:
![]() |
- [Web] katmanı, web uygulamasının kullanıcısıyla etkileşimde bulunan katmandır. Kullanıcı, bir tarayıcı aracılığıyla görüntülenen web sayfaları vasıtasıyla web uygulamasıyla etkileşime girer. Spring MVC bu katmanda yer alır ve yalnızca bu katmanda bulunur;
- [métier] katmanı, maaş veya fatura hesaplaması gibi uygulama yönetim kurallarını uygular. Bu katman, [Web] katmanı aracılığıyla kullanıcıdan gelen verileri ve SGBD katmanından [DAO] katmanı aracılığıyla gelen verileri kullanır;
- [DAO] katmanı (Veri Erişim Nesneleri), [ORM] katmanı (Nesne-İlişkisel Eşleştirici) ve JDBC sürücüsü, SGBD'teki verilere erişimi yönetir. [ORM] katmanı, [DAO] katmanı tarafından işlenen nesneler ile ilişkisel bir veritabanındaki tabloların satırları ve sütunları arasında bir köprü görevi görür. JPA (Java Persistence API) adlı bir spesifikasyon, kullanılan ORM katmanının bu spesifikasyonları uyguladığı durumlarda, bu katmandan soyutlaşmaya olanak tanır. Bu eğitimde durum böyle olacak ve bundan böyle ORM katmanını JPA katmanı olarak adlandıracağız;
- katmanların entegrasyonu Spring çerçeve yapısı tarafından gerçekleştirilir;
16.2. Spring MVC geliştirme modeli
Spring MVC, MVC olarak adlandırılan mimari modelini (Model – Görünüm – Denetleyici) şu şekilde uygular:
![]() |
Bir istemciden gelen isteğin işlenmesi şu şekilde gerçekleşir:
- istek - istenen URL'ler http://machine:port/contexte/Action/param1/param2/....?p1=v1&p2=v2&... biçimindedir. [Front Controller], isteği doğru denetleyiciye ve bu denetleyici içindeki doğru eyleme "yönlendirmek" için bir yapılandırma dosyası veya Java açıklamaları kullanır. Bunun için, URL'in [Action] alanını kullanır. URL ve [/param1/param2/...]'in geri kalanı, eyleme iletilecek isteğe bağlı parametrelerden oluşur. Burada MVC'teki C, [Front Controller, Contrôleur, Action] dizesidir. İstenen eylemi işleyebilecek hiçbir denetleyici yoksa, web sunucusu istenen URL'in bulunamadığını bildirir.
- İşleme
- (devam)
- Seçilen eylem, [Front Controller] tarafından kendisine iletilen parami parametrelerini kullanabilir. Bu parametreler çeşitli kaynaklardan gelebilir:
- URL'in [/param1/param2/...] yolundan,
- URL'in ,'e gönderdiği [p1=v1&p2=v2] parametrelerinden
- tarayıcı tarafından istekle birlikte gönderilen parametrelerden;
- kullanıcının isteğinin işlenmesi sırasında, eylem [métier] ve [2b] katmanlarına ihtiyaç duyabilir. Müşterinin isteği işlendikten sonra, bu işlem çeşitli yanıtları tetikleyebilir. Klasik bir örnek şudur:
- istek düzgün bir şekilde işlenemediğinde bir hata sayfası
- aksi takdirde bir onay sayfası
- eylem, belirli bir görünümün görüntülenmesini ister: [3]. Bu görünüm, görünüm modeli olarak adlandırılan verileri gösterecektir. Bu, MVC'teki M'dir. Eylem, bu M şablonunu [2c] oluşturacak ve bir V görünümünün görüntülenmesini isteyecektir [3];
- yanıt - seçilen V görünümü, eylemin oluşturduğu M şablonunu kullanarak, müşteriye göndermesi gereken HTML yanıtının dinamik kısımlarını başlatır ve ardından bu yanıtı gönderir.
Bir web hizmeti / jSON için, önceki mimari biraz değiştirilmiştir:
![]() |
- [4a]'te, bir Java sınıfı olan şablon, bir kütüphane tarafından jSON dizesine dönüştürülür;
- [4b]'te, bu jSON dizesi tarayıcıya gönderilir;
Şimdi, MVC web mimarisi ile katmanlı mimari arasındaki bağlantıyı açıklayalım. Modele verilen tanıma göre, bu iki kavram birbiriyle ilişkili olabilir veya olmayabilir. Tek katmanlı bir Spring web uygulaması MVC ele alalım:
![]() |
[Web] katmanını Spring MVC ile uygularsak, bir MVC web mimarisine sahip oluruz, ancak çok katmanlı bir mimariye sahip olmayız. Burada, [web] katmanı her şeyi üstlenecektir: sunum, iş mantığı, veri erişimi. Bu işleri gerçekleştirecek olanlar eylemlerdir.
Şimdi, çok katmanlı bir web mimarisini ele alalım:
![]() |
[Web] katmanı, herhangi bir çerçeve kullanmadan ve MVC modelini takip etmeden uygulanabilir. Bu durumda gerçekten çok katmanlı bir mimariye sahip oluruz, ancak web katmanı MVC modelini uygulamaz.
Örneğin, .NET ortamında yukarıdaki [Web] katmanıyukarıdaki [Web] katmanı, ASP.NET ve MVC ile uygulanabilir ve böylece [Web] katmanının MVC türü olduğu bir katmanlı mimari elde edilir. Bu işlem tamamlandıktan sonra, bu ASP.NET ve MVC katmanını, geri kalan (iş mantığı, DAO, ORM) aynı şekilde koruyarak değiştirebiliriz. Böylece, artık MVC türü olmayan bir [Web] katmanına sahip katmanlı bir mimari elde ederiz.
MVC'te, M modelinin V görünümü olan c.a.d'in modeli olduğunu belirtmiştik. V görünümü tarafından görüntülenen verilerin tamamı. MVC'in M modeline ilişkin başka bir tanım verilmiştir:
![]() |
Birçok yazar, [Web] katmanının sağındaki kısmın MVC'in M modelini oluşturduğunu düşünmektedir. Belirsizlikleri önlemek için şunlardan söz edilebilir:
- [Web] katmanının sağındaki her şeyi ifade ederken alan modelinden
- bir V görünümü tarafından görüntülenen verileri ifade ederken "görünüm modeli"
Bundan sonra, "M modeli" terimi yalnızca bir V görünümünün modelini ifade edecektir.
16.3. Spring ile bir web projesi / jSON
[http://spring.io/guides] sitesi, Spring ekosistemini keşfetmek için başlangıç kılavuzları sunmaktadır. Bir Spring projesi MVC için gerekli Maven yapılandırmasını öğrenmek üzere bu kılavuzlardan birini takip edeceğiz.
16.3.1. Demonstrasyon projesi
![]() |
- [1]'te, Spring kılavuzlarından birini içe aktarıyoruz;
![]() |
- [2]'te, [Rest Service] örneğini seçiyoruz;
- [3]'te, Maven projesini seçiyoruz;
- [4]'te kılavuzun son sürümünü seçiyoruz;
- [5]'te, onaylıyoruz;
- [6]'te, içe aktarılan proje;
Standart URL aracılığıyla erişilebilen ve jSON metni sağlayan web hizmetleri genellikle REST (REpresentational Durum Aktarımı) hizmetleri olarak adlandırılır. Bir hizmet, belirli kurallara uyuyorsa Restful olarak adlandırılır.
Şimdi içe aktarılan projeyi, öncelikle Maven yapılandırmasını inceleyelim.
16.3.2. Maven Yapılandırması
[pom.xml] dosyası şu şekildedir:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-rest-service</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<properties>
<start-class>hello.Application</start-class>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
</project>
- 6-8. satırlar: Maven projesinin özellikleri. Maven derlemesi sonucunda üretilen dosyanın türünü belirten [<packaging>] etiketi eksik. Bu etiket olmadığında, [jar] türü kullanılır. Dolayısıyla uygulama, konsol türü bir yürütülebilir uygulamadır; paketleme türü [war] olacak bir web uygulaması değildir;
- 10-14. satırlar: Maven projesinin [spring-boot-starter-parent] adlı bir üst projesi vardır. Projenin bağımlılıklarının büyük kısmını bu üst proje tanımlar. Bu bağımlılıklar yeterli olabilir; bu durumda başka bağımlılık eklenmez, ya da yeterli olmayabilir; bu durumda eksik olan bağımlılıklar eklenir;
- satır 17-20: [spring-boot-starter-web] artefaktı, oluşturulmuş görünümlerin bulunmadığı bir web hizmeti türü Spring projesi olan MVC için gerekli kütüphaneleri beraberinde getirir. Bu artefakt, gömülü bir Tomcat sunucusuna ait kütüphaneler de dahil olmak üzere çok sayıda kütüphaneyi beraberinde getirir. Uygulama bu sunucu üzerinde çalıştırılacaktır;
Bu yapılandırma ile birlikte gelen kütüphanelerin sayısı oldukça fazladır:
![]() | ![]() |
Yukarıda Tomcat sunucusuna ait üç arşiv dosyası görülüyor.
16.3.3. Bir Spring hizmetinin mimarisi [web / jSON]
Bir web hizmeti / jSON için, Spring MVC, MVC modelini şu şekilde uygular:
![]() |
- [4a]'te, bir Java sınıfı olan model, jSON kütüphanesi tarafından jSON dizesine dönüştürülür;
- [4b]'te, bu jSON dizesi tarayıcıya gönderilir;
16.3.4. C denetleyicisi
![]() |
İçe aktarılan uygulama aşağıdaki denetleyiciye sahiptir:
package hello;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
@RequestMapping("/greeting")
public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
return new Greeting(counter.incrementAndGet(), String.format(template, name));
}
}
- 9. satır: [@RestController] anotasyonu, [GreetingController] sınıfını bir Spring denetleyicisi haline getirir; yani, bu sınıfın yöntemleri URL'leri işlemek üzere kaydedilir. Benzer bir anotasyon olan [@Controller]'i daha önce görmüştük. Bu denetleyicinin yöntemlerinin sonucu, görüntülenecek görünümün adı olan [String] türündeydi. Burada durum farklıdır. [@RestController] türündeki bir denetleyicinin yöntemleri, tarayıcıya gönderilmek üzere serileştirilmiş nesneler döndürür. Uygulanan serileştirme türü, Spring MVC yapılandırmasına bağlıdır. Burada, nesneler jSON olarak serileştirilecektir. Projenin bağımlılıkları arasında bir jSON kütüphanesinin bulunması, Spring Boot'un otomatik yapılandırma yoluyla projeyi bu şekilde yapılandırmasına neden olur;
- 14. satır: [@RequestMapping] anotasyonu, yöntemin işlediği URL'i belirtir; burada bu, URL [/greeting]'tir;
- 15. satır: [@RequestParam] anotasyonunu daha önce açıklamıştık. Yöntemin döndürdüğü sonuç, [Greeting] türünde bir nesnedir.
- 12. satır: atomik türde bir uzun tamsayı. Bu, erişim eşzamanlılığını desteklediği anlamına gelir. Birden fazla iş parçacığı, [counter] değişkenini aynı anda artırmak isteyebilir. Bu işlem düzgün bir şekilde gerçekleştirilecektir. Bir iş parçacığı, sayacın değerini ancak onu değiştiren iş parçacığı değişikliğini tamamladıktan sonra okuyabilir.
16.3.5. M Modeli
Önceki yöntemle oluşturulan M modeli, aşağıdaki [Greeting] nesnesidir:
![]() |
package hello;
public class Greeting {
private final long id;
private final String content;
public Greeting(long id, String content) {
this.id = id;
this.content = content;
}
public long getId() {
return id;
}
public String getContent() {
return content;
}
}
Bu nesnenin jSON dönüşümü, {"id":n,"content":"metin"} karakter dizisini oluşturacaktır. Sonuç olarak, denetleyici yöntemi tarafından üretilen jSON dizisi şu şekilde olacaktır:
veya
16.3.6. Çalıştırma
![]() |
[Application.java] sınıfı, projenin yürütülebilir sınıfıdır. Kodu şöyledir:
package hello;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan
@EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Bu kodu önceki örnekte daha önce görmüş ve açıklamıştık. Projeyi çalıştıralım:
![]() |
Aşağıdaki konsol günlükleri elde edilir:
- 13. satır: Tomcat sunucusu 8080 numaralı bağlantı noktasında başlatılıyor (12. satır);
- 17. satır: [DispatcherServlet] servleti mevcut;
- 20. satır: [GreetingController.greeting] yöntemi tespit edildi;
Web uygulamasını test etmek için URL ve [http://localhost:8080/greeting] yöntemleri çağrılır:
![]() | ![]() |
Beklenen jSON dizisini başarıyla alıyoruz. Sunucu tarafından gönderilen HTTP başlıklarını incelemek ilginç olabilir. Bunun için, [Advanced Rest Client] adlı Chrome uzantısını kullanacağız (Chrome / Ctrl-T / [Applications] Menüsü / [Advanced Rest Client] - bkz. Ekler, paragraf 23.11):
![]() |
- [1]'e dönüştürürken, istenen URL;
- [2]'te, GET yöntemi kullanılmıştır;
- [3]'te, yanıt jSON;
- [4]'te, sunucu jSON biçiminde bir yanıt gönderdiğini belirtmiştir;
- [5]'te, aynı URL isteniyor, ancak bu sefer POST ile;
- [7]'te, bilgiler sunucuya [urlencoded] biçiminde gönderilir;
- [6]'te, name parametresi ve değeri;
- [8]'te, tarayıcı sunucuya [urlencoded] bilgilerini gönderdiğini bildirir;
- [9]'te, sunucunun jSON yanıtı;
16.3.7. Çalıştırılabilir bir arşiv oluşturma
Şimdi bir yürütülebilir arşiv oluşturuyoruz:
![]() |
![]() |
- [1]: bir Maven hedefi çalıştırıyoruz;
- [2]'te: iki hedef (goal) vardır: [clean], Maven projesinden [target] klasörünü silmek için; [package] ise bu klasörü yeniden oluşturmak içindir;
- [3]'te: Oluşturulan [target] klasörü bu klasörde oluşturulacaktır;
- [4]'te: hedef oluşturulur;
Konsolda görüntülenen günlüklerde, [spring-boot-maven-plugin] eklentisinin göründüğünden emin olun. Yürütülebilir arşivi oluşturan budur (aşağıdaki [pom.xml]'e bakın):
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Konsol aracılığıyla oluşturulan klasöre girin:
D:\Temp\wksSTS\gs-rest-service\target>dir
...
11/06/2014 15:30 <DIR> classes
11/06/2014 15:30 <DIR> generated-sources
11/06/2014 15:30 11 073 572 gs-rest-service-0.1.0.jar
11/06/2014 15:30 3 690 gs-rest-service-0.1.0.jar.original
11/06/2014 15:30 <DIR> maven-archiver
11/06/2014 15:30 <DIR> maven-status
...
- 5. satır: oluşturulan arşiv;
Bu arşiv şu şekilde çalıştırılır:
D:\Temp\wksSTS\gs-rest-service-complete\target>java -jar gs-rest-service-0.1.0.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.1.0.RELEASE)
2014-06-11 15:32:47.088 INFO 4972 --- [ main] hello.Application
: Starting Application on Gportpers3 with PID 4972 (D:\Temp\wk
sSTS\gs-rest-service-complete\target\gs-rest-service-0.1.0.jar started by ST in
D:\Temp\wksSTS\gs-rest-service-complete\target)
...
Artık web uygulaması başlatıldığına göre, bir tarayıcıyla erişilebilir:
![]() |
16.3.8. Uygulamayı bir Tomcat sunucusuna dağıtma
Önceki projede olduğu gibi, [pom.xml] dosyasını şu şekilde değiştiriyoruz:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-rest-service</artifactId>
<version>0.1.0</version>
<packaging>war</packaging>
...
</project>
- 9. satır: bir war arşivi (Web ARchive) oluşturulacağını belirtmek gerekir;
Ayrıca web uygulamasını da yapılandırmamız gerekiyor. [web.xml] dosyası bulunmadığından, bu işlem [SpringBootServletInitializer] sınıfından miras alan bir sınıfla gerçekleştirilir:
![]() |
[ApplicationInitializer] sınıfı şu şekildedir:
package hello;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
public class ApplicationInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
- 6. satır: [ApplicationInitializer] sınıfı, [SpringBootServletInitializer] sınıfını genişletir;
- 9. satır: [configure] yöntemi yeniden tanımlanmıştır (8. satır);
- 10. satır: Projeyi yapılandıran sınıf belirtilir;
Projeyi çalıştırmak için şu adımları uygulayabilirsiniz:
![]() |
- [1-2]'te, proje Eclipse'te IDE'te kayıtlı sunuculardan birinde çalıştırılır;
Bu işlem tamamlandıktan sonra, bir tarayıcıda URL [http://localhost:8080/gs-rest-service/greeting/?name=Mitchell] adresini girebilirsiniz:
![]() |
16.4. Conclusion
Web uygulamasının tarayıcıya bir jSON akışı gönderdiği bir tür Spring projesi olan MVC'i tanıttık. Şimdi, önceki bölümlerde incelediğimiz [dbproduitscategories] veritabanını web üzerinde sunmak için bir web uygulaması / jSON geliştireceğiz.























