Kembali ke Beranda
Web Development

Belajar Spring Boot dan React JS dari Nol: Tutorial CRUD Lengkap untuk Pemula

Panduan langkah demi langkah membangun aplikasi CRUD menggunakan Spring Boot dan React JS untuk pemula yang sudah memahami dasar Java. Mulai dari instalasi JDK, IntelliJ IDEA, Node.js, dan VS Code, membuat REST API, menghubungkan database H2, hingga membangun antarmuka React yang dapat menambah, menampilkan, mengubah, dan menghapus data. Dilengkapi penjelasan konsep, struktur project, contoh kode, pengujian, dan solusi error yang sering ditemukan.

Membangun aplikasi web modern tidak harus dimulai dengan teknologi yang rumit. Jika Anda sudah memahami dasar pemrograman Java, seperti class, object, method, dan variabel, sebenarnya Anda sudah memiliki modal yang cukup untuk mulai belajar pengembangan aplikasi web.

Dalam tutorial ini, kita akan membangun aplikasi Manajemen Produk menggunakan Spring Boot sebagai backend dan React JS sebagai frontend.

Tutorial ini ditulis untuk pemula. Kita tidak akan langsung melompat ke penulisan kode, tetapi memulai dari instalasi software, pengenalan konsep, pembuatan project, sampai aplikasi CRUD benar-benar dapat digunakan.

1. Apa yang Akan Kita Buat?

Kita akan membuat aplikasi sederhana untuk mengelola data produk dengan empat kemampuan utama:

  • Create: Menambahkan produk baru.
  • Read: Melihat daftar produk.
  • Update: Mengubah informasi produk.
  • Delete: Menghapus produk.

Setiap produk memiliki tiga atribut:

AtributContoh
ID1
Nama ProdukLaptop Asus
Harga8500000

Aplikasi akan memiliki sebuah form untuk memasukkan nama dan harga produk, serta tabel yang menampilkan seluruh produk yang tersimpan.

Ketika pengguna menekan tombol Simpan, React akan mengirim data ke Spring Boot. Spring Boot kemudian memproses dan menyimpan data tersebut ke database.

2. Mengenal Teknologi yang Digunakan

Sebelum menulis kode, penting untuk memahami fungsi masing-masing teknologi.

2.1 Java

Java adalah bahasa pemrograman yang akan kita gunakan untuk membuat backend.

Karena tutorial ini ditujukan bagi pembaca yang sudah memahami Java dasar, kita tidak akan membahas kembali konsep variabel, class, dan method secara mendalam.

2.2 Spring Boot

Spring Boot adalah framework berbasis Java yang mempermudah pembuatan aplikasi backend.

Dengan Spring Boot, kita tidak perlu mengonfigurasi web server secara manual untuk menjalankan REST API sederhana.

Spring Boot menyediakan berbagai fitur seperti:

  • Embedded web server.
  • Dependency Injection.
  • REST API.
  • Integrasi database.
  • Validasi data.
  • Pengelolaan konfigurasi aplikasi.

2.3 React JS

React adalah library JavaScript untuk membangun antarmuka pengguna.

Jika Spring Boot menangani data dan logika backend, React menangani apa yang dilihat dan digunakan oleh pengguna di browser.

2.4 Database H2

H2 adalah database ringan yang dapat digunakan langsung dalam aplikasi Java.

Untuk pembelajaran awal, kita menggunakan H2 agar tidak perlu memasang PostgreSQL atau MySQL terlebih dahulu.

Nantinya, konsep yang sama dapat diterapkan menggunakan database lain.

2.5 IntelliJ IDEA dan Visual Studio Code

Kita akan menggunakan dua editor:

  • IntelliJ IDEA: Mengembangkan backend Spring Boot.
  • Visual Studio Code: Mengembangkan frontend React JS.

Penggunaan dua editor bukan suatu kewajiban. Namun, untuk pembelajaran ini, pemisahan tersebut membantu memahami bahwa frontend dan backend adalah dua aplikasi yang berbeda.


BAGIAN I — PERSIAPAN LINGKUNGAN PENGEMBANGAN

3. Instalasi Java Development Kit

Spring Boot membutuhkan Java Development Kit atau JDK.

Dalam tutorial ini kita menggunakan Java 21 LTS.

Langkah Instalasi

  1. Buka https://adoptium.net/
  2. Pilih Eclipse Temurin JDK 21.
  3. Pilih sistem operasi Windows dan arsitektur x64.
  4. Download installer.
  5. Jalankan installer dan ikuti petunjuk.
  6. Aktifkan pengaturan JAVA_HOME dan PATH jika tersedia.

Setelah instalasi selesai, buka Command Prompt.

Jalankan:

java -version

Contoh hasil:

openjdk version "21.0.x"

Periksa juga Java compiler:

javac -version

Contoh:

javac 21.0.x

Jika kedua perintah berhasil, Java siap digunakan.

Catatan: Jika muncul pesan java is not recognized, tutup Command Prompt dan buka kembali. Jika masih gagal, periksa konfigurasi Environment Variables Windows.

4. Instalasi IntelliJ IDEA

IntelliJ IDEA merupakan IDE yang sangat membantu pengembangan aplikasi Java.

Download melalui:

https://www.jetbrains.com/idea/download/

Lakukan instalasi seperti aplikasi Windows pada umumnya.

Untuk tutorial ini, fitur dasar IntelliJ sudah cukup. Kita tidak memerlukan fitur Spring khusus yang berbayar.

5. Instalasi Node.js

Node.js dibutuhkan untuk menjalankan tooling frontend React.

Download dari:

https://nodejs.org/

Pilih versi LTS yang kompatibel dengan Vite.

Setelah instalasi, buka Command Prompt:

node -v

Kemudian:

npm -v

Jika keduanya menampilkan nomor versi, instalasi berhasil.

Apa Perbedaan Node.js dan npm?

Node.js memungkinkan JavaScript dijalankan di luar browser.

Sementara itu, npm adalah package manager yang digunakan untuk mengunduh dan mengelola library JavaScript.

Sebagai analogi:

  • Maven digunakan untuk mengelola dependency Java.
  • npm digunakan untuk mengelola dependency JavaScript.

6. Instalasi Visual Studio Code

Download melalui:

https://code.visualstudio.com/

Setelah terpasang, buka menu Extensions dengan shortcut:

Ctrl + Shift + X

Instal beberapa extension berikut:

  • ESLint.
  • Prettier.
  • ES7+ React/Redux/React-Native Snippets.

