Takip et

Giriş: Jersey ve RESTful Web Servisleri

Giriş: Jersey ve RESTful Web Servisleri Modern web uygulamalarının bel kemiğini oluşturan RESTful mimari, kaynak tabanlı, durum bilgisi olmay

Giriş: Jersey ve RESTful Web Servisleri

Modern web uygulamalarının bel kemiğini oluşturan RESTful mimari, kaynak tabanlı, durum bilgisi olmayan ve HTTP protokolünü tam anlamıyla kullanan bir yaklaşımdır. Java dünyasında bu mimariyi uygulamak için çeşitli çerçeveler (framework) bulunmaktadır. Bunlardan biri de, Java EE standardı olan JAX-RS (Java API for RESTful Web Services) referans uygulaması olan Jersey’dir. Bu rehberde, Jersey kullanarak nasıl RESTful web servisleri geliştireceğinizi adım adım öğreneceksiniz.

Jersey Nedir?

Jersey, JAX-RS API’sinin açık kaynaklı bir referans implementasyonudur. JAX-RS, Java geliştiricilerinin RESTful servisleri kolayca oluşturabilmeleri için standart bir API sağlar. Jersey, bu API’yi kullanarak, POJO’lar (Plain Old Java Objects) aracılığıyla HTTP isteklerini ve yanıtlarını yönetmenizi, URI’ları kaynaklara eşlemenizi ve çeşitli medya tiplerini (JSON, XML, metin vb.) işlemenizi sağlar.

RESTful Mimari ve Önemi

REST (Representational State Transfer), web servisleri için bir yazılım mimarisi stilidir. Temel prensipleri şunlardır:

  • Kaynaklar (Resources): Her şey bir kaynaktır ve tekil bir URI (Uniform Resource Identifier) ile tanımlanır. Örn: /urunler, /urunler/123.
  • Durum Bilgisi Olmaması (Stateless): Her istek, sunucunun isteği işlemek için ihtiyaç duyduğu tüm bilgiyi içermelidir. Sunucu, önceki isteklerden herhangi bir istemci durumunu saklamaz.
  • Standart Metotlar (Standard Methods): HTTP metotları (GET, POST, PUT, DELETE) kaynaklar üzerinde belirli işlemler yapmak için kullanılır.
  • Temsil (Representation): Kaynaklar, JSON, XML veya HTML gibi farklı formatlarda temsil edilebilir.

Jersey, bu prensipleri Java koduna dönüştürmek için güçlü ve esnek bir yapı sunar.

Jersey Projesi Kurulumu ve Yapılandırması

Jersey ile bir RESTful servis geliştirmeye başlamadan önce, projemizi doğru bir şekilde kurmamız ve gerekli bağımlılıkları eklememiz gerekir. Bu bölümde, Maven kullanarak bir Jersey projesi oluşturma adımlarını inceleyeceğiz.

Ön Gereksinimler

  • JDK (Java Development Kit) 8 veya üzeri
  • Maven (Proje Yönetim Aracı)
  • Tercih edilen bir IDE (IntelliJ IDEA, Eclipse, VS Code)
  • Bir Servlet Konteyneri (Apache Tomcat, Jetty vb.)

Maven Projesi Oluşturma

Yeni bir Maven projesi oluşturarak başlayabiliriz. Komut satırından veya IDE’niz üzerinden “maven-archetype-webapp” şablonunu kullanarak bir web uygulaması projesi oluşturabilirsiniz:

mvn archetype:generate -DgroupId=com.example -DartifactId=jersey-tutorial -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false

Bu komut, jersey-tutorial adında yeni bir Maven web projesi oluşturacaktır.

pom.xml Bağımlılıkları

