Skip to content

1. Giriş

Bu belgenin PDF dosyası, |BURADA| adresinde mevcuttur.

Bu belgedeki örnekler |BURADA| adresinde mevcuttur.

Burada, MVC (Model – Görünüm – Denetleyici) modeline göre web uygulamaları geliştirmek için bir çerçeve sağlayan bir Java web çerçevesi olan Spring MVC'in önemli kavramlarını örnekler yardımıyla tanıtmayı amaçlıyoruz. Spring MVC, Spring [http://projects.spring.io/spring-framework/] ekosisteminin bir dalıdır. Ayrıca Thymeleaf [http://www.thymeleaf.org/] görünüm motorunu da tanıtacağız.

Bu ders, Java diline gerçekten hakim olan okuyuculara yöneliktir. Web programlama bilgisi gerekli değildir.

Ayrıntılı olmasına rağmen, bu belge muhtemelen eksiktir. Spring, çok sayıda dalı olan devasa bir çerçeve (framework)dır. Spring MVC hakkında daha derinlemesine bilgi edinmek için aşağıdaki kaynaklara başvurulabilir:

  • Spring çerçevesinin referans belgesi [http://docs.spring.io/spring/docs/current/spring-framework-reference/pdf/spring-framework-reference.pdf];
  • URL adresinde çok sayıda Spring öğreticisi bulunabilir; [http://spring.io/guides]
  • Spring [http://spring.developpez.com/]'e adanmış [developpez.com] sitesi.

Bu belge, elinizde bilgisayar olmadan da okunabilecek şekilde yazılmıştır. Bu nedenle, çok sayıda ekran görüntüsü eklenmiştir.

1.1. Sources

Bu belgenin iki ana kaynağı vardır:

  • [Örneklerle ASP.NET MVC çerçevesine giriş (2013)]. Spring MVC ve ASP.NET MVC, birbirine benzeyen iki çerçeve olup, ikincisi birincisinden çok sonra geliştirilmiştir. İki çerçeveyi karşılaştırabilmek için, ASP.NET ve MVC hakkındaki belgede izlediğim aynı sıralamayı kullandım;
  • ASP.NET ve MVC hakkındaki belgede şu anda (Aralık 2014) çözüm içeren bir vaka çalışması bulunmamaktadır. Burada, [Bir istemci/sunucu örneği - AngularJS 1.x / Spring 4 (2014)] belgesindeki vaka çalışmasını aldım ve şu şekilde değiştirdim:
    • [Tutoriel AngularJS / Spring 4]'teki vaka çalışması, sunucunun Spring ile oluşturulmuş bir web hizmeti (jSON) ve istemcinin bir istemci (AngularJS) olduğu bir istemci/sunucu uygulamasına aittir;
    • bu belgede ise aynı web hizmeti / jSON ele alınmaktadır, ancak istemci iki katmanlı bir web uygulamasıdır ([client jQuery] / [service web / jSON]);

Bu kaynakların dışında, sorularımın yanıtlarını İnternet'te aradım. Özellikle [http://stackoverflow.com/] sitesi bana çok yardımcı oldu.

1.2. Kullanılan araçlar

Aşağıdaki örnekler şu ortamda test edilmiştir:

  • 64 bit Windows 8.1 Pro işletim sistemli bilgisayar;
  • JDK 1.8;
  • IDE Spring Tool Suite 3.6.3 (bkz. paragraf 9.3);
  • Chrome tarayıcısı (diğer tarayıcılar kullanılmamıştır);
  • Chrome [Advanced Rest Client] uzantısı (bkz. paragraf 9.6);

JDK 1.8'e dikkat edin. Vaka çalışmasındaki yöntemlerden biri, Java 8'in [java.lang] paketindeki bir yöntemi kullanmaktadır.

Tüm örnekler, Eclipse, IntellijIDEA veya NetBeans ile aynı şekilde açılabilen Maven projeleridir. Aşağıdaki ekran görüntüleri, Eclipse’in bir türü olan Spring Tool Suite’ten alınmıştır.

1.3. Örnekler

Örnekler, URL ve [http://tahe.developpez.com/java/springmvc-thymeleaf] dosyalarında, indirilebilir bir zip dosyası biçiminde mevcuttur.

  

Tüm projeleri STS dosyasına yüklemek için aşağıdaki adımları izleyin:

  • [1-3] dosyasına Maven projelerini içe aktarın;
  • [4]'te örnek klasörünü belirtin;
  • [5]'te, klasördeki tüm projeleri seçin;
  • [6]'te, onaylayın;
  • [7]'te, içe aktarılan projeleri;

1.4. Spring MVC'in bir web uygulamasındaki yeri

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 temas halinde olan 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 [DAO] katmanı aracılığıyla SGBD katmanından 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. Burada ORM Hibernate'i kullanacağız. JPA (Java Persistence API) adlı bir spesifikasyon, kullanılan ORM bu spesifikasyonları uyguluyorsa, ondan soyutlaşmaya olanak tanır. Hibernate ve diğer Java ORM'leri bu duruma uymaktadır. Dolayısıyla bundan böyle ORM katmanına ORM katmanı, JPA katmanına ise JPA katmanı denecektir;
  • katmanların entegrasyonu Spring çerçeve sistemi tarafından gerçekleştirilir;

Aşağıda verilen örneklerin çoğu, yalnızca tek bir katman, yani [Web] katmanını kullanacaktır:

Ancak bu belge, çok katmanlı bir web uygulamasının oluşturulmasıyla sona erecektir:

Tarayıcı, Spring ile uygulanan bir [Web1] uygulamasına bağlanacaktır MVC / Thymeleaf ile geliştirilmiş bir uygulamaya bağlanacak ve bu uygulama da yine Spring MVC ile geliştirilmiş bir web hizmetinden verilerini alacaktır. Bu ikinci web uygulaması bir veritabanına erişecektir.

1.5. Spring MVC geliştirme modeli

Spring MVC, MVC olarak bilinen mimari modelini (Model – Görünüm – Denetleyici) şu şekilde uygular:

Bir istemciden gelen isteğin işlenmesi şu şekilde gerçekleşir:

  1. 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'in C'si, [Front Controller, Contrôleur, Action] dizesidir. İstenen eylemi işleyebilecek hiçbir denetleyici yoksa, web sunucusu istenen URL'in bulunamadığını bildirir.
  1. İşleme
  • 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] parametreleri
    • 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. İstemcinin 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 ([3]) görüntülenmesini ister. 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 ([3]) görüntülenmesini isteyecektir;
  1. yanıt - seçilen V görünümü, eylemin oluşturduğu M modelini 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.

Şimdi, web mimarisi MVC 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, çok katmanlı bir mimari söz konusudur, ancak web katmanı MVC modelini uygulamamaktadır.

Örneğin, .NET ortamında yukarıdaki [Web] katmanıyukarıdaki [Web] katmanı, ASP.NET ve MVC ile uygulanabilir ve böylece MVC türünde bir [Web] katmanına sahip katmanlı bir 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.

1.6. İlk Spring projesi MVC

Bundan itibaren, Spring için özelleştirilmiş bir Eclipse sürümü olan IDE Spring Tool Suite (STS) ile çalışacağız. [http://spring.io/guides] sitesi, Spring ekosistemini keşfetmek için başlangıç eğitimleri sunmaktadır. Bunlardan birini takip ederek, bir Spring MVC projesi için gerekli Maven yapılandırmasını öğreneceğiz.

Not: Projenin ayrıntılarını anlamak çoğu yeni başlayan için zor olacaktır. Bu önemli değildir. Bu ayrıntılar belgenin ilerleyen bölümlerinde açıklanmaktadır. Biz sadece adımları tekrarlayacağız.

1.6.1. Demo projesi

  • [1]'te, Spring kılavuzlarından birini içe aktarıyoruz;
  • [2]'e, [Serving Web Content] ö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;

Projeyi, öncelikle Maven yapılandırmasını inceleyelim.

1.6.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-serving-web-content</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.9.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</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-milestone</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestone</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 bir [<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-thymeleaf] artefaktı, MVC adlı bir Spring projesinin, [Thymeleaf] adlı bir görünüm motoruyla birlikte çalışması için gerekli kütüphaneleri beraberinde getirir. Bu artefakt, gömülü bir Tomcat sunucusunun kütüphaneleri 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 sunucusunun arşivleri görülmektedir.

Spring Boot, Spring ekosisteminin bir dalıdır ([http://projects.spring.io/spring-boot/]). Bu proje, Spring projelerinin yapılandırma işini en aza indirmeyi amaçlamaktadır. Bunun için Spring Boot, projenin Classpath'inde bulunan bağımlılıklardan yola çıkarak otomatik yapılandırma gerçekleştirir. Spring Boot, kullanıma hazır birçok bağımlılık sağlar. Böylece, önceki Maven projesinde bulunan [spring-boot-starter-thymeleaf] bağımlılığı, [Thymeleaf] görünüm motorunu kullanan bir Spring uygulamasına MVC gerekli tüm bağımlılıkları getirir. Bu iki özellik sayesinde:

  • kullanıma hazır bağımlılıklar;
  • bu bağımlılıklar ve "makul" varsayılan değerler temelinde yapılan otomatik yapılandırma sayesinde, çok kısa sürede çalışır durumda bir Spring MVC uygulaması elde edilebilir. Burada incelenen proje de buna bir örnektir;

1.6.3. Bir Spring MVC uygulamasının mimarisi

Spring MVC, MVC olarak bilinen mimari modelini (Model – Görünüm – Denetleyici) uygular:

Bir istemciden gelen isteğin işlenmesi şu şekilde gerçekleşir:

  1. istek - istenen URL'ler http://machine:port/contexte/Action/param1/param2/....?p1=v1&p2=v2&... biçimindedir. [Dispatcher Servlet], gelen URL'leri işleyen Spring sınıfıdır. Bu sınıf, URL'i işlenmesi gereken eyleme "yönlendirir". Bu eylemler, [Contrôleurs] olarak adlandırılan belirli sınıfların yöntemleridir. Burada MVC'in C kısmı, [Dispatcher Servlet, Contrôleur, Action] dizesidir. Gelen URL'i işlemek için herhangi bir eylem yapılandırılmamışsa, [Dispatcher Servlet] servleti, istenen URL'in bulunamadığını bildirir (404 hatası NOT FOUND);
  2. işleme
  • seçilen eylem, [Dispatcher Servlet] servletinin kendisine ilettiği parami parametrelerini kullanabilir. Bu parametreler çeşitli kaynaklardan gelebilir:
    • [/param1/param2/...]'in URL'teki yolundan,
    • URL,'in [p1=v1&p2=v2] parametrelerinden
    • tarayıcının isteğiyle birlikte gönderdiği parametrelerden;
  • Kullanıcının isteğinin işlenmesinde, eylem [metier] [2b] katmanına ihtiyaç duyabilir. Müşterinin isteği işlendikten sonra, bu eylem ç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 ([3]) görüntülenmesini ister. 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];
  1. 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.

İncelediğimiz projede bu farklı unsurları inceleyeceğiz.

1.6.4. C denetleyicisi

  

İçe aktarılan uygulama aşağıdaki denetleyiciye sahiptir:


package hello;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class GreetingController {

    @RequestMapping("/greeting")
    public String greeting(@RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
        model.addAttribute("name", name);
        return "greeting";
    }

}
  • 8. satır: [@Controller] 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. Bir Spring denetleyicisi bir singleton'dur. Tek bir örnek olarak oluşturulur;
  • 11. satır: [@RequestMapping] anotasyonu, yöntemin işlediği URL'i belirtir; buradaki URL, [/greeting]'tir. Daha sonra göreceğiz ki bu URL'in parametreleri ayarlanabilir ve bu parametreleri geri almak mümkündür;
  • 12. satır: Yöntem iki parametre kabul eder:
    • [String name]: Bu parametre, işlenen sorgudaki [name] adlı bir parametre tarafından başlatılır; örneğin, [/greeting?name=alfonse]. Bu parametre isteğe bağlıdır ([required=false]) ve mevcut olmadığında, [name] parametresi 'World' değerini alır ([defaultValue="World"]),
    • [Model model] bir görünüm modelidir. Boş olarak gelir ve onu doldurmak eylemin (greeting yöntemi) görevidir. Eylemin görüntüleyeceği görünüme aktarılacak olan bu modeldir. Dolayısıyla bu bir görünüm modelidir;
  • 13. satır: [name]'in değeri görünüm şablonuna eklenir. [Model] sınıfı bir sözlük gibi davranır;
  • 14. satır: Yöntem, oluşturulan şablonu görüntülemesi gereken görünümün adını döndürür. Görünümün tam adı, [Thymeleaf]'in yapılandırmasına bağlıdır. Bu yapılandırma yoksa, burada görüntülenen görünüm [/templates/greeting.html] olacaktır; ya da [templates] klasörü, projenin Classpath kök dizininde bulunmalıdır;

Eclipse projemize bir göz atalım:

[src/main/java] ve [src/main/resources] klasörlerinin içeriği, projenin Classpath'ine eklenecektir. [src/main/java] klasörüne ise Java kaynak kodlarının derlenmiş sürümleri eklenecektir. [src/main/resources] klasörünün içeriği ise herhangi bir değişiklik yapılmadan Classpath'e eklenir. Dolayısıyla, [templates] klasörünün [1] projesinin Classpath'inde yer alacağı görülmektedir.

Bunu, Eclipse'teki [Navigator] penceresinde [2-3] dosyasını kontrol ederek doğrulayabiliriz. [target] klasörü, projenin derlenmesi (build olarak adlandırılır) sonucunda oluşturulur. [classes] klasörü, Classpath'in kök dizinini temsil eder. Burada [templates] klasörünün mevcut olduğu görülür.

1.6.5. V görünümü

MVC dosyasında az önce C denetleyicisini ve M görünüm modelini inceledik. V görünümü burada aşağıdaki [greeting.html] dosyasıyla temsil edilmektedir:


<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <p th:text="'Hello, ' + ${name} + '!'" />
</body>
</html>
  • 2. satır: Thymeleaf etiketlerinin ad alanı;
  • 8. satır: bir Thymeleaf özniteliğine sahip <p> (paragraf) etiketi. [th:text] özniteliği, paragrafın içeriğini belirler. Dize içinde [${name}] ifadesi bulunmaktadır. Bu, görünüm şablonundaki [name] özniteliğinin değerinin alınmak istendiği anlamına gelir. Ancak hatırlayacağımız üzere, bu öznitelik şablona şu eylemle eklenmiştir:

model.addAttribute("name", name);

İlk parametre özniteliğin adını, ikincisi ise değerini belirler.

1.6.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);
    }

}
  • 11. satır: Sınıf, konsol uygulamalarına özgü bir [main] yöntemi ile çalıştırılabilir. 12. satırdaki [SpringApplication] sınıfı, bağımlılıklar arasında bulunan Tomcat sunucusunu başlatacak ve web hizmetini bu sunucuya dağıtacaktır;
  • 4. satır: [SpringApplication] sınıfının [Spring Boot] projesine ait olduğu görülmektedir;
  • 12. satır: ilk parametre projeyi yapılandıran sınıftır, ikincisi ise olası parametrelerdir;
  • 8. satır: [@EnableAutoConfiguration] anotasyonu, Spring Boot'tan projenin yapılandırılmasını ister;
  • 7. satır: [@ComponentScan] anotasyonu, [Application] sınıfını içeren klasörün Spring bileşenlerini aramak üzere taranmasını sağlar. Bir bileşen bulunacaktır: [GreetingController] sınıfı, [@Controller] anotasyonuna sahiptir ve bu da onu bir Spring bileşeni yapar;

Projeyi çalıştıralım:

 

Aşağıdaki konsol günlükleri elde edilir:

.   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.1.9.RELEASE)

2014-11-27 16:48:12.567  INFO 3908 --- [           main] hello.Application                        : Starting Application on Gportpers3 with PID 3908 (started by ST in D:\data\istia-1415\spring mvc\dvp\gs-serving-web-content-complete)
2014-11-27 16:48:12.723  INFO 3908 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@1a38c59b: startup date [Thu Nov 27 16:48:12 CET 2014]; root of context hierarchy
2014-11-27 16:48:13.813  INFO 3908 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'beanNameViewResolver': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]]
2014-11-27 16:48:15.247  INFO 3908 --- [           main] .t.TomcatEmbeddedServletContainerFactory : Server initialized with port: 8080
2014-11-27 16:48:15.574  INFO 3908 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2014-11-27 16:48:15.575  INFO 3908 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/7.0.56
2014-11-27 16:48:15.955  INFO 3908 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2014-11-27 16:48:15.955  INFO 3908 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3236 ms
2014-11-27 16:48:16.918  INFO 3908 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]
2014-11-27 16:48:16.922  INFO 3908 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2014-11-27 16:48:17.354  INFO 3908 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-11-27 16:48:17.679  INFO 3908 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/greeting],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String hello.GreetingController.greeting(java.lang.String,org.springframework.ui.Model)
2014-11-27 16:48:17.681  INFO 3908 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2014-11-27 16:48:17.682  INFO 3908 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[text/html],custom=[]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest)
2014-11-27 16:48:17.696  INFO 3908 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] türündeki işleyiciye
2014-11-27 16:48:17.697  INFO 3908 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] QZXW2HTML türündeki işleyici BW2NsYXNzIG9yZy5zcHJpbmdmcmFtZXdvcmsud2ViLnNlcnZsZXQucmVzb3VyY2UuUmVzb3VyY2VIdHRwUmVxdWVzdEhhbmRsZXJdZQX
2014-11-27 16:48:18.159  INFO 3908 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2014-11-27 16:48:18.491  INFO 3908 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080/http
2014-11-27 16:48:18.493  INFO 3908 --- [           main] hello.Application                        : Started Application in 6.833 seconds (JVM running for 8.658)
  • 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: [hello.GreetingController.greeting] yöntemi ve bu yöntemin işlediği URL [/greeting] tespit edildi;

