https://buraksenyurt.com/Burak Selim Şenyurt - Spring Boot2020-12-19T20:21:30+00:00Matematik Mühendisi Bir Bilgisayar Programcısının NotlarıBurak Selim SenyurtBlogEngine.Net Syndication Generatorhttps://buraksenyurt.com/opml.axdBurak Selim SenyurtMatematik Mühendisi Bir Bilgisayar Programcısının Notlarıtr-TRBurak Selim Şenyurt0.0000000.000000https://buraksenyurt.com/post/spring-boot-ile-eski-usul-soap-based-xml-web-service-yazmak-ne-kadar-zor-olabilirSpring Boot ile Eski Usül Soap Based XML Web Service Yazmak Ne Kadar Zor Olabilir?2020-10-26T17:51:00+00:00bsenyurt<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/39/xmlheimdall.png" alt="" align="right" />Kısa bir süre önce değerli bir çalışma arkadaşım kullanmaya çalıştığı Java tabanlı XML Web servis ile epeyce sorun yaşadı. Söz konusu servisi .Net tarafından tüketmeye çalışıyordu ancak XML şeması da epeyce karmaşık olan servis iletişim noktasında şema adlarına kızıyor, header içeriğini beğenmiyor sürekli naz yapıyordu. Arkadaşım allem etti kallem etti sorunun altından girip üstünden çıktı ve nihayetinde çözdü. Bu olaylara kısmen tanıklık ettikten sonra "yahu Java tarafında XML Web Service geliştirmek şimdilerde daha bir kolay değil midir!?" diye söylenmeye başladım. Yol doğal olarak beni Spring Boot'a ve resmi dokümantasyonuna götürdü.</p>
<p>Şimdiki amacımız yönergeleri takip ederek basit bir XML Web servisin Spring Boot çerçevesinde nasıl yazıldığını deneyimlemek. Günümüzde neredeyse tüm servisler REST, gRPC, OData ve benzeri kavramlar üzerinde konuşuyor olsalar da özellikle kurumsal çapta uzun yıllardır var olan pek çok uygulama halen daha SOAP<em>(Simple Object Access Protocol)</em> temelli XML Web servislerini kullanıyor. Nitekim SOAP protokolünün de dezavantajları kadar avantajlı olduğu taraflar var. Ancak konumuz bunu tartışmak yerine bir pratik yapmak.</p>
<p>Örneğimizde bir firmanın belli bir bölgedeki müşteri segmentine ait birkaç özet bilgisinin döndürüleceği kobay bir servis operasyonu söz konusu olacak. Mesela bölge ve müşteri segmenti seviyesini alan ve geriye o bölgedeki toplam işlem hacmi, müşteri memnuniyeti oranı, strateji özeti, temsilci sayısı gibi detayları döndüren bir operasyon pekala işe yarayabilir. Daha önceden baktığımız diğer Spring Boot çalışmalarında da olduğu gibi işe <a href="https://start.spring.io/">https://start.spring.io/</a> adresine gidip projeyi üreterek başlamak gerekiyor. Uygulamanın birkaç bağımlılığı var. Spring Web, Spring Web Services ve wsdl4j<em>(Java için WSDL kullanıcığımızı bildireceğimiz dependency)</em> Detaylar için kodların da ye aldığı SkyNet <a href="https://github.com/buraksenyurt/skynet/tree/master/No%2039%20-%20SOAP%20Based%20Web%20Service%20with%20Spring/src/services" target="_blank">github reposuna</a> uğrayabilir ve pom.xml dosya içeriğine bakabilirsiniz.</p>
<p>Yine belirtmem de yarar var; örneği Heimdall<em>(Ubuntu-20.04)</em> üzerine ve Visual Studio Code arabirimiyle geliştirmekteyim ;)</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/39/Screenshot_01.png" alt="" /></p>
<p>Şimdi de gerekli dosyalarımızı oluşturalım.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false"># SOAP Based Web Servisinin olmassa olmazı tabii ki içereceği operasyon
# ve bu operasyonların kullanacağı veri tiplerinin tanımlandığı
# XSD - XML Schema Definition dosyası (uygulama klasöründeyken)
# Firmanın belli bir şehirdeki müşterilerine ait istatistiki özet getirecek bir servisi olduğunu varsayalım
# XSD ile biraz haşırneşir olmak gerekiyor
touch src/main/resources/customer.xsd
# XSD şeması hazır. Request, Response verimizi tanımladık
# Kodda kolay kullanabilmek için onu karşılayacak bir Java sınıfı da gerekiyor
# Bunun için JAXB (Java Architecture for XML Binding) plug-in'ini kullanıyoruz
# XSD yi karşılayacak POJO (Plain Old Java Object) sınıfını otomatik üretiyor
# Ancak bu destek için pom.xml dosyasında bir plug-in tanımı eklemeliyiz (jaxb2-maven-plugin artifact'ini bulun)
# plug-in eklendikten sonra target klasöründe XSD'ye bağlı sınıflar otomatik olarak üretilir
# Şema hazır. Şema karşılığı POJO hazır. Peki ya asıl işi yapan sınıf.
# Veri odaklı bir iş söz konusu olduğu için bir Repository tasarlanması öneriliyor
touch src/main/java/com/bemewe/services/CustomerRepository.java
# Serivse gelecek SOAP talepleri çok doğal olarak kod tarafında bir sınıfla karşılanmalı
touch src/main/java/com/bemewe/services/CustomerEndpoint.java
# Repository ve Endpoint sınıfları hazır ancak yeterli değil.
# Web Service konfigurasyonu için de bir dosya kullanacağız
touch src/main/java/com/bemewe/services/ServiceConfiguration.java</pre>
<p>XSD şeması aslında okunabilir bir formatta. Servisin request ve response mesajları getCustomerUsageRequest ve getCustomerUsageResponse elementleri ile tanımlanıyor. Bu mesajların içeriğinde ilkel<em>(primitive, xs önekli olanlar)</em> ve karmaşık<em>(complex, tns önekli alanlar)</em> tipler kullanıyoruz. Yani mesajın hangi veri yapılarından oluşacağını XSD üzerinde tanımlıyoruz. Aynen aşağıdaki kod parçasında görüldüğü gibi.</p>
<pre class="brush:html;auto-links:false;toolbar:false" contenteditable="false"><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://bemewe.com/services"
targetNamespace="http://bemewe.com/services" elementFormDefault="qualified">
<xs:element name="getCustomerUsageRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="region" type="xs:string"/>
<xs:element name="size" type="tns:size"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:simpleType name="size">
<xs:restriction base="xs:string">
<xs:enumeration value="Light"/>
<xs:enumeration value="Average"/>
<xs:enumeration value="AverageHigh"/>
<xs:enumeration value="MVP"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="getCustomerUsageResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="usageSummary" type="tns:usageSummary"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="usageSummary">
<xs:sequence>
<xs:element name="totalTransactionVolume" type="xs:float"/>
<xs:element name="size" type="tns:size"/>
<xs:element name="avgCustomerSatisfaction" type="xs:float"/>
<xs:element name="numberOfRepresentetive" type="xs:int"/>
<xs:element name="evaluation" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema></pre>
<p>XSD içerisindeki tanımlamarın kod tarafında karşılığı olmazsa kullanmak oldukça zor olabilir. Bu nedenle pom.xml dosyası içerisinde jaxb2-maven-plugin tanımı söz konusu. Bu eklenti sonrası XSD'den otomatik olarak gerekli sınıflar üretilecektir. Örnekte yer alan servis operasyonumuzu CustomerRepository tipinde aşağıdaki gibi yazabiliriz.</p>
<pre class="brush:java;auto-links:false;toolbar:false" contenteditable="false">package com.bemewe.services;
import org.springframework.stereotype.Component;
/*
Sembolik repository sınıfı. Bu bileşeni Service Endpoint sınıfı kullanıyor.
*/
@Component
public class CustomerRepository {
/*
* Servisin sunduğu fonksiyonelliklerden birisi belli bir bölge için müşteri
* segmentine göre istatistiki bilgi döndürmek.
*
* UsageSummary ve Size tipleri tahmin edeceğiniz üzere XSD'den otomatik
* üretilen JAXB türleri.
*/
public UsageSummary GetSummaryByRegion(String region, Size size) {
UsageSummary summary = new UsageSummary();
summary.setAvgCustomerSatisfaction(76.50F);
summary.setNumberOfRepresentetive(12);
summary.setTotalTransactionVolume(15000000.99F);
summary.setSize(size);
summary.setEvaluation("Daha agresit satış stratejilerine ihtiyacımız var");
return summary;
}
}</pre>
<p>Aslında Repository için Interface kullanımını tercih etsek DI kurallarına daha uygun olur mu dersiniz?. Gelelim bu Repository'yi kullanan ve SOAP isteklerini karşılayacak olan Endpoint sınıfına.</p>
<pre class="brush:java;auto-links:false;toolbar:false" contenteditable="false">package com.bemewe.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
/*
Endpoint annotation ile sınıfın bir servis endpoint olarak çalışacağını belirttik.
(Kime belirttik derseniz cevap Spring WS modülü)
Autowired ise constructor'ın Spring'in DI mekanizmasına otomatik olarak bağladı.
*/
@Endpoint
public class CustomerEndpoint {
private CustomerRepository _repository;
@Autowired
public CustomerEndpoint(CustomerRepository repository) {
_repository = repository;
}
/*
* Bu Endpoint üzerinden sunduğumuz operasyonu karşılayacak olan metot.
* Gelen XML paketindeki hangi namespace ve operasyon bilgisine cevaben çalışacağını @PayloadRoot ile belirttik.
*
* Gelen XML paketi metodun request parametresine bağlanacak. Bunu @RequestPayload ile bildiriyoruz.
*
* Tam tersi metod çıktısınında cevaben dönecek XML paketinde map edileceğiniz @ResponsePayload ile belirtmekteyiz.
*
* setUsageSummary'nin UsageSummary'yi otomatik olarak nasıl alabildiğini merak etmiş olabilirsiniz.
* Plug-In ile üretilen GetCustomerUsageResponse sınıfı bu bilgiyi XSD içeriğinden alıp gerekli sınıf üretimini gerçekleştirdi.
*/
@PayloadRoot(namespace = "http://bemewe.com/services", localPart = "getCustomerUsageRequest")
@ResponsePayload
public GetCustomerUsageResponse getUsageSummary(@RequestPayload GetCustomerUsageRequest request) {
UsageSummary summary = _repository.GetSummaryByRegion(request.getRegion(), request.getSize());
GetCustomerUsageResponse response = new GetCustomerUsageResponse();
response.setUsageSummary(summary);
return response;
}
}</pre>
<p>Endpoint'te hazır ancak yeterli değil. Konfigurasyon için bir adaptör eklememiz de lazım. Adaptörümüz XSD dosyasını da baz alarak servisin çalışma zamanı kaydını açmakta. Bunu yaparken koddanda göreceğiniz gibi WSDL standardını da belirleyebiliyoruz. Örnekte 1.1 standardını baz almaktayız. 1.2'de sorun yaşadığımı hatırlıyorum. Ancak çözüm üreten olursa lütfen yorumlarını esirgemesin.</p>
<pre class="brush:java;auto-links:false;toolbar:false" contenteditable="false">package com.bemewe.services;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ws.config.annotation.EnableWs;
import org.springframework.ws.config.annotation.WsConfigurerAdapter;
import org.springframework.ws.transport.http.MessageDispatcherServlet;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.XsdSchema;
/*
WS Config dosyası olduğunu belirtiyoruz.
*/
@EnableWs
@Configuration
public class ServiceConfiguration extends WsConfigurerAdapter {
@Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/stats/*");
}
/*
* WSDL 1.1 standartlarına göre schema özelliklerini ayarlıyoruz. PortTipinin
* adını, Uri, namespace...
*/
@Bean(name = "customers")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema serviceSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("CustomerPort");
wsdl11Definition.setLocationUri("/stats");
wsdl11Definition.setTargetNamespace("http://bemewe.com/services");
wsdl11Definition.setSchema(serviceSchema);
// wsdl11Definition.setCreateSoap12Binding(true); //SOAP 1.2 Binding oluşturmayı deneyeyim dedim
return wsdl11Definition;
}
@Bean
public XsdSchema countriesSchema() {
return new SimpleXsdSchema(new ClassPathResource("customer.xsd"));
}
}</pre>
<p>Kodlama faslı tamamlandıktan sonra örneği maven üzerinden çalıştırıp http://localhost:8080/stats/customers.wsdl adresinden ilgili WSDL dosyasına<em>(yani servis sözleşmesine)</em> ulaşmayı deneyebiliriz.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">./mvnw spring-boot:run</pre>
<p>İlk etapta WSDL içeriğine ulaşabilmek beni olduğu kadar sizi de mutlu edecektir diye düşünüyorum. Artık elimizde SOAP standartlarında operasyon desteği sunabilen bir service var.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/39/Screenshot_02.png" alt="" /></p>
<p>Tabii bunu birde tüketmek gerekiyor. SoapUI bu anlamda ideal ve pratik bir çözüm. Ne varki ben ilk Request denemesinden sonra <strong>"Implementation of JAXB-API has not been found on module path or classpath"</strong> şeklinde bir hata aldım. Çözümü araştırdığımda konuya çalıştığım tarih itibariyle jaxb'nin aşağıdaki paketini kullanmam önerildi. Tabii siz bunu denerken aynı problemle karşılaşmayabilirsiniz.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.3</version>
</dependency></pre>
<p>POM.xml üzerinde gerekli değişikliği yaptıktan sonra ise ilk talebimizi gönderebiliriz.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://bemewe.com/services">
<soapenv:Header/>
<soapenv:Body>
<ser:getCustomerUsageRequest>
<ser:region>East Dublin</ser:region>
<ser:size>Average</ser:size>
</ser:getCustomerUsageRequest>
</soapenv:Body>
</soapenv:Envelope></pre>
<p>Aşağıdaki sonucu almamız gerekiyor.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/39/Screenshot_03.png" alt="" /></p>
<h2>Peki Ya .Net Core Tarafı!?</h2>
<p>Aslında SOAP talebini HttpClient ve benzeri tipler ile yollayıp almak mümkün. Ancak ilk sürümlerinden beri .Net tarafında geliştirme yapanlar wsdl ve svcutil gibi araçların getirdiği kolaylıkları bilirler. Kullanmak istediğimiz servis için .Net tarafında proxy sınıfını oluşturmak kodlamada işimizi epey kolaylaştırıyor<em>(du)</em>. Sorun şu ki SOAP tabanlı web servisler özellikle protokolün hantallığı dolayısıyla artık daha az kullanılmakta. Kurumsal projelerde var olanlar genellikle evrilmeye çalışıyor ve yerlerini hafif orta siklet Web API'lere bırakıyorlar. Yine de .Net Core tarafında bu tip servisleri tüketmek istediğimizde elimizde Visual Studio varsa servis referansını ekleyerek ilerlemek mümkün. Bununla birlikte dotnet-svcutil aracına başvurulabiliriz ama o da sistemde .Net Core 2.1 gerektiriyor<em>(.Net 5 dünyasında durum nasıl bunu henüz incelemedim. Bilen varsa lütfen yorumlarını esirgemesin)</em> Bununla birlikte SoapCore gibi üçüncü parti Nuget paketleri de alternatifler arasında yer alıyor.</p>
<p>Şimdilik benden bu kadar ancak sizin için iki güzel sorum var ;) Sizce Soap Response mesajında N sayıda nesne içerecek bir koleksiyon döndürebilir miyiz; döndürebilirsek bunun için XSD'de nasıl bir değişiklik yapmamız gerekir. İkinci olarak customer.xsd için üretilen JAXB dosyalarının nerede olduğuna bakar mısınız? Bu sorulara ek olarak örneği zenginleştirmek elbette elinizde. Söz gelimi CustomerRepository üstünden gerçek bir veritabanına<em>(MongoDB Container olabilir)</em> bağlanıp ilgili istatistiklerin oradan gelmesini sağlayabilir veya servisi SOAP 1.2 standardına uyumlu hale getirebilirsiniz. Böylece geldik bir SkyNet derlememizin daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>2020-10-26T17:51:00+00:00javaspring bootxmlxml web servicesoapwsdldependency injectionservice discoverysoapuibsenyurtKısa bir süre önce değerli bir çalışma arkadaşım kullanmaya çalıştığı Java tabanlı XML Web servis ile epeyce sorun yaşadı. Söz konusu servisi .Net tarafından tüketmeye çalışıyordu ancak XML şeması da epeyce karmaşık olan servis iletişim noktasında şema adlarına kızıyor, header içeriğini beğenmiyor sürekli naz yapıyordu. Arkadaşım allem etti kallem etti sorunun altından girip üstünden çıktı ve nihayetinde çözdü. Bu olaylara kısmen tanıklık ettikten sonra "yahu Java tarafında XML Web Service geliştirmek şimdilerde daha bir kolay değil midir!?" diye söylenmeye başladım. Yol doğal olarak beni Spring Boot'a ve resmi dokümantasyonuna götürdü...https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=316cf51c-8ba6-42a6-b531-464ba701f1c90https://buraksenyurt.com/trackback.axd?id=316cf51c-8ba6-42a6-b531-464ba701f1c9https://buraksenyurt.com/post/spring-boot-ile-eski-usul-soap-based-xml-web-service-yazmak-ne-kadar-zor-olabilir#commenthttps://buraksenyurt.com/syndication.axd?post=316cf51c-8ba6-42a6-b531-464ba701f1c9https://buraksenyurt.com/post/spring-boot-ile-postgresql-kullanan-basit-bir-web-uygulamasi-gelistirmekSpring Boot ile PostgreSQL Kullanan Basit Bir Web Uygulaması Geliştirmek2020-10-19T07:20:00+00:00bsenyurt<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/31/category.png" alt="" align="right" />Spring Boot maceralarımız hız kesmeden devam ediyor. Bu sefer PostgreSQL veritabanını kullanan bir Web uygulamasını resmi dokümandan da yararlanarak geliştirmeye çalışacağız. Örneğimizde veritabanı olarak PostgreSQL kullanabiliriz. Her zaman olduğu gibi sisteme kurmamız şart değil. Pekala Docker imajından yararlanabiliriz. Kurgumuz basit bir MVC düzeneği olacak. Statik bir web sayfası dışında listeleme ve yeni kategori ekleme adımlarında şablonlardan<em>(templates)</em> faydalanacağız. Kategorileri ifade eden bir POJO sınıfımız olacak. PostgreSQL bağımlılığı kapsamında temel CRUD operasyonlarının tamamı Spring Boot'e ekleyeceğimiz bağımlılık sayesinde zaten hazır gelecek. Bunu kategori türüne uygulamak içinse generic bir Repository arayüzünden türetme yoluna gideceğiz.</p>
<p>Model ile View arasında köprü vazifesi gören Controller tipi, gerekli CRUD operasyonlarına erişmek için bir sözleşme arayüzünü kullanacak. Tahmin edeceğiniz üzere asıl operasyonları kullanması için Controller tipine ihtiyacı olan nesneyi, Dependency Injection mekanizması yardımıyla aktaracağız. Kod kısmını sırayla takip ettiğinizde konuyu daha iyi anlayacağınızdan eminim. Ben örneğimizi Heimdall<em>(Ubuntu-20.04)</em> üzerinde ve Visual Studio Code arabirimini kullanarak geliştirmekteyim. Ancak temel olarak tüm platformlarda benzer adımlarla ilerleyeceğinizi ifade edebilirim. Öyleyse gelin PostgreSQL Container'ını hazırlayarak çalışmamıza başlayalım.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false"># Container'ı Tokyo ismiyle ayağa kaldıralım
sudo docker run --name Tokyo -e POSTGRES_PASSWORD=P@ssw0rd -p 5432:5432 -d postgres
# Üzerinde bash açıp
sudo docker exec -it Tokyo bash
# PostgreSQL veritabanımızı oluşturalım
psql -U postgres
Create Database qworld;</pre>
<p>Veritabanı tarafı hazır. Sırada uygulamanın inşası var. İlk iş olarak <a href="https://start.spring.io/" target="_blank">Spring Initializr</a> adresine gidip POM içeriğini ve uygulamayı hazırlamak lazım. Veritabanı kullanımı için PostgreSQL Driver, temel web uygulaması kabiliyetleri için Spring Web, MVC şablonlarını kullanabilmek için Thymeleaf<em>(ki bunu bir türlü telaffuz edemiyorum)</em>, Object Relational Map aracı Hibernate içinse Spring Data JPA kütüphanelerini yüklüyoruz.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/31/Screenshot_01.png" alt="" /></p>
<p>Arabirimin ürettiği uygulamayı sisteme indirdikten sonra aşağıdaki adımları takip ederek senaryomuz için gerekli kod dosyalarını oluşturabiliriz.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">cd quote-world-web
# Model klasörü ve sınıfı
mkdir src/main/java/com/learning/quoteworldweb/model
touch src/main/java/com/learning/quoteworldweb/model/Category.java
# Repository klasörü ve sınıfı
mkdir src/main/java/com/learning/quoteworldweb/repository
touch src/main/java/com/learning/quoteworldweb/repository/CategoryRepository.java
# Servis sözleşmesi ve sınıfı
mkdir src/main/java/com/learning/quoteworldweb/service
touch src/main/java/com/learning/quoteworldweb/service/ICategoryService.java src/main/java/com/learning/quoteworldweb/service/CategoryService.java
# Controller klasörü ve sınıfı
mkdir src/main/java/com/learning/quoteworldweb/controller
touch src/main/java/com/learning/quoteworldweb/controller/CategoryController.java
# statik indeks sayfası
touch src/main/resources/static/index.html
# Kategorileri listelemek ve yeni bir tane eklemekte kullanılmak üzere iki template sayfası
touch src/main/resources/templates/allCategories.html src/main/resources/templates/newCategory.html
# Veritabanı tablo şeması ve örnek veri girişleri için ilgili sql dosyaları
# application.properties dosyasındaki ayarlara göre uygulama başlarken schema dosyasına bakıp eğer yoksa tabloyu oluşturmalı
# ve örnek verileri eklemeli
touch src/main/resources/schema.sql src/main/resources/data.sql</pre>
<p>Gelelim kodlarımıza. İlk olarak bir kategoriyi temsil eden POJO<em>(Plain Old Java Object)</em> sınıfı ile işe başlayalım<em>(Kodları sadece Copy-Paste yapmayın. Yorum satırlarını da mutlaka okuyun)</em></p>
<pre class="brush:java;auto-links:false;toolbar:false" contenteditable="false">package com.learning.quoteworldweb.model;
/*
Model sınıfımız. Yani Entity nesnemiz.
*/
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="categories") // Veritabanındaki categories tablosunu işaret ettiğini belirtiyoruz
public class Category{
// Tablodaki otomatik artan Identity alanımız
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private Integer quotecount;
// Varsayılan yapıcı metodumuz
public Category()
{
}
// Parametrik yapıcı metodumuz
public Category(Long id,String title,Integer quotecount)
{
this.id=id;
this.title=title;
this.quotecount=quotecount;
}
public Long getId()
{
return this.id;
}
public String getTitle()
{
return this.title;
}
public void setTitle(String value)
{
this.title=value;
}
public Integer getQuotecount()
{
return this.quotecount;
}
public void setQuotecount(Integer value)
{
this.quotecount=value;
}
}</pre>
<p>Varsayılan CRUD<em>(Create Read Update Delete)</em> operasyonlarını barındıran Repository sözleşmesini Category tipi için uygulayacağımızı sisteme bir şekilde söylememiz lazım. Bu nedenle generic CrudRepository'den türetilen bir Interface tipi söz konusu. Spring ile REST servisi geliştirdiğimiz örnekte de benzer bir yaklaşım olduğunu hatırlarsınız. Bu sözleşme içerisinde başka bir operasyon bildirimi henüz yok ancak dilerseniz genişletebilir ek fonksiyonellikleri de Repository'ye dahil edebilirsiniz.</p>
<pre class="brush:java;auto-links:false;toolbar:false" contenteditable="false">package com.learning.quoteworldweb.repository;
import com.learning.quoteworldweb.model.Category;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
/*
Standart CRUD operasyonlarını devraldığımız repository arayüzü.
*/
@Repository
public interface CategoryRepository extends CrudRepository<Category, Long> {
}</pre>
<p>Sırada Controller tarafından kullanılacak olan servis sözleşmesi var. Bu sözleşme Controller tipine DI üzerinden dahil edileceğinden bir Interface ve uyarlamasına ihtiyacımız var. ICategoryService ve CategoryService tiplerini aşağıdaki gibi geliştirebiliriz.</p>
<p><strong>ICategoryService;</strong></p>
<pre class="brush:java;auto-links:false;toolbar:false" contenteditable="false">package com.learning.quoteworldweb.service;
import java.util.List;
import com.learning.quoteworldweb.model.Category;
public interface ICategoryService {
List<Category> getAll();
Category getSingle(Long id);
Long add(Category category);
}</pre>
<p><strong>CategoryService;</strong></p>
<pre class="brush:java;auto-links:false;toolbar:false" contenteditable="false">package com.learning.quoteworldweb.service;
import java.util.List;
import com.learning.quoteworldweb.model.Category;
import com.learning.quoteworldweb.repository.CategoryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/*
Tüm kategorileri ve bir id değerine göre tek kategoriyi döndüren operasyonları içeren servis sınıfımız.
ICategoryService arayüzünü implemente ettiği için oradaki metodları ezmek zorundayız.
findAll ve findById gibi fonksiyonlar CategoryRepository isimli repository sınıfı üzerinden kullanılmaktadır.
add Metodunu ise yeni bir kategoriyi eklemek için kullanmaktayız.
*/
@Service
public class CategoryService implements ICategoryService {
@Autowired
private CategoryRepository repository; // Repository sınıfı enjekte ediliyor
@Override
public List<Category> getAll() {
return (List<Category>) repository.findAll();
}
@Override
public Category getSingle(Long id) {
return repository.findById(id).get();
}
@Override
public Long add(Category category){
Long id=repository.save(category).getId();
return id;
}
}</pre>
<p>Artık Controller için gerekli enstrümanlarımız hazır. Model ile View tarafını bağlayan CategoryController sınıfını aşağıdaki gibi yazarak çalışmamıza devam edelim.</p>
<pre class="brush:java;auto-links:false;toolbar:false" contenteditable="false">package com.learning.quoteworldweb.controller;
import java.util.List;
import com.learning.quoteworldweb.model.Category;
import com.learning.quoteworldweb.service.ICategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class CategoryController {
@Autowired
private ICategoryService categoryService; // Servis örneği enjekte ediliyor
@GetMapping("/allCategories") // Path tanımı
public String allCategories(Model model) {
var result = (List<Category>) categoryService.getAll(); // Enjekte edilen servis üstünden tüm kategori listesi
// çekildi
model.addAttribute("categoryList", result); // İlişkili model nesnesine attibute olarak ilgili liste eklendi
return "allCategories"; // Model nesnesi, thymeleaf sayesinde allCategories.html dosyasına bağlanacak
/*
* Model üstünden categoryList değişkeni ile geriye döndürdüğümüz bir liste söz
* konusu. allCategories.html dosyasında model'den gelen Category nesnelerini
* HTML'e nasıl bağladığımıza dikkat edin.
*
* Ayrıca yeni kategori eklemek için farklı bir view kullanılıyor. newCategory
* path'ine gelen talepler newCategory.html şablonunu döndürmekte.
*
* newCategory.html şablonundaki form HTTP Post ile yollandığındaysa PostMapping
* niteliği ile işaretlenmiş olan addCategory metodu çalışıyor. Form
* elementinden gelen Category nesne örneği,CategoryService aracılığıyla
* Postgresql veritabanına kayıt ediliyor. Sonrasında ana sayfaya yönlendirme
* yapıyoruz.
*/
}
@GetMapping("newCategory")
public String newCategory(Model model) {
model.addAttribute("category", new Category());
return "newCategory";
}
@PostMapping("/addCategory")
public String addCategory(Model model, @ModelAttribute("category") Category c) {
// TODO Exception durumunu kontrol edip bir HTTP Status mesajı vermeyi
// deneyebiliriz
categoryService.add(c);
return "redirect:/allCategories/";
}
}</pre>
<p>Bitti mi? Bitmedi :) Önyüzden ne haber? Oldukça ilkel HTML şabonlarımızı da sırasıyla yazalım. Web uygulamamızın giriş sayfası index.html. Sadece diğer sayfalara yönlendirme yapan linkler barındırıyor.</p>
<pre class="brush:html;auto-links:false;toolbar:false" contenteditable="false"><html>
<head>
<title>Alıntı Dünyası</title>
</head>
<body>
<div>
<h2>Alıntı Dünyasına Hoşgeldiniz</h2>
<a href="allCategories">Tüm Kategoriler için tıklayın</a><br/>
<a href="newCategory">Kategori eklemek için tıklayın</a>
</div>
</body>
</html></pre>
<p>Yeni bir kategori eklemek için kullanacağımız newCategory sayfasını da aşağıdaki gibi geliştirebiliriz. Burada tahmin edileceği üzere bir POST işlemi söz konusu. Hangi Action'a bağlanacağımız th:action ile belirtilirken kullanlacak model nesnesi de th:object bildirimleri ile belirtmekteyiz. Category alanları ile HTML elementlerini bağlarken ise th:field bildirimi devreye giriyor.</p>
<pre class="brush:html;auto-links:false;toolbar:false" contenteditable="false"><html>
<head>
<title>Yeni Kategori</title>
</head>
<body>
<div>
<h2>Yeni Kategori</h2>
<form th:action="@{addCategory}" th:object="${category}" method="POST">
<table>
<tr>
<td>Başlık</td>
<td><input type="text" th:field="*{title}" /></td>
</tr>
<tr>
<td>Alıntı Sayısı</td>
<td><input type="text" th:field="*{quotecount}" /></td>
</tr>
<tr>
<td><input type="submit" value="Kaydet"/></td>
<td></td>
</tr>
</table>
</form>
</div>
</body>
</html></pre>
<p>ve son olarak tüm kategorileri gösteren allCategories sayfamız. Sayfanın bağlandığı modeldeki categoryList koleksiyonunun elemanlarını dolaşırken th:each bildirimi devreye giriyor. Her bir kategori nesnesinin alanlarına ise bu nesne üzerinde nokta notasyonu ile<em>(c.title gibi)</em> erişiyoruz.</p>
<pre class="brush:html;auto-links:false;toolbar:false" contenteditable="false"><html>
<head>
<title>Kategoriler</title>
</head>
<body>
<div>
<h2>Kategoriler</h2>
<table>
<tr>
<th>Id</th>
<th>Başlık</th>
<th>Alıntı Sayısı</th>
</tr>
<tr th:each="c : ${categoryList}">
<td th:text="${c.id}">Id</td>
<td th:text="${c.title}">Başlık</td>
<td th:text="${c.quotecount}">Alıntı Sayısı</td>
</tr>
</table>
<p>
<a href="https://buraksenyurt.com/">Ana sayfa</a>
</p>
</div>
</body>
</html></pre>
<p>Bu arada PostgreSQL tarafındaki nesne oluşumları için hazırlanan script'leri de atlamayalım. Schema.sql içerisinde categories tablosunu oluşturan script yer alıyor.</p>
<pre class="brush:sql;auto-links:false;toolbar:false" contenteditable="false">CREATE TABLE categories(id serial PRIMARY KEY, title varchar(50),quotecount integer);</pre>
<p>Örnek birkaç veri içinse Data.sql içeriğini kullanabiliriz.</p>
<pre class="brush:sql;auto-links:false;toolbar:false" contenteditable="false">INSERT INTO categories(title,quoteCount) VALUES ('Türk Edebiyatından',150);
INSERT INTO categories(title,quoteCount) VALUES ('Futuristlerde',58);
INSERT INTO categories(title,quoteCount) VALUES ('İlham Veren',18);</pre>
<p>Peki tabii arabirim çok ilkel. Bootstrap veya muadili yapıları kullanarak görsel yönü çok daha zengin bir tasarım hazırlanabilir. Uygulamayı maven üzerinden aşağıdaki terminal komutu hemen çalıştırabiliriz. Sonrasında localhost:8080 portuna gitmemiz yeterli olacaktır.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">./mvnw spring-boot:run</pre>
<p>İşte Index sayfamız,</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/31/Screenshot_02.png" alt="" /></p>
<p>ve kategorilere gittiğimizde göreceğimiz sayfa.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/31/Screenshot_03.png" alt="" /></p>
<p>Yeni kategori ekleme sayfası ise aşağıdaki gibi görünecektir.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/31/Screenshot_04.png" alt="" /></p>
<p> </p>
<p>Son olarak yeni eklenen kategorinin listeye geldiğini gördüğümüzden emin olalım.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/31/Screenshot_05.png" alt="" /></p>
<p>Yanlış bir kategori mi eklediniz? Var olanı silmek mi istiyorsunuz? Vay halinize :D Benim üşenip de yazmadığım bu action'lar size bir görev olsun. Kodları incelerken şu sorulara cevap bulmaya çalışırsanız konuyu daha da pekiştirebilirsiniz. En azından benim aklıma gelenler bunlar.</p>
<ul>
<li>Template tarafı model nesnesinin ilgili alanlarıyla nasıl bağlantı kuruyor?</li>
<li>Sizce örnek tipik bir Repository Pattern uyarlaması mı?</li>
<li>CategoryController sınıfındaki newCategory metodunda model nesnesinin attribute'larına yeni bir Category nesnesi eklememizin sebebi nedir? Eklemezsek ne olur?</li>
</ul>
<p>Bu sorulara ek olarak uygulamaya yeni bir Entity nesnesini<em>(örneğin kategorilere bağlı kitap alıntlarını tutan sınıfı) </em>dahil edebilir, PostgreSQL yerine MongoDB kullanmayı deneyebilirsiniz. Hoş bir tasarıma da kavuşturduktan sonra aslında çok temel ihtiyaçları sağlayan veri odaklı bir MVC uygulaması yazmış oluyorsunuz. Bence güzel ;) Böylece geldik bir SkyNet derlememizin daha sonuna. Kodların tamamına <a href="https://github.com/buraksenyurt/skynet/tree/master/No%2031%20-%20Web%20App%20with%20Spring%20and%20PostgreSQL" target="_blank">github reposu üzerinden</a> ulaşabilirsiniz. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>2020-10-19T07:20:00+00:00spring frameworkspring bootjavapostgresqlmvcweb programming modelubuntudependency injectionspring initializrbsenyurtSpring Boot maceralarımız hız kesmeden devam ediyor. Bu sefer PostgreSQL veritabanını kullanan bir Web uygulamasını resmi dokümandan da yararlanarak geliştirmeye çalışacağız. Örneğimizde veritabanı olarak PostgreSQL kullanabiliriz. Her zaman olduğu gibi sisteme kurmamız şart değil. Pekala Docker imajından yararlanabiliriz. Kurgumuz basit bir MVC düzeneği olacak. Statik bir web sayfası dışında listeleme ve yeni kategori ekleme adımlarında şablonlardan(templates) faydalanacağız. Kategorileri ifade eden bir POJO sınıfımız olacak. PostgreSQL bağımlılığı kapsamında temel CRUD operasyonlarının tamamı Spring Boot'e ekleyeceğimiz bağımlılık sayesinde zaten hazır gelecek. Bunu kategori türüne uygulamak içinse generic bir Repository arayüzünden türetme yoluna gideceğiz...https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=9c140118-f12c-455d-9ca2-e84593c4ca440https://buraksenyurt.com/trackback.axd?id=9c140118-f12c-455d-9ca2-e84593c4ca44https://buraksenyurt.com/post/spring-boot-ile-postgresql-kullanan-basit-bir-web-uygulamasi-gelistirmek#commenthttps://buraksenyurt.com/syndication.axd?post=9c140118-f12c-455d-9ca2-e84593c4ca44https://buraksenyurt.com/post/spring-boot-ile-mongodb-kullanan-bir-rest-servisinin-gelistirilmesiSpring Boot ile MongoDb Kullanan Bir Rest Servisinin Geliştirilmesi2020-10-11T19:01:00+00:00bsenyurt<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/27/springboot.png" alt="" align="right" />Spring Boot, Java kod tabanı üzerine oturmuş ve özellikle kurumsal çapta uygulamaların geliştirilmesinde önemli bir yere sahip olan Spring çatısınının kullanımını oldukça kolaylaştıran,basitleştiren zevkli hale getiren<em> </em>bir başka çatıdır<em>(Framework)</em>. Dahili Dependency Injection mekanizması ve zengin paket desteği sayesinde otonom araçlardan akıllı televizyonlara, elektronik ticaretten bulut uygulamalara kadar birçok alanda Spring'in kabiliyetlerini oldukça etkin kullanabilmemize olanak sağlamaktadır. Birazdan sizin de göreceğiniz üzere az eforla oldukça etkili bir servis ortaya çıkaracağız.</p>
<p>Geliştireceğimiz örnekteki amacımız <a href="https://spring.io/guides/gs/spring-boot/" target="_blank">resmi dokümantasyondan</a> da yararlanarak MongoDb veritabanını kullanan basit bir REST servisi yazmak. Spring hayatı o kadar kolaylaştırıyor ki, onunla geliştirilen bir API servisi pek çok standardı da otomatik olarak sağlıyor. Haydi gelin nasıl olduğuna bir bakalım. </p>
<p>Ben bu çalışmayı Heimdall<em>(Ubuntu-20.04)</em> üstünde ve bir numaralı geliştirme arabirimi olarak kabul ettiğim Visual Studio Code ile geliştirmekteyim<em>.</em> Çalışmaya başladığınızda sizin de sisteminizde Java ve build mekanizması için kullanılması gereken Gradle ya da Maven olmayabilir. Bu nedenle aşağıdaki terminal komutlarına benzer bir kurulum sürecinden geçmeniz gerekebilir. Ek olarak bu örnek özelinde sisteme MongoDB kurmak yerine her zaman olduğu gibi Docker imajından yararlanabiliriz. </p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false"># Ubuntu 20.04 tarafındaki kurulum için
sudo apt install openjdk-14-jdk
# Sonrasın bir versiyon kontrolü
java --version
# Apache Maven kurulumu içinse
sudo apt install maven
# Yine bir çalışıyor mu kontrolü tabii
mvn -version
# MongoDb için daha önceki örneklerde olduğu gibi docker imajı kullanmayı tercih ettim.
sudo docker run --name mongodb -p 27017:27017 -d mongo:latest</pre>
<p>Spring Boot tarafında belki de en önemli yardımcımız uygulama iskeletini bağımlılıkları ile birlikte kolayca oluşturmamızı sağlayan Spring Initializer isimli çevrimiçi araç<em>(<a href="https://start.spring.io/" target="_blank">Şu adresten</a> ulaşabilirsiniz)</em> Bu yazıdaki örneğimiz için aşağıdaki ekran görüntüsünde yer alan konfigurasyonu kullanacağız. Uygulamaya REST özellikleri katmak için Rest Repositories ve Mongo tarafı ile kolayca konuşabilmek için Spring Data MongoDB bağımlılıklarını eklediğimize dikkat edelim.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/27/Screenshot_01.png" alt="" /></p>
<p>Arayüzde gerekli bilgileri doldurduktan sonra Generate butonuna basmamız yeterli. Sisteme sıkıştırılmış bir uygulama paketi inecektir. İndirilen hazır kod deposu üzerinde gerekli geliştirmelerimizi yapabiliriz. Tabii başlamadan önce neler gelmiş diye bakmakta yarar var. Sözgelimi yukarıdaki görselde belirlediğimiz ayarlar pom.xml dosyası içerisine yazılacaktır vb...</p>
<p>MongoDB tarafında örnek olarak oyuncu bilgilerini tutacağımız bir doküman kullanabiliriz. Bu dokümanın Java tarafındaki izdüşümünü bir sınıf<em>(POJO-Plain Old Java Object)</em> ile ifade edebiliriz. Söz konusu sınıfı src/main/java/com/skynet/gamesworldapi altında Player ismiyle aşağıdaki gibi oluşturarak çalışmamıza devam edelim.</p>
<pre class="brush:java;auto-links:false;toolbar:false" contenteditable="false">package com.skynet.gamesworldapi; // Hangi pakete dahil
import org.springframework.data.annotation.Id;
/*
MongoDb tarafındaki veriyi işaret eden eş nesne.
Bir POJO (Plain Old Java Object)
Lakin, C# Auto Property'lerin gözünü seveyim :D
*/
public class Player {
@Id
private String id; // import edilen paket üstünden kullandığımız Field. MongoDB ObjectId için
// kullanıyoruz. @Id niteliği ile bunu ifade etmiş olduk
private String _nickName;
private Integer _level;
private Boolean _isActive;
public String getNickName() {
return _nickName;
}
public void setNickName(String nickName) {
_nickName = nickName;
}
public Integer getLevel() {
return _level;
}
public void setLevel(Integer level) {
_level = level;
}
public Boolean getIsActive() {
return _isActive;
}
public void setIsActive(Boolean isActive) {
_isActive = isActive;
}
}</pre>
<p>MongoDb ile olan servis iletişimi Player nesnesine göre otomatik olarak kurgulanacaktır. Lakin ek operasyon desteği de sunmak isteyebiliriz. Örneğin aktif veya pasif oyuncu listesini verecek bir fonksiyonellik gibi. Bunun için MongoDb eklentisi ile gelen MongoRepository türünü genişletmemiz gerekiyor. Genişletilen tip sisteme enjekte edileceğinden interface olarak tasarlanmalıdır. @RepositoryRestResource niteliği ise REST için gerekli path bildirimini barındırmaktadır. Yani yönlenilen REST Endpoint'in hangi sözleşme tarafından karşılanacağı çalışma zamanına annotation üzerinden söylenir. </p>
<pre class="brush:java;auto-links:false;toolbar:false" contenteditable="false">package com.skynet.gamesworldapi;
import java.util.List; // Metodumuz bir liste döndüreceği için eklenen paket
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
/*
MongoRepository türünü genişleten bir interface söz konusu.
İçinde etkin olup olmama durumuna göre oyuncu listesi döndüren bir metodumuz da var.
path ile bu repository için API EndPoint'ini tanımlamış olduk
*/
@RepositoryRestResource(collectionResourceRel = "player", path = "player")
public interface PlayerRepository extends MongoRepository<Player, String> {
/*
Geriye Player türünden bir liste döndürecek.
Amaç isActive değerine göre etkin olan veya olmayan oyuncu listesini çekmek
_isActive.
Bu arada metot adının getBy_isActive olması tesadüf değil. Player sınıfındakinda isActive field'ını bu şekilde isimlendirdiğimiz için.
Aksi durumda build sırasında hata alırız. Kod derlenmez. Test çıktısı da fail olur.
*/
List<Player> getBy_isActive(@Param("active") Boolean isActive);
}</pre>
<p>Aslında tüm hazırlıklar bu kadar :) Uygulamayı Maven ile doğrudan çalıştırabiliriz. Ya da bir paket derleyip onu da yürütebiliriz. Her iki kullanımı da aşağıdaki terminal komutlarında görebilirsiniz<em>(mvnw dosyası bu örnek özelinde games-world-api klasörü altındadır)</em></p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">./mvnw spring-boot:run
# ya da paketi derleyip üretilen JAR dosyası ile de çalıştırılabilir
./mvnw clean package
java -jar target/games-world-api-0.0.1-SNAPSHOT.jar</pre>
<p>Buna göre aşağıdakine benzer bir çalışma zamanı elde etmemiz gerekiyor.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/27/Screenshot_02.png" alt="" /></p>
<p>Gelelim testlerimize. Uygulamamız malumunuz bir REST servisi. Bu nedenle Curl veya Postman gibi araçlarla test yapabiliriz. Dikkat edilmesi gereken nokta özellikle kendi eklediğimiz dışında tüm CRUD<em>(Create Read Update Delete)</em> fonksiyonlarının karşılığı olan Post, Get, Put, Delete operasyonlarının hazır olarak sunulmasıdır. Lütfen bunlar için herhangi bir kod yazmadığımıza dikkat edin. Sihir! ;) Öyleyse birkaç talep ile devam edelim.</p>
<p>Yeni bir oyuncuyu aşağıdaki basit talep ile ekleyebiliriz.</p>
<pre class="brush:plain;auto-links:false;toolbar:false" contenteditable="false">http://localhost:8080/player
POST
JSON Body
{
"nickName": "bamble bee",
"level": 55,
"isActive": true
}</pre>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/27/Screenshot_03.png" alt="" /></p>
<p>Birkaç oyuncu daha ekleyip sonrasında tüm oyuncu listesini almak için aşağıdaki talebi kullanmak yeterli.</p>
<pre class="brush:plain;auto-links:false;toolbar:false" contenteditable="false">http://localhost:8080/player
GET</pre>
<p>Tabii listelenen verinin büyük olma olasılığına karşın Spring Boot sayfalama özelliklerini de hesaba katmaktadır. Aşağıdaki görüntüde yer alan page kısmına dikkat edelim.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/27/Screenshot_04.png" alt="" /></p>
<p>Belli bir dokümanı<em>(player verisini)</em> çekmek istersek MongoDB'nin kendine has ID bilgisini kullanmamız yeterli. Mesela;</p>
<pre class="brush:plain;auto-links:false;toolbar:false" contenteditable="false">http://localhost:8080/player/5f3d626214851c46fd10544a
GET</pre>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/27/Screenshot_05.png" alt="" /></p>
<p>Bir içeriği silmek için,</p>
<pre class="brush:plain;auto-links:false;toolbar:false" contenteditable="false">http://localhost:8080/player/5f3d625114851c46fd105449
DELETE</pre>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/27/Screenshot_07.png" alt="" /></p>
<p>veya veri güncellemek içinse<em>(Komple set)</em> aşağıdaki örnek talebi kullanabiliriz.</p>
<pre class="brush:plain;auto-links:false;toolbar:false" contenteditable="false">http://localhost:8080/player/5f3d626214851c46fd10544a
PUT
JSON Body
{
"level": 46,
"nickName": "Sala Mura Jack",
"isActive": false
}</pre>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/27/Screenshot_08.png" alt="" /></p>
<p>Hatırlayacağınız üzere MongoDb repository'sini kendi sözleşmemiz ile genişletmiştik. Pasif ve aktif oyuncuların listesini çekmek için bu fonksiyona doğru aşağıdaki talepleri yollayabiliriz. Pasif olan oyuncular için,</p>
<pre class="brush:plain;auto-links:false;toolbar:false" contenteditable="false">http://localhost:8080/player/search/getBy_isActive?active=false
GET</pre>
<p>ve aktif oyunclar için</p>
<pre class="brush:plain;auto-links:false;toolbar:false" contenteditable="false">http://localhost:8080/player/search/getBy_isActive?active=true
GET</pre>
<p>İşte sonuçlar;</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/27/Screenshot_06.png" alt="" /></p>
<p>Görüldüğü üzere Spring Boot kullanarak MongoDB ile konuşan bir REST servisini temel CRUD ve bizim ekleyeceğimiz ilave fonksiyonlar ile ayağa kaldırmak oldukça basit, zahmetsiz ve kolay ;) Veri odaklı servisleri kolaylıkla üretim ortamlarına alabiliriz diye düşünüyorum. Spring Boot konusunda deneyimleriniz varsa bu konu özelinde yorumlarınız olursa lütfen yazının altına bırakmaya çekinmeyin. Bu arada örneği geliştirmek elbette elinizde. Söz gelimi MongoDb yerine PostgreSQL kullanmayı deneyebilirsiniz. Hatta oyuncuların katıldıkları maçlara ait skor, başarı, madalya, seviyle vb bilgilerin tutulduğu yeni bir POJO hazırlayıp Player ile ilişkilendirerek servis üzerinden sunmayı düşünebilirsiniz ;) </p>
<p>Böylece geldik bir Skynet derlememizin daha sonuna. Örneğe ait kodlara <a href="https://github.com/buraksenyurt/skynet/tree/master/No%2027%20-%20REST%20with%20Spring%20and%20MongoDb" target="_blank">github reposu üzerinden</a> erişebilirsiniz. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>2020-10-11T19:01:00+00:00javamongodbspringspring bootdockermavengradlespring frameworkbsenyurtSpring Boot, Java kod tabanı üzerine oturmuş Spring ile uygulama geliştirmeyi kolaylaştıran oldukça kolaylaştıran bir geliştirme çatısıdır. Dahili Dependency Injection mekanizması ve zengin paket desteği sayesinde otonom araçlardan akıllı televizyonlara, elektronik ticaretten bulut uygulamalara kadar birçok alanda Spring'in kabiliyetlerini oldukça etkin kullanabilmemize olanak sağlamaktadır. Birazdan sizde göreceksiniz ki az eforla oldukça etkili bir uygulama ortaya çıkartacağız. Geliştireceğimiz örnekteki amacımız resmi dokümantasyondan da yararlanarak MongoDb veritabanını kullanan basit bir REST servisi geliştirmek. Spring hayatı o kadar kolaylaştırıyor ki, onunla geliştirilen bir API servisi pek çok standardı da otomatik olarak sağlıyor. Haydi gelin nasıl olduğuna bir bakalım.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=ccfadae6-04d8-44af-8cef-9f832531d64d0https://buraksenyurt.com/trackback.axd?id=ccfadae6-04d8-44af-8cef-9f832531d64dhttps://buraksenyurt.com/post/spring-boot-ile-mongodb-kullanan-bir-rest-servisinin-gelistirilmesi#commenthttps://buraksenyurt.com/syndication.axd?post=ccfadae6-04d8-44af-8cef-9f832531d64d