Spring - Bagaimana Cara Spring Web Menangani Request dan Response

Ilustrasi Tentang DispatcherServlet

Request dan Response di Spring Web (khususnya Spring MVC, model standar yang blocking default-nya/bukan yang WebFlux) adalah proses yang sangat terstruktur yang diorkestrasi oleh DispatcherServlet.

"Jika ingin memahami DispatcherServlet secara mendalam dan teknis, Javadoc ini adalah bahan bacaan yang wajib karena menjelaskan kontrak, metode, dan interaksi yang diharapkan dari kelas tersebut dalam arsitektur Spring."
Ini adalah alur langkah demi langkah tentang bagaimana Spring Web memproses permintaan pengguna hingga menghasilkan respons:

1. Fase Awal: DispatcherServlet sebagai Front Controller

Semua dimulai ketika Servlet Container (misalnya, Tomcat) menerima request HTTP dan meneruskannya ke DispatcherServlet lalu Tomcat membuat objek HttpServletRequest (Input) dan HttpServletResponse (Wadah Output) untuk request ini.

DispatcherServlet adalah 100% implementasi dari Front Controller Pattern dalam konteks Spring MVC.  Spring Framework secara eksplisit mendesain dan menggunakan DispatcherServlet untuk memenuhi semua persyaratan dari pola desain tersebut (sumber). 

Front Controller Pattern
 

2. Fase Routing: Mencari Handler

Tugas selanjutnya DispatcherServlet adalah mencari tahu siapa yang harus menangani request ini dimana DispatcherServlet akan  berkonsultasi dengan satu atau lebih HandlerMapping (misalnya RequestMappingHandlerMapping).
 

HandlerMapping memindai Controller dan metode yang ada (yang ditandai dengan @Controller atau @RestController dan anotasi routing seperti @GetMapping atau @PostMapping).

Hasilnya, DispatcherServlet menerima sebuah Handler (metode Controller) yang cocok dengan URL request (misalnya /users/1) dan metode HTTP-nya. 

3. Fase Pre-Processing

Sebelum mencapai logika utama, request dapat dicegat (intersep) untuk tujuan global.

Interceptors: DispatcherServlet menjalankan metode preHandle() dari semua HandlerInterceptor yang terdaftar. Ini adalah kesempatan untuk:

  1. Melakukan otentikasi atau otorisasi.
  2. Mengecek sesi.
  3. Menyesuaikan request sebelum sampai ke Controller. 

 4. Fase Pemrosesan Utama: Eksekusi Controller

DispatcherServlet menyerahkan request ke HandlerAdapter untuk eksekusi yang sebenarnya.

  1. Pemanggilan Metode: HandlerAdapter memanggil metode Controller yang dituju.
  2. Injeksi Parameter: HandlerAdapter secara cerdas mengambil data dari HttpServletRequest dan mengubahnya menjadi parameter metode Controller. Contoh: 
  1. Data JSON di body request diubah menjadi objek Java (@RequestBody).
  2. ID dari URL diubah menjadi Long (@PathVariable).
  3. Data Query diubah menjadi String (@RequestParam).
Logika Bisnis: Controller menjalankan logika utamanya (memanggil Service Layer).

 5. Fase Response Awal

Setelah Controller selesai, hasilnya akan diproses.

Skenario A: RESTful API (@RestController)

  1. Controller mengembalikan objek data (misalnya User atau List<Product>).
  2. Spring menggunakan HttpMessageConverter (seperti Jackson) untuk mengubah objek Java ini menjadi format yang diminta (misalnya JSON atau XML).
  3. Data JSON ini langsung ditulis ke HttpServletResponse. Alur melompati Resolusi View.

Skenario B: Web MVC (mengembalikan View)

  1. Controller mengembalikan nama View (misalnya, "home") dan mungkin sebuah objek Model (data yang akan ditampilkan).
  2. DispatcherServlet menangkap objek ModelAndView.

6. Fase Resolusi View (Hanya MVC)