Web uygulamasını test etmek için URL ve [http://localhost:8080/greeting] yöntemlerini çağırıyoruz:

 

Sunucu tarafından gönderilen HTTP başlıklarını incelemek faydalı olabilir. Bunun için, [Advanced Rest Client] adlı Chrome eklentisini kullanacağız (bkz. paragraf 9.6):

  • [1]'te, istenen URL;
  • [2]'te, GET yöntemi kullanıldı;
  • [3]'te, sunucu HTML biçiminde bir yanıt gönderdiğini belirtti;
  • [4]'te, yanıt HTML;
  • [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 HTML yanıtı;

Uygulamayı durdurmak için:

1.6.7. Çalıştırılabilir arşiv oluşturma

Eclipse dışında çalıştırılabilir bir arşiv oluşturmak mümkündür. Gerekli yapılandırma [pom.xml] dosyasında bulunur:


    <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>
  • 7-10. satırlar, çalıştırılabilir arşivi oluşturacak eklentiyi tanımlar;
  • 2. satır ise projenin çalıştırılabilir sınıfını tanımlar;

İşlem şu şekilde yapılır:

  • [1]'te: bir Maven hedefi çalıştırılır;
  • [2]'e: iki hedef (goal) vardır: [clean], Maven projesinden [target] klasörünü silmek için; [package], bu klasörü yeniden oluşturmak içindir;
  • [3]'te: Oluşturulan [target] klasörü bu klasöre yerleştirilecektir;
  • [4]'e: hedef oluşturulur;

Not: Oluşturma işleminin başarılı olması için, STS tarafından kullanılan JVM'in bir JDK olması gerekir. [Window / Preferences / Java / Installed JREs]:

 

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 bu eklentidir.

[INFO] --- spring-boot-maven-plugin:1.1.9.RELEASE:repackage (default) @ gs-serving-web-content ---

Konsol aracılığıyla oluşturulan klasöre girilir:


gs-serving-web-content-complete\target>dir
 ...

 Répertoire de D:\data\istia-1415\spring mvc\dvp\gs-serving-web-content-complete
\target

27/11/2014  17:07    <DIR>          .
27/11/2014  17:07    <DIR>          ..
27/11/2014  17:07    <DIR>          classes
27/11/2014  17:07    <DIR>          generated-sources
27/11/2014  17:07        13 419 551 gs-serving-web-content-0.1.0.jar
27/11/2014  17:07             3 522 gs-serving-web-content-0.1.0.jar.original
27/11/2014  17:07    <DIR>          maven-archiver
27/11/2014  17:07    <DIR>          maven-status
  • 12. satır: oluşturulan arşiv;

Bu arşiv şu şekilde çalıştırılır:


gs-serving-web-content-complete\target>java -jar gs-serving-web-content-0.1.0.jar

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.1.9.RELEASE)

2014-11-27 17:14:50.439  INFO 8172 --- [           main] hello.Application                        : Starting Application on Gportpers3 with PID 8172 (D:\data\istia-1415\spring mvc\dvp\gs-serving-web-content-complete\target\gs-serving-web-content-0.1.0.jar started by ST in D:\data\istia-1415\spring mvc\dvp\gs-serving-web-content-complete\target)
2014-11-27 17:14:50.491  INFO 8172 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@12f4ec3a: startup date [Thu Nov 27 17:14:50 CET 2014]; root of context hierarchy

Not: Öncelikle Eclipse'te başlatılmış olabilecek web hizmetini durdurmanız gerekir (bkz. sayfa 17).

Artık web uygulaması başlatıldığına göre, bir tarayıcıyla erişilebilir:

 

1.6.8. Uygulamayı bir Tomcat sunucusuna dağıtma

Spring Boot, geliştirme modunda çok kullanışlı olsa da, üretim ortamındaki bir uygulama gerçek bir Tomcat sunucusuna dağıtılmalıdır. Bunun için aşağıdaki adımları izleyin:

[pom.xml] dosyasını aşağıdaki şekilde değiştirin:


<?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-serving-web-content</artifactId>
    <version>0.1.0</version>
    <packaging>war</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.9.RELEASE</version>
    </parent>

    <dependencies>
        <!-- Thymeleaf ortamı -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- WAR dosyası oluşturma -->
<!--         <bağımlılık>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </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-milestone</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestone</id>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>

</project>

Değişiklikler iki yerde yapılmalıdır:

  • 9. satır: Bir war arşivi (Web ARchive) oluşturulacağını belirtmek gerekir;
  • 24-28. satırlar: [spring-boot-starter-tomcat] artefaktına bir bağımlılık eklenmelidir. Bu artefakt, Tomcat'in tüm sınıflarını projenin bağımlılıkları arasına ekler;
  • 27. satır: Bu artefakt [provided]'tir, yani ilgili arşivler oluşturulan WAR dosyasına yerleştirilmeyecektir. Aslında bu arşivler, uygulamanın çalışacağı Tomcat sunucusunda bulunacaktır;

Aslında, projenin mevcut bağımlılıklarına bakıldığında, [spring-boot-starter-tomcat] bağımlılığının zaten mevcut olduğu görülür:

  

Dolayısıyla, bunu [pom.xml] dosyasına eklemeye gerek yoktur. Hatırlatma amacıyla yorum satırına ekledik.

Ayrıca web uygulamasını yapılandırmak 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]'te, proje Eclipse'te kayıtlı sunuculardan birinde çalıştırılır;
  • [2]'te, yukarıdan [Tomcat v8.0]'i seçin;