ESLint membantu mendeteksi masalah kode, Prettier merapikan penulisan, sedangkan React Snippets menyediakan shortcut penulisan komponen.

7. Membuat Folder Project

Buat folder berikut:

C:\
└── belajar-spring-react\
    ├── backend\
    └── frontend\

Kita akan menggunakan:

  • backend untuk Spring Boot.
  • frontend untuk React.

Kedua aplikasi nantinya dijalankan secara terpisah ketika development.


BAGIAN II — MEMBUAT BACKEND SPRING BOOT

8. Membuat Project Spring Boot

Buka:

https://start.spring.io/

Spring Initializr adalah layanan yang membantu menghasilkan struktur awal project Spring Boot.

Isi pengaturan berikut:

PengaturanNilai
ProjectMaven
LanguageJava
Spring BootVersi stabil 3.x
Groupcom.belajar
Artifactbackend
Namebackend
Package Namecom.belajar.backend
PackagingJar
Java21

Tutorial ini menggunakan keluarga Spring Boot 3.x agar import dan konfigurasi tetap konsisten.

Tambahkan dependency:

  1. Spring Web.
  2. Spring Data JPA.
  3. H2 Database.
  4. Validation.

Klik Generate.

File backend.zip akan diunduh.

Ekstrak isinya ke:

C:\belajar-spring-react\backend

Pastikan file pom.xml berada langsung di folder backend.

9. Membuka Project di IntelliJ

Jalankan IntelliJ IDEA.

Pilih:

File → Open

Kemudian pilih:

C:\belajar-spring-react\backend

Tunggu sampai IntelliJ menyelesaikan proses import Maven dan pengunduhan dependency.

Mengenal Struktur Project

backend/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/belajar/backend/
│   │   │       └── BackendApplication.java
│   │   └── resources/
│   │       └── application.properties
│   └── test/
├── pom.xml
├── mvnw
└── mvnw.cmd

Beberapa file penting:

pom.xml

File konfigurasi Maven. Di dalamnya terdapat informasi project dan dependency.

BackendApplication.java

Class utama yang digunakan untuk menjalankan aplikasi Spring Boot.

application.properties

File konfigurasi aplikasi, seperti port server dan koneksi database.

mvnw.cmd

Maven Wrapper untuk Windows. Dengan file ini, kita dapat menjalankan perintah Maven tanpa harus memasang Maven secara terpisah.

10. Memahami Class Utama Spring Boot

Buka BackendApplication.java.

package com.belajar.backend;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class BackendApplication {

    public static void main(String[] args) {
        SpringApplication.run(
            BackendApplication.class,
            args
        );
    }
}

Bagi yang sudah memahami Java, method berikut tentu familiar:

public static void main(String[] args)

Method ini merupakan titik awal aplikasi.

Perbedaannya, pada Spring Boot kita menjalankan:

SpringApplication.run(
    BackendApplication.class,
    args
);

Perintah tersebut menginisialisasi Spring Application Context, memuat konfigurasi, dan menjalankan web server yang dibutuhkan aplikasi.

Apa Itu Annotation?

Perhatikan:

@SpringBootApplication

Annotation merupakan metadata yang digunakan framework untuk menentukan bagaimana suatu class atau method diperlakukan.

Spring menggunakan annotation secara luas untuk mendefinisikan controller, service, entity, dan konfigurasi.

11. Menjalankan Spring Boot Pertama Kali

Pada IntelliJ, buka BackendApplication.java.

Klik tombol Run di samping method main().

Alternatif melalui terminal:

cd C:\belajar-spring-react\backend
.\mvnw.cmd spring-boot:run

Jika berhasil, akan muncul log serupa:

Tomcat started on port 8080
Started BackendApplication

Buka browser:

http://localhost:8080

Jika muncul halaman error 404, jangan khawatir. Server sudah berjalan, tetapi kita belum membuat endpoint untuk alamat utama.

12. Membuat REST API Pertama

Sebelum membuat CRUD, kita akan membuat endpoint sederhana.

Pada package com.belajar.backend, buat package baru bernama:

controller

Di dalamnya, buat class:

HelloController.java

Isi:

package com.belajar.backend.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Halo dari Spring Boot!";
    }
}

Jalankan kembali aplikasi jika diperlukan.

Buka:

http://localhost:8080/hello

Hasilnya:

Halo dari Spring Boot!

Penjelasan

@RestController menandakan bahwa class menangani permintaan REST API.

@GetMapping("/hello") menghubungkan permintaan HTTP GET pada URL /hello dengan method hello().

Ketika URL tersebut dibuka, Spring Boot menjalankan method dan mengirim hasilnya sebagai HTTP response.


BAGIAN III — DATABASE DAN CRUD BACKEND

13. Konfigurasi Database

Buka:

src/main/resources/application.properties

Isi dengan:

spring.application.name=backend

server.port=8080

# Database H2 berbasis file
spring.datasource.url=jdbc:h2:file:./data/produkdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

# Hibernate
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

# H2 Console
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

Penjelasan

server.port=8080 menentukan port backend.

spring.datasource.url menentukan lokasi database H2.

Karena menggunakan jdbc:h2:file, data akan disimpan dalam file sehingga tetap tersedia setelah aplikasi dihentikan dan dijalankan kembali.

spring.jpa.hibernate.ddl-auto=update mengizinkan Hibernate memperbarui struktur tabel berdasarkan entity Java.

Konfigurasi tersebut cocok untuk belajar, tetapi pada production sebaiknya menggunakan migrasi database yang terkontrol seperti Flyway atau Liquibase.

spring.jpa.show-sql=true menampilkan SQL Hibernate di terminal.

Penting: H2 Console dan konfigurasi database tanpa password dalam tutorial ini hanya untuk lingkungan development lokal.

14. Membuat Entity Product

Buat package:

model

Kemudian buat class:

Product.java

Isi:

package com.belajar.backend.model;

import jakarta.persistence.*;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

import java.math.BigDecimal;

@Entity
@Table(name = "products")
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotBlank(message = "Nama wajib diisi")
    @Column(nullable = false)
    private String nama;

    @NotNull(message = "Harga wajib diisi")
    @DecimalMin(
        value = "0.0",
        message = "Harga tidak boleh negatif"
    )
    @Column(
        nullable = false,
        precision = 19,
        scale = 2
    )
    private BigDecimal harga;

    public Product() {
    }

    public Long getId() {
        return id;
    }

    public String getNama() {
        return nama;
    }

    public void setNama(String nama) {
        this.nama = nama;
    }

    public BigDecimal getHarga() {
        return harga;
    }

    public void setHarga(BigDecimal harga) {
        this.harga = harga;
    }
}