Jika Controller mengembalikan nama View, fase ini dijalankan:

  1. View Resolver: DispatcherServlet berkonsultasi dengan ViewResolver (misalnya InternalResourceViewResolver).
  2. Pencarian Fisik: ViewResolver memetakan nama View logis ("home") menjadi jalur fisik (path) sumber daya (misalnya /WEB-INF/views/home.jsp).
  3. Rendering: View fisik (template) mengambil data dari Model dan menghasilkan HTML akhir. HTML ini kemudian ditulis ke HttpServletResponse. 

7. Fase Response Akhir: Cleanup

Setelah semua pemrosesan selesai:

  1. Post-Processing: Metode postHandle() dan afterCompletion() dari Interceptors dijalankan untuk penyesuaian akhir atau pembersihan sumber daya.
  2. Pengiriman: DispatcherServlet menyerahkan HttpServletResponse yang sudah lengkap kembali ke Tomcat.
  3. Klien Menerima: Tomcat mengirimkan respons HTTP final (berisi JSON, XML, atau HTML) kepada klien. 

 8. Contoh Konkrit di SpringBoot 

Kita akan membuat contoh konkret implementasi Front Controller Pattern di Spring Boot menggunakan DispatcherServlet sebagai front controllernya. Tujuannya agar  paham cara kerja internal Front Controller Pattern dalam konteks Spring MVC, di mana DispatcherServlet berperan sebagai pengendali utama yang mengatur alur request–response ke controller yang tepat.

Konsep Singkat  

Di Front Controller Pattern, setiap request yang masuk tidak langsung menuju controller spesifik, tapi akan melewati satu titik masuk utama yakni DispatcherServlet.  DispatcherServlet bertugas meneruskan request ke controller yang sesuai (berdasarkan URL dan method).  Dalam Spring Boot, ini sudah otomatis dikonfigurasi.  Kita tinggal mendefinisikan controller dan route untuk melihat cara kerjanya. 

Struktur Project 

 yboilerplate/
 ├─ src/main/java/com/example/demo/
 │   ├─ DemoApplication.java
 │   ├─ controller/
 │   │   └─ UserController.java
 │   ├─ model/
 │   │   └─ User.java
 │   └─ service/
 │       └─ UserService.java
 └─ pom.xml 

Model User.java    

package com.mhyusuf.yboilerplate.model;

public class User {
private Long id;
private String name;
private String email;

public User() {}

public User(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}

// getters & setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}

Service UserService.java

package com.mhyusuf.yboilerplate.service;

import com.mhyusuf.yboilerplate.model.User;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class UserService {
private final Map<Long, User> userStore = new HashMap<>();
private long counter = 1;

public User createUser(User user) {
user.setId(counter++);
userStore.put(user.getId(), user);
return user;
}

public User updateUser(User user) {
userStore.put(user.getId(), user);
return user;
}

public User getUser(Long id) {
return userStore.get(id);
}

public boolean deleteUser(Long id) {
return userStore.remove(id) != null;
}

public Collection<User> getAllUsers() {
return userStore.values();
}
}

Controller - UserController..java (entry point yang akan di-dispatch)

package com.mhyusuf.yboilerplate.controller;


import com.mhyusuf.yboilerplate.model.User;
import com.mhyusuf.yboilerplate.service.UserService;
import org.springframework.web.bind.annotation.*;

import java.util.Collection;

@RestController
@RequestMapping("/users")
public class UserController {

private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}

// POST /users
@PostMapping
public User createUser(@RequestBody User user) {
return userService.createUser(user);
}

// PUT /users
@PutMapping
public User updateUser(@RequestBody User user) {
return userService.updateUser(user);
}

// GET /users/{id}
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUser(id);
}

// DELETE /users/{id}
@DeleteMapping("/{id}")
public String deleteUser(@PathVariable Long id) {
return userService.deleteUser(id) ? "User deleted" : "User not found";
}

// BONUS: GET /users
@GetMapping
public Collection<User> getAllUsers() {
return userService.getAllUsers();
}
}


Bagaimana DispatcherServlet bekerja di balik layar?