Bu işlem tamamlandıktan sonra, URL [http://localhost:8080/gs-rest-service/greeting/?name=Mitchell]'i bir tarayıcıda görüntüleyebiliriz:

 

Not: [tomcat] ve [tc Server Developer] sürümlerine bağlı olarak bu işlem başarısız olabilir. Örneğin, [Apache Tomcat 8.0.3 et 8.0.15] ile bu durum yaşanmıştır. Yukarıda kullanılan Tomcat sürümü [8.0.9] idi.

Artık bir WAR arşivi oluşturmayı biliyoruz. Bundan sonra, Spring Boot ve onun çalıştırılabilir JAR arşivi ile çalışmaya devam edeceğiz.

1.7. İkinci bir Spring projesi: MVC

1.7.1. Tanıtım 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. Bu belgede, oluşturacağımız hizmeti kısaca bir web hizmeti / jSON olarak adlandıracağım. Bir hizmet, belirli kurallara uyuyorsa Restful olarak adlandırılır. Ben bu kurallara uymaya çalışmadım.

Şimdi içe aktarılan projeyi, öncelikle Maven yapılandırmasını inceleyelim.

1.7.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.1.9.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 bir [<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.

1.7.3. Bir Spring hizmetinin mimarisi [web / jSON]

Spring MVC'in MVC modelini nasıl uyguladığını hatırlayalım:

Bir istemciden gelen isteğin işlenmesi şu şekilde gerçekleşir:

  1. istek - istenen URL'ler http://machine:port/contexte/Action/param1/param2/....?p1=v1&p2=v2&... biçimindedir [Dispatcher Servlet], gelen URL'leri işleyen Spring sınıfıdır. Bu sınıf, URL'i işlenmesi gereken eyleme "yönlendirir". Bu eylemler, [Contrôleurs] olarak adlandırılan belirli sınıfların yöntemleridir. Burada MVC'in C kısmı, [Dispatcher Servlet, Contrôleur, Action] dizesidir. Gelen URL'i işlemek için herhangi bir eylem yapılandırılmamışsa, [Dispatcher Servlet] servleti, istenen URL'in bulunamadığını bildirir (404 hatası NOT FOUND);
  2. işleme
  • seçilen eylem, [Dispatcher Servlet] servletinin kendisine ilettiği parami parametrelerini kullanabilir. Bu parametreler çeşitli kaynaklardan gelebilir:
    • URL'in [/param1/param2/...] yolundan,
    • URL,'in [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 [metier] 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];
  1. 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, jSON kütüphanesi tarafından jSON dizesine dönüştürülür;
  • [4b]'te, bu jSON dizesi tarayıcıya gönderilir;

1.7.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 nesnelerini 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 ve [/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 rekabetini 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.

1.7.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:

{"id":2,"content":"Hello, World!"}

veya

{"id":2,"content":"Hello, John!"}

1.7.6. Çalıştırma

  

[Application.java] sınıfı, projenin yürütülebilir sınıfıdır. Kodu şu şekildedir:


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.

1.7.7. Projenin çalıştırılması

Projeyi çalıştıralım:

 

Aşağıdaki konsol günlükleri elde edilir:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.1.9.RELEASE)

2014-11-28 15:22:55.005  INFO 3152 --- [           main] hello.Application                        : Starting Application on Gportpers3 with PID 3152 (started by ST in D:\data\istia-1415\spring mvc\dvp-final\gs-rest-service)
2014-11-28 15:22:55.046  INFO 3152 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@62e136d3: startup date [Fri Nov 28 15:22:55 CET 2014]; root of context hierarchy
2014-11-28 15:22:55.762  INFO 3152 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'beanNameViewResolver': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]]
2014-11-28 15:22:56.567  INFO 3152 --- [           main] .t.TomcatEmbeddedServletContainerFactory : Server initialized with port: 8080
2014-11-28 15:22:56.738  INFO 3152 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2014-11-28 15:22:56.740  INFO 3152 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/7.0.56
2014-11-28 15:22:56.869  INFO 3152 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2014-11-28 15:22:56.870  INFO 3152 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1827 ms
2014-11-28 15:22:57.478  INFO 3152 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]
2014-11-28 15:22:57.481  INFO 3152 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2014-11-28 15:22:57.685  INFO 3152 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-11-28 15:22:57.879  INFO 3152 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/greeting],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public hello.Greeting hello.GreetingController.greeting(java.lang.String)
2014-11-28 15:22:57.884  INFO 3152 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2014-11-28 15:22:57.885  INFO 3152 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[text/html],custom=[]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest)
2014-11-28 15:22:57.906  INFO 3152 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] türündeki işleyiciye
2014-11-28 15:22:57.907  INFO 3152 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] QZXW2HTML türündeki işleyici üzerine BW2NsYXNzIG9yZy5zcHJpbmdmcmFtZXdvcmsud2ViLnNlcnZsZXQucmVzb3VyY2UuUmVzb3VyY2VIdHRwUmVxdWVzdEhhbmRsZXJdZQX
2014-11-28 15:22:58.231  INFO 3152 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2014-11-28 15:22:58.318  INFO 3152 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080/http
2014-11-28 15:22:58.319  INFO 3152 --- [           main] hello.Application                        : Started Application in 3.788 seconds (JVM running for 4.424)
  • 13. satır: Tomcat sunucusu 8080 numaralı bağlantı noktasında başlatılır (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 dizesi başarıyla alınır.

Not: Bu örnek, Eclipse'in yerleşik tarayıcısında çalışmadı.

Sunucu tarafından gönderilen HTTP başlıklarını incelemek ilginç olabilir. Bunun için, [Advanced Rest Client] adlı Chrome eklentisini kullanacağız (bkz. Ekler, paragraf 9.6):

  • [1]'te, istenen URL;
  • [2]'e, GET yöntemi kullanılı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ı;

1.7.8. Çalıştırılabilir bir arşiv oluşturma

Önceki projede yaptığımız gibi, çalıştırılabilir bir arşiv oluşturuyoruz:

  • [1]'te: 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 bu eklentidir.

[INFO] --- spring-boot-maven-plugin:1.1.0.RELEASE:repackage (default) @ gs-rest-service ---

Bir konsol kullanarak 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)
...