Memahami Entity

@Entity memberi tahu JPA bahwa class ini merepresentasikan data database.

@Table(name = "products") menentukan nama tabel.

@Id menunjukkan primary key.

@GeneratedValue mengatur pembuatan ID otomatis.

@NotBlank digunakan untuk memvalidasi nama produk.

@DecimalMin digunakan untuk memastikan harga tidak negatif.

Mengapa Menggunakan BigDecimal?

Dalam Java, double menggunakan representasi floating-point biner yang tidak selalu dapat merepresentasikan nilai desimal secara tepat.

Untuk nilai uang, BigDecimal lebih sesuai karena mendukung representasi desimal dan aturan pembulatan yang eksplisit.

15. Membuat Repository

Buat package:

repository

Kemudian buat interface:

ProductRepository.java

Isi:

package com.belajar.backend.repository;

import com.belajar.backend.model.Product;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ProductRepository
        extends JpaRepository<Product, Long> {
}

Mungkin muncul pertanyaan: mengapa interface ini tidak memiliki method?

Karena JpaRepository sudah menyediakan operasi dasar seperti:

findAll()
findById(id)
save(product)
delete(product)
existsById(id)

Spring Data JPA akan menyediakan implementasinya secara otomatis.

Kita tidak perlu menulis SQL untuk setiap operasi CRUD sederhana.

16. Membuat Service

Buat package:

service

Kemudian buat class:

ProductService.java

Isi:

package com.belajar.backend.service;

import com.belajar.backend.model.Product;
import com.belajar.backend.repository.ProductRepository;

import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

import java.util.List;

@Service
public class ProductService {

    private final ProductRepository repository;

    public ProductService(ProductRepository repository) {
        this.repository = repository;
    }

    public List<Product> getAllProducts() {
        return repository.findAll();
    }

    public Product getProductById(Long id) {
        return repository.findById(id)
            .orElseThrow(() ->
                new ResponseStatusException(
                    HttpStatus.NOT_FOUND,
                    "Produk tidak ditemukan"
                )
            );
    }

    public Product createProduct(Product product) {
        return repository.save(product);
    }

    public Product updateProduct(Long id, Product data) {
        Product product = getProductById(id);

        product.setNama(data.getNama());
        product.setHarga(data.getHarga());

        return repository.save(product);
    }

    public void deleteProduct(Long id) {
        Product product = getProductById(id);
        repository.delete(product);
    }
}

Mengapa Menggunakan Service?

Secara teknis, Controller dapat memanggil Repository secara langsung.

Namun, pemisahan Service membuat aplikasi lebih mudah dikembangkan.

Misalnya, suatu hari kita ingin menambahkan aturan:

Harga produk tidak boleh lebih rendah dari harga modal.

Aturan tersebut dapat ditempatkan di Service tanpa mencampurkannya dengan kode HTTP pada Controller.

Memahami Dependency Injection

Perhatikan constructor:

public ProductService(ProductRepository repository) {
    this.repository = repository;
}

Kita tidak membuat object Repository secara manual.

Spring akan menyediakan dependency yang dibutuhkan ketika membuat object ProductService.

Konsep ini disebut Dependency Injection.

17. Membuat Controller CRUD

Buat class:

controller/ProductController.java

Isi:

package com.belajar.backend.controller;

import com.belajar.backend.model.Product;
import com.belajar.backend.service.ProductService;

import jakarta.validation.Valid;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/products")
@CrossOrigin(origins = "http://localhost:5173")
public class ProductController {

    private final ProductService service;

    public ProductController(ProductService service) {
        this.service = service;
    }

    @GetMapping
    public List<Product> getAllProducts() {
        return service.getAllProducts();
    }