Ketika kita menjalankan aplikasi dan melakukan request misalnya:

POST /users

Alurnya seperti ini:

  1. Semua request ke aplikasi web Spring masuk ke DispatcherServlet (Front Controller).
  2. DispatcherServlet menggunakan HandlerMapping untuk menemukan controller yang cocok (UserController).
  3. Setelah ditemukan, DispatcherServlet meneruskan request ke HandlerAdapter.
  4. HandlerAdapter memanggil metode controller (createUser()).
  5. Setelah controller mengembalikan hasil, DispatcherServlet mengubah hasil tersebut menjadi HTTP response (via HttpMessageConverter seperti Jackson untuk JSON).
  6. Response dikembalikan ke client. 

Contoh Request dengan Curl

#1 Create user dengan @RequestBody

curl -X POST -H "Content-Type: application/json" \
    -d '{"name":"Yusuf","email":"mhyusufibrahim@gmail.com"}' \
    http://localhost:8080/users


// POST /users
@PostMapping
public User createUser(@RequestBody User user) {
return userService.createUser(user);
}

@RequestBody pada endpoint POST /users diatas adalah salah satu komponen penting dalam mekanisme Front Controller Pattern di Spring Boot. 

@RequestBody digunakan untuk mengikat (bind) data dari HTTP Request Body (biasanya format JSON atau XML) menjadi objek Java secara otomatis.

Artinya:

  1. Spring akan membaca body dari HTTP request (misalnya JSON dari frontend atau Postman).
  2. Kemudian Spring akan mengonversinya ke objek User sesuai dengan struktur field-nya (id, name, email, dll).
  3. Proses konversi ini dilakukan oleh DispatcherServlet melalui komponen bernama HttpMessageConverter. 

Alur Kerja di Balik Layar (DispatcherServlet + @RequestBody):

1. Client mengirimkan HTTP POST: 

POST /users
Content-Type: application/json

{
    "name": "Yusuf Ibrahim",
    "email": "mhyusufibrahim@gmail.com"

2. DispatcherServlet (Front Controller) menerima request ini.
3. Ia menemukan controller yang cocok: UserController.createUser().
4. Ia melihat parameter @RequestBody User user.

5. Spring mencari HttpMessageConverter yang cocok:

Karena Content-Type = application/json, maka digunakan MappingJackson2HttpMessageConverter. 

6. Converter ini mengubah JSON → objek Java (User).
7. Objek user yang sudah diisi dikirim ke parameter method.
8. Method createUser() kemudian memproses dan mengembalikan User baru sebagai response.

Kapan Menggunakan @RequestBody ?

Gunakan @RequestBody ketika:

  1. Ingin menerima data JSON/XML dari body request (umum pada REST API).
  2. Endpoint kamu menggunakan metode seperti POST, PUT, atau PATCH.
  3. Tidak perlu digunakan untuk GET atau DELETE, karena kedua metode ini biasanya tidak memiliki body request. 

#2 Get user dengan @PathVariable 

curl http://localhost:8080/users/1



 

// GET /users/{id}
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUser(id);
}

Fungsi Utama @PathVariable

@PathVariable digunakan untuk mengambil nilai dari URL path dan memasukkannya ke parameter method.

Artinya:

  1. Kalau ada {id} di route /users/{id}
  2. Dan client memanggil /users/1
  3. Maka Spring otomatis akan mengisi parameter id dengan nilai 1. 

Cara Kerja di Balik Layar (DispatcherServlet + HandlerMapping)

1. Client kirim request:

GET /users/1


2. DispatcherServlet (front controller) menerima request ini.
Ia mencari handler (controller method) yang cocok berdasarkan path /users/{id}.
3. Ini dilakukan lewat komponen internal bernama HandlerMapping.
4. Setelah method ditemukan (getUser(Long id)), Spring mencocokkan placeholder {id} di URL dengan parameter method.
5. Karena parameter diberi anotasi @PathVariable, Spring tahu bahwa nilai setelah /users/ (yaitu 1) harus dimasukkan ke parameter id.
6. HandlerAdapter memanggil method getUser(1).
7. Method mengembalikan hasil ke DispatcherServlet, lalu diteruskan sebagai HTTP response.

