Kursus Backend Developer Java Lengkap
Kursus Backend Developer Java Lengkap
Spring Boot)
Level: Pemula → Menengah → Siap Produksi
Komponen kursus: Teori, Source Code Lengkap, Latihan, dan Best Practice untuk setiap modul (0–20).
Modul 0 — Orientasi & Setup Lingkungan
Tujuan Modul
• Memahami peran backend dan arsitektur umum.
Kenapa Penting
• Fondasi alat yang benar menghindari hambatan teknis saat belajar.
Teori Inti
• Arsitektur: Client ↔ API ↔ Service ↔ DB ↔ Cache ↔ Message Broker ↔ Observability.
• HTTP dasar (method, status) dan JSON sebagai format pertukaran data.
Contoh Kode #1
// src/main/java/com/example/hello/[Link]
package [Link];
public class Hello {
public static void main(String[] args) {
[Link]("Hello, Backend!");
}
}
Contoh Kode #2
<!-- [Link] -->
<project xmlns="[Link]
xmlns:xsi="[Link]
xsi:schemaLocation="[Link] [Link]
<modelVersion>4.0.0</modelVersion>
<groupId>[Link]</groupId>
<artifactId>hello-backend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<[Link]>17</[Link]>
<[Link]>17</[Link]>
</properties>
</project>
Latihan / Praktikum
1. Instal JDK 17/21 dan verifikasi dengan `java -version`.
Best Practices
• Pakai versi LTS (Java 17/21).
Kenapa Penting
• Sintaks dasar adalah pondasi semua fitur lanjut.
Teori Inti
• Tipe data: byte, short, int, long, float, double, char, boolean.
Contoh Kode #1
// Variabel dan operasi dasar
public class Basics {
public static void main(String[] args) {
int a = 10;
int b = 3;
int sum = a + b;
boolean isGreater = a > b;
[Link]("Sum = " + sum + ", a>b? " + isGreater);
}
}
Contoh Kode #2
// Loop dan kondisi
public class Looping {
public static void main(String[] args) {
for (int i = 1; i <= 5; i++) {
if (i % 2 == 0) [Link](i + " genap");
else [Link](i + " ganjil");
}
}
}
Latihan / Praktikum
1. Buat kalkulator CLI (+, -, *, /) dengan input dari argumen.
Best Practices
• Gunakan nama variabel yang deskriptif.
Kenapa Penting
• OOP memudahkan pemodelan domain nyata.
Teori Inti
• Encapsulation via private field dan getter/setter.
Contoh Kode #1
// Class dan enkapsulasi
public class BankAccount {
private String owner;
private long balance;
public BankAccount(String owner) { [Link] = owner; }
public void deposit(long amount) { [Link] += amount; }
public boolean withdraw(long amount) {
if (amount > balance) return false;
[Link] -= amount; return True;
}
public long getBalance() { return balance; }
public String getOwner() { return owner; }
}
Contoh Kode #2
// Collections dasar
import [Link].*;
public class CollectionsDemo {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
[Link]("Ana"); [Link]("Budi"); [Link]("Ana"); // duplikat boleh di List
Set<String> uniq = new HashSet<>(names); // duplikat hilang
Map<String,Integer> score = new HashMap<>();
[Link]("Ana", 90); [Link]("Budi", 80);
[Link](names); [Link](uniq); [Link](score);
}
}
Latihan / Praktikum
1. Implementasikan kelas `User` dengan equals/hashCode berdasar email.
2. Kelola daftar rekening bank dalam List, hilangkan duplikat pemilik dengan Set.
Best Practices
• Tulis equals/hashCode konsisten bila dipakai di koleksi.
Kenapa Penting
• Error tak tertangani menyebabkan crash; handler global diperlukan.
Teori Inti
• Checked vs unchecked exception, finally, try-with-resources.
Contoh Kode #1
// Custom exception
class InsufficientBalanceException extends RuntimeException {
public InsufficientBalanceException(String msg) { super(msg); }
}
Contoh Kode #2
// Stream API contoh sederhana
import [Link].*;
import [Link];
public class StreamExample {
public static void main(String[] args) {
List<Integer> nums = [Link](1,2,3,4,5,6);
List<Integer> evensSquared = [Link]()
.filter(n -> n % 2 == 0)
.map(n -> n * n)
.collect([Link]());
[Link](evensSquared);
}
}
Latihan / Praktikum
1. Buat util membaca file CSV lalu filter baris tertentu dengan Stream.
Best Practices
• Tangani exception pada lapisan yang tepat; jangan menelan error.
Kenapa Penting
• Data persisten kunci aplikasi backend.
Teori Inti
• DDL vs DML, primary key, foreign key, unique, index.
Contoh Kode #1
-- Skema sederhana
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
roles VARCHAR(100) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT now()
);
Contoh Kode #2
// JDBC koneksi (contoh singkat)
import [Link].*;
public class JdbcDemo {
public static void main(String[] args) throws Exception {
String url = "jdbc:postgresql://localhost:5432/app";
try (Connection c = [Link](url, "user", "pass");
PreparedStatement ps = [Link]("select 1")) {
ResultSet rs = [Link]();
while ([Link]()) [Link]([Link](1));
}
}
}
Latihan / Praktikum
1. Buat tabel banks dan accounts dengan relasi FK.
2. Tulis program CLI untuk insert & list users via JDBC.
Best Practices
• Selalu gunakan PreparedStatement (hindari SQL injection).
Kenapa Penting
• IoC/DI membuat kode mudah diuji dan dirawat.
Teori Inti
• Bean lifecycle singkat, stereotype annotation (@Component/@Service).
Contoh Kode #1
// Aplikasi Spring Boot
@SpringBootApplication
public class AppApplication {
public static void main(String[] args) {
[Link]([Link], args);
}
}
Contoh Kode #2
// Controller sederhana
@RestController
@RequestMapping("/api/health")
public class HealthController {
@GetMapping
public Map<String, Object> health() {
return [Link]("status", "UP", "time", [Link]());
}
}
Latihan / Praktikum
1. Buat endpoint /api/info yang mengembalikan nama aplikasi & versi dari [Link].
Best Practices
• Gunakan constructor injection, bukan field injection.
Kenapa Penting
• DTO menstabilkan kontrak API dan lindungi Entity.
Teori Inti
• Konvensi endpoint, status code (201, 400, 404, 409).
Contoh Kode #1
// DTO
public record CreateUserRequest(@NotBlank @Email String email,
@NotBlank @Size(min=8) String password) {}
public record UserResponse(Long id, String email, String roles) {}
Contoh Kode #2
// Controller tipis
@RestController @RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
private final UserService service;
@PostMapping
public ResponseEntity<UserResponse> create(@Valid @RequestBody CreateUserRequest req) {
return [Link]([Link]).body([Link](req));
}
}
Contoh Kode #3
// Global Exception Handler
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler([Link])
ResponseEntity<Map<String,Object>> handleValidation(MethodArgumentNotValidException ex){
var errors = [Link]().getFieldErrors().stream()
.map(f -> [Link]()+": "+[Link]()).toList();
return [Link]().body([Link]("error","VALIDATION","details",errors));
}
}
Latihan / Praktikum
1. Implement CRUD lengkap untuk resource Category (name unik per user).
Best Practices
• Controller tipis, logika di Service, akses data di Repository.
• Jangan expose entity langsung; gunakan DTO.
Kenapa Penting
• ORM mengurangi boilerplate akses DB.
Teori Inti
• Annotation: @Entity, @Table, @Id, @GeneratedValue.
Contoh Kode #1
@Entity @Table(name="users")
public class User {
@Id @GeneratedValue(strategy=[Link]) Long id;
@Column(nullable=false, unique=true) String email;
@Column(nullable=false) String passwordHash;
@Column(nullable=false) String roles;
}
Contoh Kode #2
@Entity @Table(name="categories")
public class Category {
@Id @GeneratedValue(strategy=[Link]) Long id;
@ManyToOne(fetch=[Link]) @JoinColumn(name="user_id")
private User owner;
@Column(nullable=false) String name;
}
Contoh Kode #3
@Service @RequiredArgsConstructor
public class CategoryService {
private final CategoryRepository repo;
@Transactional
public CategoryResponse create(CreateCategoryRequest req, Long userId){
if([Link](userId, [Link]())){
throw new ConflictException("Category already exists");
}
Category c = new Category();
[Link](new User(){{ setId(userId); }});
[Link]([Link]());
return map([Link](c));
}
}
Latihan / Praktikum
1. Buat skema transaksi (Transaction) dan relasi dengan Category & User.
Best Practices
• Gunakan LAZY untuk koleksi; gunakan fetch join saat perlu.
Kenapa Penting
• Password plaintext berbahaya saat kebocoran.
Teori Inti
• BCrypt dan alasan memilihnya (salt, adaptive cost).
Contoh Kode #1
@Configuration
public class SecurityConfig {
@Bean PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); }
@Bean SecurityFilterChain filter(HttpSecurity http) throws Exception {
[Link](csrf -> [Link]())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**", "/v3/api-docs/**","/swagger-ui/**").permitAll()
.anyRequest().authenticated())
.httpBasic();
return [Link]();
}
}
Contoh Kode #2
@Service @RequiredArgsConstructor
public class AuthService {
private final UserRepository users;
private final PasswordEncoder encoder;
public void register(String email, String rawPassword){
if([Link](email)) throw new ConflictException("Email used");
User u = new User(); [Link](email); [Link]([Link](rawPassword)); u.s
[Link](u);
}
}
Latihan / Praktikum
1. Buat endpoint register dan login basic (sementara HTTP Basic).
Best Practices
• Jangan pernah log atau kirim ulang password.
Kenapa Penting
• JWT cocok untuk aplikasi terdistribusi dan mobile.
Teori Inti
• [Link], HS256 vs RS256.
Contoh Kode #1
// Util JWT ringkas (HS256)
public class JwtUtil {
private final SecretKey key = [Link]([Link]("JWT_SECRET").getBytes(StandardC
public String generate(String subject, Map<String,Object> claims, Duration ttl) {
Instant now = [Link]();
return [Link]()
.setClaims(claims).setSubject(subject)
.setIssuedAt([Link](now))
.setExpiration([Link]([Link](ttl)))
.signWith(key, SignatureAlgorithm.HS256).compact();
}
public Jws<Claims> verify(String token){
return [Link]().setSigningKey(key).build().parseClaimsJws(token);
}
}
Contoh Kode #2
// Filter JWT
public class JwtAuthFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil; private final UserDetailsService uds;
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain ch
throws ServletException, IOException {
String h = [Link]("Authorization");
if(h != null && [Link]("Bearer ")) {
String token = [Link](7);
try {
var jws = [Link](token);
String email = [Link]().getSubject();
UserDetails ud = [Link](email);
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(ud, null, [Link]());
[Link]().setAuthentication(auth);
} catch (Exception e) { /* ignore -> unauthorized */ }
}
[Link](req,res);
}
}
Latihan / Praktikum
1. Implement login yang mengembalikan access token JWT.
Best Practices
• Simpan secret di environment/secret manager.
Kenapa Penting
• Mempercepat integrasi front-end/mobile.
Teori Inti
• springdoc-openapi untuk generasi otomatis.
Contoh Kode #1
<!-- Maven dependency -->
<dependency>
<groupId>[Link]</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.5.0</version>
</dependency>
Contoh Kode #2
@OpenAPIDefinition(info = @Info(title = "MoneyMate API", version = "1.0",
description = "API untuk pengelolaan keuangan"))
@SpringBootApplication
public class App {}
Latihan / Praktikum
1. Lengkapi dokumentasi semua endpoint CRUD dan auth.
Best Practices
• Samakan nama field antara DTO dan dokumentasi.
Kenapa Penting
• Mengurangi regresi dan meningkatkan kepercayaan saat refactor.
Teori Inti
• JUnit 5, Mockito untuk mocking.
Contoh Kode #1
// Unit test service (contoh)
@ExtendWith([Link])
class UserServiceTest {
@Mock UserRepository repo; @InjectMocks UserService service;
@Test void create_user_ok(){
when([Link]("a@[Link]")).thenReturn(false);
var res = [Link](new CreateUserRequest("a@[Link]","password123"));
assertNotNull(res);
}
}
Contoh Kode #2
// Controller slice
@WebMvcTest([Link])
class UserControllerTest {
@Autowired MockMvc mvc; @MockBean UserService service;
@Test void post_create_returns_201() throws Exception {
when([Link](any())).thenReturn(new UserResponse(1L,"a@[Link]","USER"));
[Link](post("/api/users").contentType(MediaType.APPLICATION_JSON)
.content("{\"email\":\"a@[Link]\",\"password\":\"password123\"}"))
.andExpect(status().isCreated());
}
}
Latihan / Praktikum
1. Tambahkan integration test end-to-end untuk alur register → login → akses protected endpoint.
Best Practices
• Tes jalur bahagia dan error (boundary & negative cases).
Kenapa Penting
• Debug cepat saat insiden produksi.
Teori Inti
• SLF4J + Logback, Micrometer + Prometheus, OpenTelemetry tracing.
Contoh Kode #1
// Filter untuk traceId sederhana
@Component
public class TraceFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
String traceId = [Link]().toString();
[Link]("traceId", traceId);
((HttpServletResponse)res).setHeader("X-Trace-Id", traceId);
try { [Link](req, res); } finally { [Link]("traceId"); }
}
}
Latihan / Praktikum
1. Tambahkan counter request per endpoint menggunakan Micrometer.
Best Practices
• Gunakan format JSON untuk log di produksi.
Kenapa Penting
• Pagination mengontrol beban DB.
Teori Inti
• Spring Data Pageable & Sort.
Contoh Kode #1
// Pageable di repository
interface TransactionRepository extends JpaRepository<Transaction, Long> {
Page<Transaction> findByUserId(Long userId, Pageable pageable);
}
Contoh Kode #2
// Cache contoh
@Service @RequiredArgsConstructor
public class BankService {
private final BankRepository repo;
@Cacheable("banks") public List<BankResponse> list(){ return [Link]().stream().map(this::
@CacheEvict(value="banks", allEntries=true) public BankResponse create(CreateBankRequest req){
}
Latihan / Praktikum
1. Tambahkan pagination dan sorting pada /api/transactions.
Best Practices
• Selalu sediakan default page & size yang aman.
Kenapa Penting
• Konsistensi mengurangi kode sisi klien.
Teori Inti
• Format error tunggal (code, message, details, traceId).
Contoh Kode #1
public record ApiError(String code, String message, List<String> details) {}
public record ApiResponse<T>(boolean success, T data, ApiError error, String traceId) {
public static <T> ApiResponse<T> ok(T data){ return new ApiResponse<>(true, data, null, [Link]
public static ApiResponse<?> err(String c, String m, List<String> d){ return new ApiResponse<>(
}
Latihan / Praktikum
1. Pastikan semua exception dipetakan ke error format standar.
Best Practices
• Jangan expose stack trace ke klien.
Kenapa Penting
• Isolasi domain memudahkan testing dan perubahan infrastruktur.
Teori Inti
• Layered: Controller→Service→Repository.
Contoh Kode #1
// Port
public interface BankPort {
List<Bank> list();
Bank save(Bank bank);
}
// Adapter JPA
@Repository
public class BankJpaAdapter implements BankPort {
private final BankRepository repo;
public BankJpaAdapter(BankRepository repo){ [Link] = repo; }
public List<Bank> list(){ return [Link](); }
public Bank save(Bank bank){ return [Link](bank); }
}
Latihan / Praktikum
1. Abstraksikan akses storage kategori sebagai port.
Best Practices
• Domain tidak bergantung pada framework.
Kenapa Penting
• Mengurangi latency request-response.
Teori Inti
• RabbitMQ/Kafka, DLQ, backoff retry.
Contoh Kode #1
// Pseudocode publisher (RabbitTemplate)
@Service @RequiredArgsConstructor
public class TransactionPublisher {
private final RabbitTemplate rabbit;
public void publish(TransactionCreated evt){
[Link]("[Link]","[Link]", evt);
}
}
Latihan / Praktikum
1. Publish event TransactionCreated saat insert transaksi.
Best Practices
• Definisikan skema event stabil.
Kenapa Penting
• CI mencegah broken main.
Teori Inti
• GitHub Actions pipeline: build→test→package.
Contoh Kode #1
# Dockerfile (multi-stage)
FROM maven:3.9-eclipse-temurin-17 as build
WORKDIR /app
COPY . .
RUN mvn -q -DskipTests package
FROM eclipse-temurin:17-jre
WORKDIR /app
COPY --from=build /app/target/[Link] /app/[Link]
USER 1000
ENTRYPOINT ["java","-jar","/app/[Link]"]
Contoh Kode #2
# .github/workflows/[Link]
name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
- run: mvn -q -DskipTests=false test package
Latihan / Praktikum
1. Bangun image Docker dan jalankan bersama PostgreSQL via docker-compose.
Best Practices
• Gunakan non-root user di container.
Kenapa Penting
• Performa buruk = biaya tinggi & UX jelek.
Teori Inti
• JFR, Actuator metrics, profiling DB (EXPLAIN ANALYZE).
Contoh Kode #1
// Projection JPA
public interface TxnSummary {
Long getId(); String getCategoryName(); BigDecimal getAmount();
}
interface TxnRepo extends JpaRepository<Transaction,Long> {
@Query("select [Link] as id, [Link] as categoryName, [Link] as amount from Transaction t join t
Page<TxnSummary> findSummaries(Long uid, Pageable p);
}
Latihan / Praktikum
1. Profiling endpoint paling lambat dan turunkan latensi 30%.
Best Practices
• Ukur sebelum optimasi ('measure, don’t guess').
Kenapa Penting
• Serangan nyata terjadi; pencegahan lebih murah dari penanganan insiden.
Teori Inti
• CORS strict, rate limiting, header keamanan, rotasi secret.
Contoh Kode #1
// Contoh Security Header Filter
@Component
public class SecurityHeaderFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOExcep
HttpServletResponse r = (HttpServletResponse) res;
[Link]("X-Content-Type-Options","nosniff");
[Link]("X-Frame-Options","DENY");
[Link]("X-XSS-Protection","1; mode=block");
[Link](req,res);
}
}
Latihan / Praktikum
1. Tambahkan rate limiter (resilience4j/bucket4j) untuk endpoint login.
Best Practices
• Pisahkan kredensial via secret manager.
Kenapa Penting
• Pembuktian kemampuan dengan proyek nyata.
Teori Inti
• User, Bank, Category, Transaction domain & aturan bisnis.
Contoh Kode #1
// Sketsa endpoint inti
POST /api/auth/register
POST /api/auth/login
GET /api/banks (cached)
POST /api/user-banks (relasi unik)
GET /api/transactions?from=&to=&categoryId=&page=&size=
POST /api/transactions (update saldo total secara transaksional)
Contoh Kode #2
// Contoh Service Transaksi (sketsa)
@Service @RequiredArgsConstructor
public class TransactionService {
private final TxnRepo txns; private final UserBankRepo rels;
@Transactional
public TxnResponse create(CreateTxnRequest req, Long userId){
var rel = [Link]([Link](), userId)
.orElseThrow(() -> new NotFoundException("USER_BANK_NOT_FOUND"));
BigDecimal newBalance = [Link]().add([Link]());
if([Link]([Link]) < 0) throw new ConflictException("NEGATIVE_BALANCE
[Link](newBalance);
var saved = [Link](map(req, rel));
return map(saved);
}
}
Latihan / Praktikum
1. Selesaikan semua endpoint + validasi + dokumentasi.
Best Practices
• Gunakan DTO, error format, dan logging terstruktur.