Oluşturulan pom.xml dosyasına Jersey ve ilgili bağımlılıkları eklememiz gerekiyor. Özellikle jersey-server (JAX-RS API ve çekirdek implementasyon) ve jersey-container-servlet (Jersey’nin bir Servlet konteynerinde çalışmasını sağlayan modül) bağımlılıklarını eklemeliyiz. JSON desteği için jersey-media-json-jackson bağımlılığını da eklemek pratik olacaktır.


    4.0.0
    com.example
    jersey-tutorial
    war
    1.0-SNAPSHOT
    jersey-tutorial Maven Webapp
    http://maven.apache.org

    
        2.34 
        UTF-8
    

    
        
        
            org.glassfish.jersey.core
            jersey-server
            ${jersey.version}
        
        
        
            org.glassfish.jersey.containers
            jersey-container-servlet-core
            ${jersey.version}
        
        
        
            org.glassfish.jersey.media
            jersey-media-json-jackson
            ${jersey.version}
        
        
        
            javax.servlet
            javax.servlet-api
            3.1.0
            provided
        
        
        
            junit
            junit
            4.13.2
            test
        
    

    
        jersey-tutorial
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.8.1
                
                    1.8
                    1.8
                
            
            
            
                org.apache.tomcat.maven
                tomcat7-maven-plugin
                2.2
                
                    
                
            
        
    

web.xml Yapılandırması