Not: Öncelikle Eclipse'te başlatılmış olabilecek web hizmetini durdurmanız gerekir (bkz. paragraf 1.6.6).

Web uygulaması artık çalışır durumda olduğuna göre, bir tarayıcıyla bu uygulamaya erişebiliriz:

 

1.7.9. 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 yapılır:

  

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

 

1.8. Conclusion

İki tür Spring projesi ekledik:

  • web uygulamasının tarayıcıya bir HTML akışı gönderdiği bir proje. Bu akış, [Thymeleaf] görünüm motoru tarafından oluşturulur;
  • web uygulamasının tarayıcıya bir jSON akışı gönderdiği bir proje;

İlk durumda, proje için iki Maven bağımlılığı gereklidir:


    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.9.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
</dependencies>

İkinci durumda ise Maven bağımlılıkları şunlardır:


    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.9.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
</dependencies>

Bu yapılandırmaların zincirleme olarak getirdiği bağımlılıklar çok fazladır ve bunların çoğu gereksizdir. Uygulamanın devreye alınması için, projeye gerekli olan bağımlılıkların yer aldığı manuel bir Maven yapılandırması kullanılacaktır.

Şimdi, iki temel kavramı tanıtarak web programlamasının temellerine geri döneceğiz:

  • tarayıcı ile bir web uygulaması arasındaki HTTP (HyperText Aktarım Protokolü) iletişimi;
  • tarayıcının aldığı bir sayfayı görüntülemek için yorumladığı HTML (HyperText İşaretleme Dili);