Eğitim Portalı/Java/Servlet'e Giriş
Java01-java/65-servlet-giris

Servlet'e Giriş

Servlet, sunucuya gelen bir HTTP isteğini işleyip yanıt üreten bir Java sınıfıdır. Java'nın web teknolojilerinin temelidir: bugün kullandığın Spring MVC, JSF ve neredeyse tüm Java web çatıları, perde arkasında servlet…

Servlet'e Giriş

Servlet, sunucuya gelen bir HTTP isteğini işleyip yanıt üreten bir Java sınıfıdır. Java'nın web teknolojilerinin temelidir: bugün kullandığın Spring MVC, JSF ve neredeyse tüm Java web çatıları, perde arkasında servlet API'sinin üzerine kuruludur. Servlet'leri anlamak, modern çatıların "sihrini" görmeni sağlar.

Not: Gerçek servlet API'si (jakarta.servlet) bir sunucu konteyneri (Tomcat, Jetty) gerektirir; portal headless olduğu için burada servlet modelini kendi mini sınıflarımızla taklit ediyoruz. Gerçek servlet kodu aşağıda gösterilir.

Servlet modeli: istek → işleme → yanıt

Bir web sunucusunun temel döngüsü şudur:

  1. Tarayıcı bir HTTP isteği gönderir (metot + yol + parametreler/başlıklar).
  2. Konteyner (Tomcat) isteği, URL eşlemesine göre doğru servlet'e yönlendirir.
  3. Servlet, isteği işler (doGet/doPost) ve bir yanıt yazar (durum kodu + gövde + içerik tipi).

Örnek 1 (./Ornek1.java) bunu simüle eder: bir "konteyner" yol→servlet eşlemesi tutar; gelen isteği ilgili servlet'e yönlendirir; bulunmazsa 404 döner. /merhaba ve /topla "servlet"leri parametre okuyup yanıt üretir.

Servlet yaşam döngüsü ve filtreler

Konteyner her servlet'i belirli bir yaşam döngüsüyle yönetir:

  • init(): Servlet ilk kez yüklenirken bir kez (kaynak hazırlama).
  • service()doGet/doPost: Her istekte (asıl iş).
  • destroy(): Uygulama kapanırken bir kez (temizlik).

Ayrıca filtreler (Filter) vardır: istek servlet'e ulaşmadan (veya yanıt dönmeden) araya giren ara katmanlar — loglama, kimlik doğrulama, sıkıştırma, CORS. Bir zincir halinde çalışırlar. Örnek 2 (./Ornek2.java) yaşam döngüsünü ve bir filtre zincirini (log → kimlik → servlet) simüle eder.

Gerçek servlet kodu (Tomcat/Jetty ile)

import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.WebServlet;
import java.io.IOException;

@WebServlet("/merhaba")                       // URL eşlemesi
public class MerhabaServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        String ad = req.getParameter("ad");    // ?ad=Ada
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().write("<h1>Merhaba, " + (ad != null ? ad : "Misafir") + "!</h1>");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) { /* ... */ }
}

Bu sınıf bir .war olarak paketlenip Tomcat'e dağıtılır; Tomcat /merhaba isteklerini bu servlet'e yönlendirir.

Servlet'ten Spring'e

Servlet API'si güçlüdür ama düşük seviyelidir (parametre ayrıştırma, JSON dönüşümü, hata yönetimi elle). Spring MVC bunu sarmalar:

@RestController
public class MerhabaController {
    @GetMapping("/merhaba")
    public String merhaba(@RequestParam(defaultValue="Misafir") String ad) {
        return "Merhaba, " + ad + "!";
    }
}

Spring'in DispatcherServlet'i aslında tek bir servlet'tir; tüm istekleri alır ve @GetMapping/@PostMapping ile işaretlenmiş metotlara yönlendirir. Yani Spring MVC, servlet modelinin üzerine kurulu konforlu bir katmandır (bu portalın backend'i de böyle çalışır).

Özet

Servlet'in sunucuya gelen HTTP isteğini işleyen Java sınıfı olduğunu; istek→işleme→yanıt modelini ve konteynerin yönlendirmesini (Örnek 1); yaşam döngüsünü (init/service/destroy) ve filtreleri (Örnek 2) öğrendik; gerçek HttpServlet/@WebServlet kodunu ve bunun Spring MVC ile ilişkisini gördük. Sırada, servlet'lerin içine HTML gömmeyi kolaylaştıran sunum teknolojisi: JSP.

Kod Örnekleri(2)

Ornek1