Web uygulamanızın src/main/webapp/WEB-INF dizini altında bulunan web.xml dosyası, Jersey’nin Servlet konteyneri tarafından nasıl yükleneceğini ve hangi URL desenlerini dinleyeceğini belirtir. Jersey’nin ServletContainer sınıfını bir Servlet olarak tanımlamamız ve kaynak sınıflarımızın bulunduğu paketi belirtmemiz gerekir.




    Jersey RESTful Web Application

    
        jersey-servlet
        org.glassfish.jersey.servlet.ServletContainer
        
            jersey.config.server.provider.packages
            com.example.resources 
        
        1
    

    
        jersey-servlet
        /api/* 
    

Yukarıdaki yapılandırmada, jersey.config.server.provider.packages parametresi, Jersey’nin hangi paketlerdeki JAX-RS anotasyonlu sınıfları tarayacağını belirtir. url-pattern ise, /api/* ile başlayan tüm isteklerin Jersey tarafından işleneceğini gösterir.

Temel RESTful Servis Oluşturma

Artık projemiz yapılandırıldığına göre, ilk RESTful servislerimizi oluşturmaya başlayabiliriz. Jersey, JAX-RS anotasyonlarını kullanarak Java sınıflarını ve metotlarını REST kaynaklarına dönüştürmeyi son derece kolaylaştırır.

Kaynak Sınıfı Oluşturma

com.example.resources paketi altında MerhabaServis adında bir sınıf oluşturalım. Bu sınıf, @Path anotasyonu ile bir URI yoluna eşlenecektir.

package com.example.resources;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/merhaba") // Bu sınıfın tüm metotları /api/merhaba altında erişilebilir olacak
public class MerhabaServis {

    @GET // HTTP GET isteklerini karşılar
    @Produces(MediaType.TEXT_PLAIN) // Yanıtın düz metin formatında olacağını belirtir
    public String getMerhabaMesaji() {
        return "Merhaba Dünya, Jersey'e Hoş Geldiniz!";
    }
}

Bu örnekte:

  • @Path("/merhaba"): Bu sınıfın /api/merhaba URI’si altında erişilebilir olduğunu belirtir.
  • @GET: getMerhabaMesaji metodunun HTTP GET isteklerine yanıt vereceğini belirtir.
  • @Produces(MediaType.TEXT_PLAIN): Metodun döndürdüğü yanıtın text/plain medya tipinde olacağını belirtir.

HTTP Metotları ve Parametre İşleme

RESTful servisler, farklı HTTP metotlarını (GET, POST, PUT, DELETE) kullanarak kaynaklar üzerinde CRUD (Create, Read, Update, Delete) işlemleri yapar. Ayrıca, URI’den veya sorgu parametrelerinden veri alabilirler.

GET İstekleri ve Parametreler

GET istekleri genellikle veri okumak için kullanılır. @PathParam ve @QueryParam ile parametreleri yakalayabiliriz.

package com.example.resources;

import javax.ws.rs.*; // Tüm JAX-RS anotasyonlarını import edelim
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; // HTTP yanıtını özelleştirmek için

@Path("/kullanicilar")
public class KullaniciServis {

    // GET /api/kullanicilar
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getAllKullanicilar() {
        return "Tüm kullanıcılar listeleniyor...";
    }

    // GET /api/kullanicilar/{id}
    @GET
    @Path("/{id}") // URI yolunda bir parametre tanımlar
    @Produces(MediaType.TEXT_PLAIN)
    public String getKullaniciById(@PathParam("id") int kullaniciId) {
        return "ID'si " + kullaniciId + " olan kullanıcı getiriliyor.";
    }

    // GET /api/kullanicilar/ara?ad=Ahmet&soyad=Yilmaz
    @GET
    @Path("/ara")
    @Produces(MediaType.TEXT_PLAIN)
    public String searchKullanicilar(@QueryParam("ad") String ad,
                                     @QueryParam("soyad") String soyad) {
        return "Adı: " + ad + ", Soyadı: " + soyad + " olan kullanıcılar aranıyor.";
    }
}
  • @PathParam("id"): URI yolundaki {id} kısmını kullaniciId int değişkenine eşler.
  • @QueryParam("ad"): URI sorgu parametrelerindeki ad değerini ad String değişkenine eşler.

POST İstekleri ve Veri Gönderme

POST istekleri genellikle yeni bir kaynak oluşturmak için kullanılır. @Consumes anotasyonu, metodun hangi medya tipindeki veriyi kabul ettiğini belirtir.

package com.example.resources;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/urunler")
public class UrunServis {

    // POST /api/urunler
    @POST
    @Consumes(MediaType.TEXT_PLAIN) // İstek gövdesinde düz metin bekler
    @Produces(MediaType.TEXT_PLAIN) // Yanıtın düz metin olacağını belirtir
    public Response createUrun(String urunAdi) {
        // Veritabanına ürün ekleme işlemi simüle ediliyor
        System.out.println("Yeni ürün oluşturuldu: " + urunAdi);
        return Response.status(Response.Status.CREATED) // 201 Created HTTP durumu döner
                       .entity("Ürün başarıyla oluşturuldu: " + urunAdi)
                       .build();
    }
}
  • @POST: Metodun HTTP POST isteklerine yanıt vereceğini belirtir.
  • @Consumes(MediaType.TEXT_PLAIN): İstek gövdesinin text/plain formatında olması gerektiğini belirtir.
  • Response.status(Response.Status.CREATED).entity(...).build(): Özel bir HTTP yanıtı oluşturmak için kullanılır. Bu, 201 Created durum koduyla bir yanıt döndürür.

Veri Modelleri ve JSON/XML Entegrasyonu

Gerçek dünya uygulamalarında, genellikle basit String veya int değerler yerine daha karmaşık veri yapıları (POJO’lar) ile çalışırız. Jersey, bu POJO’ları otomatik olarak JSON veya XML gibi formatlara dönüştürmek (serileştirme) ve bu formatlardan POJO’lara geri dönüştürmek (deserileştirme) için güçlü bir destek sunar.

POJO (Plain Old Java Object) Oluşturma

Öncelikle, temsil etmek istediğimiz veri için bir POJO oluşturalım.

package com.example.model;

import javax.xml.bind.annotation.XmlRootElement; // XML desteği için

@XmlRootElement // Bu anotasyon, JAXB'nin bu sınıfı XML'e dönüştürmesine yardımcı olur
public class Urun {
    private int id;
    private String ad;
    private double fiyat;

    public Urun() {
        // Varsayılan kurucu metot, JSON/XML serileştirme için gereklidir
    }

    public Urun(int id, String ad, double fiyat) {
        this.id = id;
        this.ad = ad;
        this.fiyat = fiyat;
    }

    // Getter ve Setter metotları
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public String getAd() { return ad; }
    public void setAd(String ad) { this.ad = ad; }
    public double getFiyat() { return fiyat; }
    public void setFiyat(double fiyat) { this.fiyat = fiyat; }

    @Override
    public String toString() {
        return "Urun{" +
               "id=" + id +
               ", ad='" + ad + '\'' +
               ", fiyat=" + fiyat +
               '}';
    }
}

@XmlRootElement anotasyonu, bu POJO’nun XML formatına dönüştürülürken kök element olarak kullanılabileceğini belirtir. JSON için genellikle varsayılan kurucu metot ve getter/setter’lar yeterlidir (Jackson kütüphanesi tarafından kullanılır).

JSON Desteği ile POJO Kullanımı

pom.xml dosyamıza jersey-media-json-jackson bağımlılığını eklediğimiz için, Jersey otomatik olarak Jackson kütüphanesini kullanarak POJO’ları JSON’a serileştirecek ve JSON’dan POJO’lara deseralize edecektir.

package com.example.resources;

import com.example.model.Urun;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

@Path("/urunler")
public class UrunKaynak {

    // Basit bir bellek içi depolama
    private static List urunler = new ArrayList<>();
    private static AtomicInteger idCounter = new AtomicInteger();

    static {
        urunler.add(new Urun(idCounter.incrementAndGet(), "Laptop", 1200.00));
        urunler.add(new Urun(idCounter.incrementAndGet(), "Mouse", 25.00));
    }

    // GET /api/urunler
    @GET
    @Produces(MediaType.APPLICATION_JSON) // JSON formatında yanıt döndürür
    public List getAllUrunler() {
        return urunler;
    }

    // GET /api/urunler/{id}
    @GET
    @Path("/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getUrunById(@PathParam("id") int id) {
        for (Urun urun : urunler) {
            if (urun.getId() == id) {
                return Response.ok(urun).build(); // 200 OK ile ürünü döndür
            }
        }
        return Response.status(Response.Status.NOT_FOUND).entity("Ürün bulunamadı.").build(); // 404 Not Found
    }

    // POST /api/urunler
    @POST
    @Consumes(MediaType.APPLICATION_JSON) // İstek gövdesinde JSON bekler
    @Produces(MediaType.APPLICATION_JSON)
    public Response createUrun(Urun yeniUrun) {
        yeniUrun.setId(idCounter.incrementAndGet());
        urunler.add(yeniUrun);
        System.out.println("Yeni ürün eklendi: " + yeniUrun);
        return Response.status(Response.Status.CREATED).entity(yeniUrun).build(); // 201 Created ile oluşturulan ürünü döndür
    }

    // PUT /api/urunler/{id}
    @PUT
    @Path("/{id}")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response updateUrun(@PathParam("id") int id, Urun guncelUrun) {
        for (int i = 0; i < urunler.size(); i++) {
            if (urunler.get(i).getId() == id) {
                guncelUrun.setId(id); // ID'nin değişmediğinden emin ol
                urunler.set(i, guncelUrun);
                System.out.println("Ürün güncellendi: " + guncelUrun);
                return Response.ok(guncelUrun).build(); // 200 OK ile güncellenen ürünü döndür
            }
        }
        return Response.status(Response.Status.NOT_FOUND).entity("Güncellenecek ürün bulunamadı.").build();
    }

    // DELETE /api/urunler/{id}
    @DELETE
    @Path("/{id}")
    @Produces(MediaType.TEXT_PLAIN)
    public Response deleteUrun(@PathParam("id") int id) {
        boolean removed = urunler.removeIf(urun -> urun.getId() == id);
        if (removed) {
            System.out.println("Ürün silindi: ID " + id);
            return Response.ok("Ürün başarıyla silindi.").build(); // 200 OK
        }
        return Response.status(Response.Status.NOT_FOUND).entity("Silinecek ürün bulunamadı.").build();
    }
}

Bu UrunKaynak sınıfı, Urun POJO’larını kullanarak tam bir CRUD (Create, Read, Update, Delete) operasyonlarını JSON formatında nasıl gerçekleştirebileceğimizi gösterir.

Jersey Uygulamasını Çalıştırma ve Test Etme

Servislerimizi kodladığımıza göre, şimdi bunları bir Servlet konteynerinde çalıştırma ve test etme zamanı.

Uygulama Sunucusu (Servlet Konteyneri) Kullanımı

En yaygın yöntem, uygulamayı bir WAR (Web Application Archive) dosyası olarak paketleyip Apache Tomcat veya Jetty gibi bir uygulama sunucusuna dağıtmaktır.

1. WAR Dosyası Oluşturma: Projenizin kök dizininde aşağıdaki Maven komutunu çalıştırın:

mvn clean package

Bu komut, target klasöründe jersey-tutorial.war (veya pom.xml‘deki finalName neyse o) adında bir WAR dosyası oluşturacaktır.

2. WAR Dosyasını Dağıtma: Oluşturulan WAR dosyasını Tomcat’in webapps dizinine kopyalayın ve Tomcat’i başlatın. Tomcat otomatik olarak uygulamayı dağıtacaktır.

3. Maven Tomcat Plugin ile Çalıştırma (Geliştirme Ortamı İçin): pom.xml‘e eklediğimiz tomcat7-maven-plugin‘i kullanarak doğrudan Maven üzerinden uygulamayı çalıştırabilirsiniz:

mvn tomcat7:run

Bu, Tomcat’i gömülü olarak başlatacak ve uygulamanızı dağıtacaktır. Varsayılan olarak, uygulamanız http://localhost:8080/jersey-tutorial adresinde erişilebilir olacaktır.

Servisi Test Etme

Servislerinizi test etmek için Postman, Insomnia gibi GUI tabanlı araçları veya cURL gibi komut satırı araçlarını kullanabilirsiniz.

Varsayılan olarak, uygulamanız http://localhost:8080/jersey-tutorial altında çalışıyorsa ve web.xml‘deki url-pattern /api/* ise, servisleriniz http://localhost:8080/jersey-tutorial/api/... adresinde olacaktır.

GET İstekleri


Tüm ürünleri getir

curl http://localhost:8080/jersey-tutorial/api/urunler

ID'si 1 olan ürünü getir

curl http://localhost:8080/jersey-tutorial/api/urunler/1

POST İstekleri (JSON ile Yeni Ürün Oluşturma)


curl -X POST \
  http://localhost:8080/jersey-tutorial/api/urunler \
  -H 'Content-Type: application/json' \
  -d '{
    "ad": "Klavye",
    "fiyat": 75.50
  }'

PUT İstekleri (JSON ile Ürün Güncelleme)


curl -X PUT \
  http://localhost:8080/jersey-tutorial/api/urunler/1 \
  -H 'Content-Type: application/json' \
  -d '{
    "id": 1,
    "ad": "Kablosuz Klavye",
    "fiyat": 99.99
  }'

DELETE İstekleri


curl -X DELETE \
  http://localhost:8080/jersey-tutorial/api/urunler/2

Bu komutları çalıştırdığınızda, konsolunuzda veya HTTP istemcinizde beklenen JSON yanıtlarını veya düz metin mesajlarını görmelisiniz.

Sonuç ve Sıkça Sorulan Sorular (SSS)

Bu rehberde, Jersey kullanarak temel bir RESTful web servisinin nasıl oluşturulacağını, yapılandırılacağını ve test edileceğini öğrendiniz. Jersey, JAX-RS standartlarını takip ederek Java’da RESTful uygulamalar geliştirmek için güçlü, esnek ve standartlara uygun bir yol sunar. POJO’ları JSON/XML’e dönüştürme yeteneği ve basit anotasyon tabanlı yaklaşımı sayesinde, veri odaklı servisleri hızlıca oluşturabilirsiniz.

Sıkça Sorulan Sorular (SSS)

S1: Jersey’i Spring REST ile karşılaştırırsak, hangisini seçmeliyim?
C1: Jersey, JAX-RS’in referans implementasyonudur ve saf bir JAX-RS deneyimi sunar. Spring REST (Spring WebFlux veya Spring MVC ile), Spring ekosisteminin bir parçasıdır ve Spring’in diğer modülleri (Dependency Injection, Data JPA vb.) ile sorunsuz entegrasyon sağlar. Eğer projeniz zaten Spring tabanlıysa veya geniş bir ekosistem arıyorsanız Spring REST daha uygun olabilir. Sadece JAX-RS standartlarına bağlı kalmak istiyorsanız Jersey mükemmel bir seçimdir.

S2: JAX-RS tam olarak nedir ve Jersey’nin rolü ne?
C2: JAX-RS (Java API for RESTful Web Services), Java EE’nin bir parçası olan, RESTful web servisleri oluşturmak için bir standart API’dir. Geliştiricilerin RESTful servisleri yazmak için kullanacakları anotasyonları ve arayüzleri tanımlar. Jersey ise bu JAX-RS API’sinin bir implementasyonudur. Yani JAX-RS “ne yapılması gerektiğini” söyler, Jersey ise “nasıl yapılacağını” gösterir ve sağlar.

S3: Jersey uygulamalarında güvenlik nasıl sağlanır?

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Gönder

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.
Mobil sürümden çık