#2b Get user dengan @RequestParams

http://localhost:8080/users/detail?id=1 

@GetMapping("/detail")
public User getUserByParam(@RequestParam(required = false) Long id) {
if (id != null) {
return userService.getUser(id);
}
return null; // atau kembalikan daftar user kalau id null
}

@RequestParam digunakan di Spring untuk mengambil nilai dari parameter di query string, form data, atau request body tipe application/x-www-form-urlencoded, lalu memasukkannya ke parameter method controller. 

Saat user hit /users/detail?id=1 Maka Spring otomatis akan:

  • Membaca parameter id dari URL,

  • Mengubah nilainya ("1") ke tipe data Long,

  • Dan memasukannya ke parameter id dalam method.

#3 Update user
curl -X PUT -H "Content-Type: application/json" \
    -d '{"id":1,"name":"Yusuf Updated","email":"updated@gmail.com"}' \
    http://localhost:8080/users


// PUT /users
@PutMapping
public User updateUser(@RequestBody User user) {
return userService.updateUser(user);
}


#4 Delete user
curl -X DELETE http://localhost:8080/users/1 

 

  

// DELETE /users/{id}
@DeleteMapping("/{id}")
public String deleteUser(@PathVariable Long id) {
return userService.deleteUser(id) ? "User deleted" : "User not found";
}

 

Komponen Peran
DispatcherServlet Front Controller utama di Spring MVC
HandlerMapping Mencocokkan URL ke Controller
HandlerAdapter Memanggil metode yang sesuai di Controller
Controller Menangani request dan menghasilkan response
ViewResolver (Jika non-REST) Menentukan view yang akan ditampilkan
HttpMessageConverter Mengubah objek Java <-> JSON/XML

@PostMapping dan @PutMapping dan sejenisnya bukan bagian dari DispatcherServlet secara langsung, tapi bekerja di atas DispatcherServlet."

Dalam pembahasan ini, kita telah mempelajari cara kerja Front Controller Pattern melalui DispatcherServlet di Spring Boot. Kita melihat bagaimana setiap permintaan (request) dari client pertama kali diterima oleh DispatcherServlet, lalu diarahkan (dispatch) ke controller yang sesuai berdasarkan route mapping yang kita definisikan menggunakan anotasi seperti @PostMapping, @PutMapping, @GetMapping, dan @DeleteMapping.

Kita juga memahami beberapa konsep penting dalam penanganan request di Spring Boot:

  • @RequestBody digunakan untuk mengambil data dari body request (biasanya JSON) dan mengonversinya menjadi objek Java.

  • @PathVariable digunakan untuk mengambil nilai dari URL path (misalnya /users/{id}id diambil dari path).

  • @RequestParam digunakan untuk mengambil nilai dari query parameter (misalnya /users?id=1id diambil dari parameter).

Dengan memahami perbedaan antara @RequestBody, @PathVariable, dan @RequestParam, kita kini dapat mengelola berbagai jenis input dari client dengan lebih fleksibel.

Secara keseluruhan, pembelajaran ini memberikan pemahaman menyeluruh tentang bagaimana Spring Boot mengimplementasikan Front Controller Pattern melalui DispatcherServlet, dan bagaimana kita sebagai developer dapat memanfaatkan konsep ini untuk membangun REST API yang terstruktur, bersih, dan mudah dikembangkan.

Intinya: DispatcherServlet adalah jantung dari request handling di Spring Boot — semua permintaan masuk melewati satu gerbang pusat, yang kemudian mendistribusikannya ke controller yang sesuai berdasarkan konfigurasi routing kita.

 

 

 

Comments

Popular posts from this blog

Numpang Kerja Remote dari Bandung Creative Hub

Numpang Kerja Remote dari Bandung Digital Valley

Cara Decompile berkas Dex dan Apk Android