çalıştırılabilir
Ornek1.java
1// Ornek1: Servlet modeli — istek/yanıt ve yol-eşleme (dispatch) SİMÜLASYONU.
2// (Gerçek jakarta.servlet API'si bir sunucu konteyneri gerektirir; portal headless olduğu için
3//  modeli kendi mini sınıflarımızla taklit ediyoruz. Gerçek kod README'de.)
4// Çalıştırma: java Ornek1.java
5import java.util.HashMap;
6import java.util.Map;
7import java.util.function.BiConsumer;
8
9public class Ornek1 {
10
11    // Gerçek HttpServletRequest/Response'un minik karşılıkları:
12    record Istek(String metot, String yol, Map<String, String> parametreler) {}
13    static class Yanit {
14        int durum = 200; String govde = ""; String tip = "text/html";
15        void yaz(String s) { govde += s; }
16    }
17
18    // Bir "servlet": belirli bir yola gelen isteği işler (gerçekte doGet/doPost).
19    interface Servlet extends BiConsumer<Istek, Yanit> {}
20
21    // Mini konteyner: yol -> servlet eşlemesi + dispatch.
22    static class Konteyner {
23        private final Map<String, Servlet> rotalar = new HashMap<>();
24        void ekle(String yol, Servlet s) { rotalar.put(yol, s); }
25        Yanit istekGonder(Istek istek) {
26            Yanit y = new Yanit();
27            Servlet s = rotalar.get(istek.yol());
28            if (s == null) { y.durum = 404; y.yaz("404 Bulunamadı: " + istek.yol()); }
29            else s.accept(istek, y);   // ilgili servlet'i çalıştır
30            return y;
31        }
32    }
33
34    public static void main(String[] args) {
35        Konteyner konteyner = new Konteyner();
36
37        // "/merhaba" servlet'i — gerçekte doGet'in yaptığı iş:
38        konteyner.ekle("/merhaba", (istek, yanit) -> {
39            String ad = istek.parametreler().getOrDefault("ad", "Misafir");
40            yanit.yaz("<h1>Merhaba, " + ad + "!</h1>");
41        });
42        // "/topla" servlet'i
43        konteyner.ekle("/topla", (istek, yanit) -> {
44            int a = Integer.parseInt(istek.parametreler().getOrDefault("a", "0"));
45            int b = Integer.parseInt(istek.parametreler().getOrDefault("b", "0"));
46            yanit.tip = "text/plain";
47            yanit.yaz("Sonuç: " + (a + b));
48        });
49
50        // İstekleri "gönder" (tarayıcı yerine biz simüle ediyoruz):
51        yazdir(konteyner.istekGonder(new Istek("GET", "/merhaba", Map.of("ad", "Ada"))));
52        yazdir(konteyner.istekGonder(new Istek("GET", "/topla", Map.of("a", "7", "b", "5"))));
53        yazdir(konteyner.istekGonder(new Istek("GET", "/yok", Map.of())));
54
55        System.out.println("""
56
57                --- Servlet modeli ---
58                Servlet = sunucuya gelen HTTP isteğini işleyip yanıt üreten Java sınıfı.
59                Konteyner (Tomcat/Jetty) isteği DOĞRU servlet'e yönlendirir (URL eşlemesi) ve doGet/doPost'u çağırır.
60                İstek: metot + yol + parametreler/başlıklar. Yanıt: durum kodu + gövde + içerik tipi.
61                Spring MVC'deki @GetMapping/@RestController, bu servlet modelinin üzerine kurulu üst katmandır.""");
62    }
63
64    static void yazdir(Yanit y) {
65        System.out.println("[" + y.durum + " | " + y.tip + "] " + y.govde);
66    }
67}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

Ornek2

çalıştırılabilir
Ornek2.java
1// Ornek2: Servlet yaşam döngüsü (init/service/destroy) ve filtre zinciri SİMÜLASYONU.
2// Çalıştırma: java Ornek2.java
3import java.util.List;
4
5public class Ornek2 {
6
7    // Servlet yaşam döngüsü: konteyner servlet'i bir kez init eder, her istekte service çağırır, sonda destroy.
8    static abstract class Servlet {
9        void init() { System.out.println("  [init] servlet başlatıldı (bir kez)"); }
10        abstract void service(String istek);
11        void destroy() { System.out.println("  [destroy] servlet kapatıldı (bir kez)"); }
12    }
13
14    // Filtre: istek servlet'e ULAŞMADAN önce/sonra araya girer (kimlik, log, sıkıştırma...).
15    interface Filtre { void uygula(String istek, Runnable sonraki); }
16
17    public static void main(String[] args) {
18        Servlet servlet = new Servlet() {
19            @Override void service(String istek) { System.out.println("  [service] işleniyor: " + istek); }
20        };
21
22        // Filtre zinciri: log -> kimlik -> (servlet). Her filtre 'sonraki'yi çağırarak zinciri ilerletir.
23        List<Filtre> filtreler = List.of(
24                (istek, sonraki) -> { System.out.println("  [filtre:log] istek geldi: " + istek); sonraki.run(); },
25                (istek, sonraki) -> {
26                    if (istek.contains("token")) { System.out.println("  [filtre:kimlik] OK"); sonraki.run(); }
27                    else System.out.println("  [filtre:kimlik] 401 - reddedildi");
28                }
29        );
30
31        // Yaşam döngüsü:
32        System.out.println(">> Konteyner servlet'i başlatıyor:");
33        servlet.init();
34
35        System.out.println("\n>> İstek 1 (token var):");
36        zinciriCalistir(filtreler, "GET /panel?token=abc", () -> servlet.service("GET /panel"));
37
38        System.out.println("\n>> İstek 2 (token yok):");
39        zinciriCalistir(filtreler, "GET /panel", () -> servlet.service("GET /panel"));
40
41        System.out.println("\n>> Konteyner kapanıyor:");
42        servlet.destroy();
43
44        System.out.println("""
45
46                --- Servlet yaşam döngüsü + filtreler ---
47                Yaşam döngüsü: init() (bir kez, başlangıçta) -> service() (HER istekte) -> destroy() (bir kez, sonda).
48                Filtre (Filter): istek servlet'e ulaşmadan/yanıt dönmeden araya giren ara katman
49                  (loglama, kimlik doğrulama, sıkıştırma, CORS...). Zincir halinde çalışır.
50                Spring'in interceptor'ları ve filtreleri bu modelin üzerine kuruludur.""");
51    }
52
53    static void zinciriCalistir(List<Filtre> filtreler, String istek, Runnable servletCagrisi) {
54        // Filtreleri sırayla iç içe çağıran özyinelemeli zincir.
55        Runnable zincir = servletCagrisi;
56        for (int i = filtreler.size() - 1; i >= 0; i--) {
57            Filtre f = filtreler.get(i);
58            Runnable sonraki = zincir;
59            zincir = () -> f.uygula(istek, sonraki);
60        }
61        zincir.run();
62    }
63}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.