    @GetMapping("/{id}")
    public Product getProductById(
            @PathVariable Long id) {

        return service.getProductById(id);
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Product createProduct(
            @Valid @RequestBody Product product) {

        return service.createProduct(product);
    }

    @PutMapping("/{id}")
    public Product updateProduct(
            @PathVariable Long id,
            @Valid @RequestBody Product product) {

        return service.updateProduct(id, product);
    }

    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteProduct(
            @PathVariable Long id) {

        service.deleteProduct(id);
    }
}

Mengenal HTTP Method

MethodFungsiEndpoint
GETMengambil seluruh produk/api/products
GETMengambil satu produk/api/products/1
POSTMenambahkan produk/api/products
PUTMemperbarui produk/api/products/1
DELETEMenghapus produk/api/products/1

Apa Itu @RequestBody?

Annotation ini digunakan untuk membaca JSON yang dikirim melalui HTTP request.

Misalnya React mengirim:

{
  "nama": "Laptop Asus",
  "harga": 8500000
}

Spring akan mengubah JSON tersebut menjadi object Java Product.

Apa Itu @PathVariable?

Misalnya kita mengakses:

/api/products/5

Angka 5 akan dibaca melalui:

@PathVariable Long id

Dengan demikian, Spring mengetahui produk mana yang diminta.

Apa Itu CORS?

React akan berjalan pada port 5173, sedangkan Spring Boot berjalan pada port 8080.

Karena origin keduanya berbeda, browser menerapkan aturan Cross-Origin Resource Sharing atau CORS.

Annotation berikut mengizinkan frontend lokal kita mengakses API:

@CrossOrigin(origins = "http://localhost:5173")

CORS bukan mekanisme login atau pengamanan API. Pada aplikasi production, keamanan tetap membutuhkan autentikasi dan otorisasi yang sesuai.

18. Struktur Akhir Backend

Setelah semua class dibuat, struktur backend adalah:

backend/
└── src/
    └── main/
        ├── java/
        │   └── com/belajar/backend/
        │       ├── BackendApplication.java
        │       ├── controller/
        │       │   ├── HelloController.java
        │       │   └── ProductController.java
        │       ├── model/
        │       │   └── Product.java
        │       ├── repository/
        │       │   └── ProductRepository.java
        │       └── service/
        │           └── ProductService.java
        └── resources/
            └── application.properties

19. Menguji Backend

Jalankan aplikasi melalui IntelliJ.

Buka browser:

http://localhost:8080/api/products

Jika belum ada data, responsnya:

[]

Ini berarti API berhasil dijalankan.

Menambahkan Produk Menggunakan PowerShell

Buka PowerShell:

$body = @{
    nama = "Laptop Asus"
    harga = 8500000
} | ConvertTo-Json

Invoke-RestMethod `
    -Uri "http://localhost:8080/api/products" `
    -Method Post `
    -ContentType "application/json" `
    -Body $body

Contoh respons:

{
  "id": 1,
  "nama": "Laptop Asus",
  "harga": 8500000.00
}

Melihat Seluruh Produk

Invoke-RestMethod `
    -Uri "http://localhost:8080/api/products"

Mengubah Produk

$body = @{
    nama = "Laptop Asus Gaming"
    harga = 9500000
} | ConvertTo-Json

Invoke-RestMethod `
    -Uri "http://localhost:8080/api/products/1" `
    -Method Put `
    -ContentType "application/json" `
    -Body $body

Menghapus Produk

Invoke-RestMethod `
    -Uri "http://localhost:8080/api/products/1" `
    -Method Delete

Pastikan ID yang digunakan memang tersedia di database.

Jika seluruh pengujian berhasil, backend CRUD kita sudah selesai.

20. Melihat Database H2

Buka:

http://localhost:8080/h2-console

Masukkan:

JDBC URL : jdbc:h2:file:./data/produkdb
Username : sa
Password :

Biarkan password kosong sesuai konfigurasi tutorial.

Klik Connect.

Jalankan SQL:

SELECT * FROM PRODUCTS;

Anda akan melihat isi tabel produk.

Perlu diperhatikan bahwa path database bersifat relatif terhadap working directory aplikasi. Untuk menghindari kebingungan, jalankan backend dari folder project yang sama setiap kali.


BAGIAN IV — MEMBUAT FRONTEND REACT JS

21. Mengenal React JS

React menggunakan konsep komponen.

Komponen adalah bagian antarmuka yang dapat digunakan kembali.

Sebagai contoh, sebuah aplikasi dapat terdiri dari:

App
├── Header
├── ProductForm
├── ProductList
└── Footer

Untuk tutorial pertama, kita akan menggunakan satu komponen App agar alur program lebih mudah diikuti.

Setelah memahami dasarnya, barulah aplikasi dapat dipecah menjadi beberapa komponen.

22. Membuat Project React dengan Vite

Buka Command Prompt.

Masuk ke folder project:

cd C:\belajar-spring-react

Jalankan:

npm create vite@latest frontend -- --template react

Jika muncul pertanyaan konfirmasi, pilih opsi yang sesuai untuk melanjutkan pembuatan project.

Masuk ke folder frontend:

cd frontend

Instal dependency:

npm install

Kemudian jalankan:

npm run dev

Jika berhasil, terminal akan menampilkan alamat seperti:

http://localhost:5173/

Buka alamat tersebut melalui browser.

Halaman React bawaan Vite akan ditampilkan.

Jika port 5173 tidak tersedia, Vite dapat memilih port lain. Untuk tutorial ini, gunakan port 5173 agar sesuai dengan konfigurasi CORS backend.

23. Membuka Project React di VS Code

Buka Visual Studio Code.

Pilih:

File → Open Folder

Pilih:

C:\belajar-spring-react\frontend

Struktur project kurang lebih:

frontend/
├── node_modules/
├── public/
├── src/
│   ├── assets/
│   ├── App.css
│   ├── App.jsx
│   ├── index.css
│   └── main.jsx
├── index.html
├── package.json
└── vite.config.js

Mengenal File React

main.jsx

Titik awal React.

App.jsx

Komponen utama aplikasi.

App.css

Styling untuk tampilan App.

index.css

Styling global aplikasi.

package.json

Konfigurasi package dan script npm.

24. Memahami JSX

Pada JavaScript biasa, kita mungkin menulis:

function hello() {
    return "Halo Dunia";
}

Di React, kita dapat menulis:

function App() {
    return <h1>Halo Dunia</h1>;
}

export default App;

Penulisan HTML di dalam JavaScript tersebut disebut JSX.

JSX bukan HTML murni. JSX merupakan sintaks yang diproses oleh tooling React menjadi representasi elemen antarmuka.

25. Memahami useState

Sebelum membuat CRUD, kita perlu memahami konsep state.

Contoh:

import { useState } from "react";

function Counter() {
    const [count, setCount] = useState(0);

    return (
        <div>
            <p>Nilai: {count}</p>

            <button onClick={() => setCount(count + 1)}>
                Tambah
            </button>
        </div>
    );
}

export default Counter;

Perhatikan:

const [count, setCount] = useState(0);

count menyimpan nilai state saat render berlangsung.

setCount digunakan untuk meminta React memperbarui nilai tersebut.

0 adalah nilai awal.

Ketika tombol ditekan, React akan memperbarui state dan merender ulang komponen sehingga nilai baru tampil.

Apa Itu const?

Dalam JavaScript:

const nama = "Laptop";

const berarti binding variabel tidak dapat diisi ulang dengan nilai lain.

Sementara:

let harga = 100000;

let memungkinkan variabel diberi nilai baru.

Dalam React, const sangat sering digunakan karena nilai state diperbarui melalui setter, bukan dengan mengubah variabel secara langsung.

26. Memahami useEffect

React menyediakan Hook useEffect untuk menyinkronkan komponen dengan sistem eksternal, termasuk pengambilan data dari API.

Contoh sederhana:

useEffect(() => {
    console.log("Effect dijalankan");
}, []);

Array kosong [] berarti Effect tidak dijalankan ulang akibat perubahan dependency selama komponen tetap terpasang.

Pada development dengan React Strict Mode, Effect dapat dijalankan lebih dari sekali untuk membantu mendeteksi masalah. Karena itu, pengambilan data sebaiknya dirancang agar aman terhadap pengulangan.


BAGIAN V — MEMBANGUN CRUD REACT

27. Membuat App.jsx

Buka:

src/App.jsx

Hapus seluruh isi bawaan, kemudian ganti dengan kode berikut.

import { useEffect, useState } from "react";
import "./App.css";

const API_URL = "http://localhost:8080/api/products";

function App() {

  // State untuk daftar produk
  const [products, setProducts] = useState([]);

  // State untuk form
  const [nama, setNama] = useState("");
  const [harga, setHarga] = useState("");

  // ID produk yang sedang diedit
  const [editId, setEditId] = useState(null);

  // State untuk informasi proses
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState("");
  const [message, setMessage] = useState("");

  // READ: Mengambil data produk
  async function loadProducts() {
    try {
      const response = await fetch(API_URL);

      if (!response.ok) {
        throw new Error("Gagal mengambil data produk");
      }

      const data = await response.json();

      setProducts(data);

    } catch (err) {
      setError(err.message);
    }
  }

  // Memuat data saat komponen ditampilkan
  useEffect(() => {
    loadProducts();
  }, []);

  // Membersihkan form
  function resetForm() {
    setNama("");
    setHarga("");
    setEditId(null);
  }

  // CREATE dan UPDATE
  async function handleSubmit(event) {
    event.preventDefault();

    if (!nama.trim()) {
      setError("Nama produk wajib diisi");
      return;
    }

    if (
      harga === "" ||
      !Number.isFinite(Number(harga)) ||
      Number(harga) < 0
    ) {
      setError("Harga harus berupa angka tidak negatif");
      return;
    }

    const product = {
      nama: nama.trim(),
      harga: Number(harga)
    };

    const isEditing = editId !== null;

    const url = isEditing
      ? `${API_URL}/${editId}`
      : API_URL;

    const method = isEditing ? "PUT" : "POST";

    try {
      setLoading(true);
      setError("");
      setMessage("");

      const response = await fetch(url, {
        method: method,
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(product)
      });

      if (!response.ok) {
        throw new Error("Gagal menyimpan produk");
      }

      resetForm();

      await loadProducts();

      setMessage(
        isEditing
          ? "Produk berhasil diperbarui"
          : "Produk berhasil ditambahkan"
      );

    } catch (err) {
      setError(err.message);

    } finally {
      setLoading(false);
    }
  }

  // Memilih produk untuk diedit
  function handleEdit(product) {
    setEditId(product.id);
    setNama(product.nama);
    setHarga(String(product.harga));

    setError("");
    setMessage("");
  }

  // DELETE
  async function handleDelete(id) {
    const confirmed = window.confirm(
      "Yakin ingin menghapus produk ini?"
    );

    if (!confirmed) {
      return;
    }

    try {
      setLoading(true);
      setError("");
      setMessage("");

      const response = await fetch(
        `${API_URL}/${id}`,
        {
          method: "DELETE"
        }
      );

      if (!response.ok) {
        throw new Error("Gagal menghapus produk");
      }

      if (editId === id) {
        resetForm();
      }

      await loadProducts();

      setMessage("Produk berhasil dihapus");

    } catch (err) {
      setError(err.message);

    } finally {
      setLoading(false);
    }
  }

  // Format angka menjadi Rupiah
  function formatRupiah(value) {
    return new Intl.NumberFormat("id-ID", {
      style: "currency",
      currency: "IDR",
      maximumFractionDigits: 0
    }).format(value);
  }

  return (
    <div className="container">

      <h1>Manajemen Produk</h1>

      <p className="subtitle">
        CRUD Spring Boot + React JS
      </p>

      <div className="card">

        <h2>
          {editId !== null
            ? "Edit Produk"
            : "Tambah Produk"}
        </h2>

        <form onSubmit={handleSubmit}>

          <div className="form-group">
            <label htmlFor="nama">
              Nama Produk
            </label>

            <input
              id="nama"
              type="text"
              value={nama}
              onChange={(e) => setNama(e.target.value)}
              placeholder="Contoh: Laptop Asus"
              required
            />
          </div>

          <div className="form-group">
            <label htmlFor="harga">
              Harga Produk
            </label>

            <input
              id="harga"
              type="number"
              min="0"
              step="0.01"
              value={harga}
              onChange={(e) => setHarga(e.target.value)}
              placeholder="Contoh: 8500000"
              required
            />
          </div>

          <div className="actions">

            <button
              type="submit"
              disabled={loading}
            >
              {loading
                ? "Memproses..."
                : editId !== null
                  ? "Update Produk"
                  : "Simpan Produk"}
            </button>

            {editId !== null && (
              <button
                type="button"
                className="secondary"
                onClick={resetForm}
              >
                Batal
              </button>
            )}

          </div>
        </form>
      </div>

      {error && (
        <p className="alert error">
          {error}
        </p>
      )}

      {message && (
        <p className="alert success">
          {message}
        </p>
      )}

      <div className="card">

        <h2>Daftar Produk</h2>

        <div className="table-wrapper">

          <table>
            <thead>
              <tr>
                <th>ID</th>
                <th>Nama Produk</th>
                <th>Harga</th>
                <th>Aksi</th>
              </tr>
            </thead>

            <tbody>

              {products.length === 0 ? (

                <tr>
                  <td colSpan="4">
                    Belum ada produk
                  </td>
                </tr>

              ) : (

                products.map((product) => (

                  <tr key={product.id}>

                    <td>{product.id}</td>

                    <td>{product.nama}</td>

                    <td>
                      {formatRupiah(product.harga)}
                    </td>

                    <td>
                      <div className="actions">

                        <button
                          className="edit"
                          disabled={loading}
                          onClick={() => handleEdit(product)}
                        >
                          Edit
                        </button>

                        <button
                          className="delete"
                          disabled={loading}
                          onClick={() => handleDelete(product.id)}
                        >
                          Hapus
                        </button>

                      </div>
                    </td>

                  </tr>

                ))

              )}

            </tbody>
          </table>

        </div>
      </div>

    </div>
  );
}

export default App;

28. Memahami Cara React Berkomunikasi dengan Backend

Perhatikan kode:

const API_URL = "http://localhost:8080/api/products";

Variabel ini menyimpan alamat REST API Spring Boot.

Kemudian:

const response = await fetch(API_URL);

fetch() adalah fungsi JavaScript yang digunakan untuk melakukan HTTP request.

Secara default, fetch() menggunakan metode GET.

Artinya, kode tersebut akan mengirim:

GET /api/products

Ke Spring Boot.

Apa Itu async dan await?

Pada JavaScript, operasi HTTP membutuhkan waktu.

Kita tidak mengetahui apakah respons akan datang dalam 10 milidetik atau beberapa detik.

Karena itu digunakan:

async function loadProducts() {
    const response = await fetch(API_URL);
}

async menandakan bahwa function bekerja secara asynchronous dan mengembalikan Promise.

await menunggu penyelesaian Promise sebelum melanjutkan baris berikutnya dalam function tersebut, tanpa memblokir seluruh browser.

Mengubah JSON Menjadi Object JavaScript

const data = await response.json();

Perintah ini membaca dan mem-parsing body respons JSON.

Misalnya backend mengirim:

[
  {
    "id": 1,
    "nama": "Laptop Asus",
    "harga": 8500000
  }
]

Hasil parsing menjadi array object JavaScript yang dapat digunakan React.

Memperbarui State

setProducts(data);

Ketika state diperbarui, React akan merender ulang bagian tampilan yang bergantung pada state tersebut.

29. Memahami Create dan Update

Perhatikan:

const isEditing = editId !== null;

Jika editId bernilai null, artinya pengguna sedang menambahkan produk.

Jika editId memiliki nilai, misalnya 5, artinya pengguna sedang mengedit produk dengan ID 5.

Kemudian:

const method = isEditing ? "PUT" : "POST";

Ini disebut ternary operator.

Bentuk umumnya:

kondisi ? nilaiJikaBenar : nilaiJikaSalah

Dengan demikian:

  • Produk baru menggunakan POST.
  • Produk yang diedit menggunakan PUT.

30. Memahami JSON.stringify()

Perhatikan:

body: JSON.stringify(product)

Object JavaScript tidak langsung dikirim sebagai JSON string.

JSON.stringify() mengubah object menjadi representasi teks JSON.

Contohnya:

const product = {
    nama: "Mouse",
    harga: 250000
};

Akan dikirim dalam bentuk JSON:

{
  "nama": "Mouse",
  "harga": 250000
}

Spring Boot kemudian membaca JSON tersebut melalui @RequestBody.

31. Memahami Delete

Perhatikan:

const response = await fetch(
    `${API_URL}/${id}`,
    {
        method: "DELETE"
    }
);

Jika ID produk adalah 3, alamat yang dipanggil menjadi:

http://localhost:8080/api/products/3

Dengan HTTP method:

DELETE

Spring Boot akan menjalankan method Controller yang memiliki annotation @DeleteMapping("/{id}").


BAGIAN VI — MEMBUAT TAMPILAN DENGAN CSS

32. Mengubah App.css

Buka:

src/App.css

Hapus isi bawaan, lalu ganti dengan:

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: Arial, sans-serif;
  background: #f4f6f9;
  color: #263238;
}

.container {
  max-width: 960px;
  margin: 40px auto;
  padding: 0 20px;
}

h1 {
  margin-bottom: 6px;
}

h2 {
  margin-top: 0;
  font-size: 20px;
}

.subtitle {
  color: #64748b;
  margin-bottom: 30px;
}

.card {
  background: white;
  padding: 24px;
  border-radius: 12px;
  margin-bottom: 24px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
}

.form-group {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 18px;
}

label {
  font-weight: bold;
}

input {
  padding: 12px;
  border: 1px solid #cbd5e1;
  border-radius: 6px;
  font-size: 15px;
  width: 100%;
}

input:focus {
  outline: 2px solid #93c5fd;
  border-color: #2563eb;
}

.actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

button {
  background: #2563eb;
  color: white;
  padding: 10px 16px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
}

button:hover {
  opacity: 0.9;
}

button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

button.secondary {
  background: #64748b;
}

button.edit {
  background: #d97706;
}

button.delete {
  background: #dc2626;
}

.table-wrapper {
  overflow-x: auto;
}

table {
  width: 100%;
  border-collapse: collapse;
}

th,
td {
  padding: 14px;
  border-bottom: 1px solid #e2e8f0;
  text-align: left;
}

th {
  background: #f8fafc;
}

.alert {
  padding: 14px;
  border-radius: 6px;
  margin-bottom: 20px;
}

.error {
  background: #fee2e2;
  color: #991b1b;
}

.success {
  background: #dcfce7;
  color: #166534;
}

@media (max-width: 600px) {
  .container {
    margin: 20px auto;
  }

  .card {
    padding: 16px;
  }
}

Selanjutnya, buka:

src/index.css

Ganti isinya:

:root {
  font-family: Arial, sans-serif;
  font-synthesis: none;
  text-rendering: optimizeLegibility;
}

body {
  min-width: 320px;
}

Sekarang tampilan aplikasi akan lebih rapi, memiliki form, tombol, tabel, dan pesan status.


BAGIAN VII — MENJALANKAN APLIKASI

33. Menjalankan Backend dan Frontend Bersamaan

Aplikasi kita terdiri dari dua proses.

Terminal Pertama: Backend

Buka IntelliJ IDEA.

Jalankan:

BackendApplication.java

Atau gunakan terminal:

cd C:\belajar-spring-react\backend
.\mvnw.cmd spring-boot:run

Backend berjalan pada:

http://localhost:8080

Terminal Kedua: Frontend

Buka terminal VS Code.

Shortcut:

Ctrl + `

Jalankan:

npm run dev

Frontend berjalan pada:

http://localhost:5173

Penting: Kedua proses harus tetap berjalan. Jika backend dihentikan, React tidak dapat mengambil atau menyimpan data produk.

34. Menguji CRUD Melalui Browser

Buka:

http://localhost:5173

Lakukan pengujian berikut.

Pengujian Create

Isi form:

Nama Produk : Laptop Asus
Harga       : 8500000

Klik Simpan Produk.

Produk akan muncul pada tabel.

Pengujian Read

Refresh halaman browser.

Jika produk masih tampil, berarti React berhasil mengambil data dari backend.

Pengujian Update

Klik Edit pada produk.

Ubah harga:

9500000

Klik Update Produk.

Harga pada tabel akan berubah.

Pengujian Delete

Klik Hapus.

Browser akan menampilkan konfirmasi.

Pilih OK.

Produk akan dihapus dari database dan tabel diperbarui.


BAGIAN VIII — MEMAHAMI ALUR PROGRAM SECARA UTUH

35. Alur Ketika Menambahkan Produk

Misalnya pengguna memasukkan:

Nama  : Keyboard
Harga : 350000

Kemudian menekan Simpan.

Alur yang terjadi:

PENGGUNA
   |
   | Mengisi form
   v
REACT JS
   |
   | POST /api/products
   | JSON:
   | {
   |   "nama": "Keyboard",
   |   "harga": 350000
   | }
   v
SPRING BOOT CONTROLLER
   |
   | createProduct()
   v
SPRING BOOT SERVICE
   |
   | repository.save()
   v
SPRING DATA JPA
   |
   | INSERT
   v
H2 DATABASE
   |
   | Data tersimpan
   v
SPRING BOOT
   |
   | HTTP 201 + JSON
   v
REACT JS
   |
   | Mengambil daftar terbaru
   v
TABEL PRODUK DIPERBARUI

Inilah gambaran sederhana arsitektur aplikasi full stack.

Mengapa Perlu Memisahkan Controller, Service, dan Repository?

Karena masing-masing memiliki tanggung jawab berbeda.

Controller

Menangani komunikasi HTTP.

Service

Menangani logika aplikasi.

Repository

Menangani akses data.

Entity

Merepresentasikan data yang disimpan.

Pemisahan ini membuat aplikasi lebih mudah diuji, diperbaiki, dan dikembangkan.


BAGIAN IX — DEBUGGING UNTUK PEMULA

36. Menggunakan Browser Developer Tools

Ketika aplikasi tidak berjalan sesuai harapan, jangan langsung mengubah kode secara acak.

Gunakan Developer Tools browser.

Pada Chrome atau Edge:

F12

Pilih tab Network.

Kemudian lakukan operasi Simpan Produk.

Anda akan melihat request menuju:

http://localhost:8080/api/products

Klik request tersebut.

Periksa:

  • Request Method.
  • Status Code.
  • Request Payload.
  • Response.

Contoh status HTTP:

StatusArti
200Permintaan berhasil
201Data berhasil dibuat
204Berhasil tanpa response body
400Data request tidak valid
404Endpoint atau data tidak ditemukan
500Terjadi kesalahan server

Jika muncul 400, periksa JSON dan aturan validasi.

Jika muncul 404, periksa URL endpoint dan ID produk.

Jika muncul 500, periksa log Spring Boot di IntelliJ.

37. Menggunakan Debugger IntelliJ

IntelliJ menyediakan debugger untuk memeriksa alur program Java.

Contohnya, buka:

public Product createProduct(Product product) {
    return repository.save(product);
}

Klik area di sebelah kiri nomor baris pada:

return repository.save(product);

Sebuah titik merah akan muncul. Ini disebut breakpoint.

Kemudian:

  1. Hentikan aplikasi jika masih berjalan.
  2. Jalankan melalui tombol Debug di IntelliJ.
  3. Buka React.
  4. Tambahkan produk baru.
  5. IntelliJ akan menghentikan eksekusi sementara pada breakpoint.

Sekarang Anda dapat melihat nilai object product, termasuk nama dan harga.

Debugger sangat berguna untuk memahami bagaimana data berpindah dari React menuju Java.

38. Error yang Sering Ditemukan

Error: Port 8080 Already in Use

Artinya port 8080 sudah digunakan proses lain.

Pada Windows:

netstat -ano | findstr :8080

Periksa PID proses yang menggunakan port tersebut.

Jika proses itu memang milik Anda dan aman dihentikan, gunakan:

taskkill /PID NOMOR_PID /F

Ganti NOMOR_PID dengan PID yang benar. Jangan menghentikan proses yang tidak dikenali.

Alternatifnya, ubah port backend pada application.properties, tetapi alamat API React juga harus disesuaikan.

Error: Failed to Fetch

Biasanya React tidak berhasil menghubungi backend.

Periksa:

  1. Apakah Spring Boot berjalan?
  2. Apakah port backend benar?
  3. Apakah endpoint /api/products bisa dibuka?
  4. Apakah browser menampilkan masalah CORS?
  5. Apakah ada error jaringan di tab Network?

Error: CORS Policy

Pastikan Controller memiliki:

@CrossOrigin(origins = "http://localhost:5173")

Perhatikan bahwa port harus sesuai dengan alamat frontend yang benar-benar digunakan.

Error: npm Is Not Recognized

Artinya Node.js atau npm belum terpasang dengan benar, atau PATH belum diperbarui.

Periksa:

node -v
npm -v

Tutup dan buka kembali terminal setelah instalasi.

Error: Package Does Not Exist

Pada Spring Boot, error ini biasanya disebabkan oleh:

  • Dependency belum diunduh.
  • Import salah.
  • Package Java tidak sesuai.
  • Project Maven belum selesai di-load.

Coba lakukan Maven Reload melalui IntelliJ.

Error: Cannot Resolve Symbol

Periksa nama class, package, dan import.

Contohnya:

import com.belajar.backend.model.Product;

Harus sesuai dengan lokasi class Product.

Error: Database Is Locked

H2 berbasis file umumnya tidak dapat dibuka oleh dua proses yang mencoba mengakses file database yang sama secara tidak kompatibel.

Pastikan tidak ada aplikasi lain yang membuka database tersebut secara terpisah.

Untuk tutorial ini, gunakan H2 Console yang disediakan oleh Spring Boot ketika aplikasi sedang berjalan.

Error: Halaman React Kosong

Buka Developer Tools dan periksa tab Console.

Perhatikan error JavaScript atau JSX.

Kesalahan kecil seperti kurung yang tidak ditutup dapat menyebabkan komponen gagal ditampilkan.


BAGIAN X — MENINGKATKAN PEMAHAMAN

39. Mengapa React Tidak Langsung Mengakses Database?

Pada arsitektur web modern, browser sebaiknya tidak memiliki akses langsung ke database.

Ada beberapa alasan:

Keamanan

Kredensial database tidak boleh disimpan pada kode frontend yang dapat dibaca pengguna.

Validasi

Backend harus memeriksa apakah data yang dikirim memenuhi aturan aplikasi.

Aturan Bisnis

Misalnya harga produk harus lebih besar dari nol, atau hanya pengguna tertentu yang boleh menghapus produk.

Pemeliharaan

Frontend dapat berubah tanpa harus mengubah seluruh mekanisme penyimpanan data.

Karena itu, komunikasi dilakukan melalui REST API.

40. Apa Perbedaan Spring Boot dan React?

Keduanya tidak saling menggantikan.

Spring Boot berfokus pada backend, sedangkan React berfokus pada antarmuka pengguna.

Contohnya:

KebutuhanTeknologi
Menampilkan formReact
Menampilkan tabelReact
Menangani klik tombolReact
Memvalidasi request di serverSpring Boot
Menjalankan logika bisnisSpring Boot
Menyimpan dataSpring Data JPA
Mengelola databaseH2

Validasi pada React membantu pengalaman pengguna, tetapi validasi backend tetap diperlukan karena API dapat dipanggil tanpa melalui React.

41. Apakah Harus Menggunakan Dua Project?

Tidak selalu.

Untuk pembelajaran, kita sengaja memisahkan frontend dan backend.

Strukturnya:

belajar-spring-react/
├── backend/
└── frontend/

Pendekatan ini memiliki keuntungan:

  • Lebih mudah memahami tanggung jawab setiap aplikasi.
  • Frontend dapat dikembangkan secara terpisah.
  • Backend dapat digunakan oleh aplikasi lain.
  • Lebih mudah mempelajari REST API.

Pada tahap deployment, hasil build React dapat dilayani oleh web server terpisah atau dikemas bersama aplikasi backend, tergantung kebutuhan arsitektur.


BAGIAN XI — LANGKAH SELANJUTNYA

42. Mengganti H2 dengan PostgreSQL

Setelah memahami CRUD, langkah berikutnya adalah menggunakan database yang lebih umum untuk aplikasi production, seperti PostgreSQL.

Secara konsep, kita tidak perlu menulis ulang seluruh aplikasi.

Entity, Service, Controller, dan React tetap dapat digunakan.

Perubahan utama meliputi:

  • Menambahkan dependency PostgreSQL JDBC Driver.
  • Mengubah konfigurasi datasource.
  • Membuat database PostgreSQL.
  • Mengatur kredensial secara aman.
  • Mengelola migrasi database.

Ini menunjukkan manfaat penggunaan Spring Data JPA: aplikasi tidak harus bergantung langsung pada SQL database tertentu untuk operasi sederhana.

43. Memecah Komponen React

Dalam tutorial ini, seluruh kode frontend berada di App.jsx.

Untuk aplikasi yang lebih besar, struktur dapat diubah menjadi:

src/
├── components/
│   ├── ProductForm.jsx
│   └── ProductList.jsx
├── services/
│   └── productService.js
├── App.jsx
├── App.css
└── main.jsx

ProductForm menangani form produk.

ProductList menangani tabel.

productService.js menangani komunikasi API.

Pemisahan ini akan membuat kode lebih mudah dipelihara.

44. Fitur Tambahan untuk Latihan

Setelah aplikasi CRUD berhasil, cobalah beberapa pengembangan berikut:

  1. Tambahkan field kategori produk.
  2. Tambahkan field stok.
  3. Tambahkan pencarian berdasarkan nama.
  4. Tambahkan sorting berdasarkan harga.
  5. Tambahkan pagination.
  6. Tambahkan validasi nama produk maksimal 100 karakter.
  7. Tambahkan halaman detail produk.
  8. Tambahkan notifikasi yang lebih menarik.
  9. Tambahkan autentikasi pengguna.
  10. Ganti H2 dengan PostgreSQL.

Mulailah dari satu fitur kecil. Jangan langsung mencoba menambahkan semuanya sekaligus.


BAGIAN XII — CATATAN PENTING SEBELUM PRODUCTION

Aplikasi yang kita buat sudah cukup untuk memahami CRUD, tetapi belum dirancang sebagai aplikasi production.

Beberapa hal yang perlu ditingkatkan adalah:

Keamanan

Tambahkan autentikasi dan otorisasi, misalnya menggunakan Spring Security.

Validasi

Pisahkan request DTO dari Entity agar input API lebih terkontrol.

Error Handling

Gunakan mekanisme penanganan exception yang konsisten agar frontend menerima pesan kesalahan yang jelas.

Database Migration

Gunakan Flyway atau Liquibase untuk mengelola perubahan struktur database.

Konfigurasi

Jangan menyimpan password atau kredensial production langsung di source code.

Testing

Tambahkan unit test dan integration test.

Ketepatan Nilai Uang

Backend sudah menggunakan BigDecimal, tetapi contoh React mengubah harga menjadi JavaScript Number demi kesederhanaan. Untuk aplikasi keuangan yang membutuhkan presisi desimal tinggi, gunakan representasi string atau satuan integer terkecil dengan aturan pembulatan yang jelas.

Optimasi React

Contoh useEffect dalam tutorial cukup untuk latihan, tetapi aplikasi yang lebih kompleks sebaiknya mengelola pembatalan request, loading state, dan kemungkinan respons asynchronous yang datang tidak berurutan.


Kesimpulan

Membangun aplikasi web menggunakan Spring Boot dan React JS sebenarnya dapat dipelajari secara bertahap.

Kuncinya bukan menghafal seluruh annotation Spring atau seluruh fitur React, melainkan memahami bagaimana setiap komponen bekerja dan saling berkomunikasi.

Dari tutorial ini, kita telah mempelajari:

  • Menyiapkan lingkungan Java dan JavaScript.
  • Membuat project Spring Boot menggunakan Maven.
  • Memahami Entity, Repository, Service, dan Controller.
  • Membuat REST API CRUD.
  • Menyimpan data menggunakan H2 dan Spring Data JPA.
  • Membuat frontend menggunakan React dan Vite.
  • Memahami state, Effect, JSX, dan HTTP request.
  • Menghubungkan React dengan Spring Boot.
  • Menguji dan melakukan debugging aplikasi.

Hal terpenting yang perlu dipahami adalah bahwa React bertanggung jawab terhadap pengalaman pengguna, Spring Boot menangani proses aplikasi, dan database bertugas menyimpan data.

Ketika hubungan ketiganya sudah dipahami, pengembangan aplikasi yang lebih kompleks akan terasa jauh lebih mudah.

CRUD mungkin terlihat sederhana, tetapi konsep di baliknya merupakan fondasi dari banyak aplikasi bisnis, mulai dari sistem inventori, aplikasi keuangan, sistem ticketing, hingga platform enterprise.

Belajar software development bukan tentang seberapa banyak framework yang kita kuasai, tetapi seberapa baik kita memahami cara sebuah sistem bekerja.


Referensi


Ditulis untuk pembaca Nirantara yang ingin memulai perjalanan pengembangan aplikasi full stack, dari memahami konsep hingga membangun aplikasi yang benar-benar dapat dijalankan.

spring bootreact jsjavajavascriptrest apicrudfull stack developmenttutorial pemrogramanbelajar spring bootbelajar reactintellij ideavisual studio codevitespring data jpahibernateh2 databaseweb developmentbackend developmentfrontend developmentnirantara
Nirantara Logo

Published by Nirantara

Nirantara is an Indonesian Enterprise AI company specializing in Enterprise AI, RAG, Intelligent Search, and AI Automation. Article written by jsturana.

Learn more about Nirantara