Tujuan Praktikum
Setelah praktikum ini, mahasiswa mampu:
- Membuat struktur file untuk CRUD data bagian.
- Menampilkan daftar data bagian.
- Menambah dan mengubah data bagian.
- Menghapus data bagian yang tidak dipakai pegawai.
Persiapan
Siapkan kebutuhan berikut:
- Project Java Web Starter
- Folder `src/java/controller`
- Folder `src/java/dao`
- Folder `src/java/model`
- Folder `web/WEB-INF/views/bagian`
- File `web/WEB-INF/views/partials/sidebar.jsp`
- File `web/assets/css/style.css`
- Tabel `bagian` di database
- Data pegawai jika ingin mencoba hapus relasi
Konsep Singkat
CRUD data bagian dipakai untuk mengelola divisi atau unit kerja pegawai.
Alurnya seperti ini:
/bagian -> BagianServlet.java -> BagianDAO.java -> bagian/daftar.jsp atau bagian/form.jsp
BagianServlet.java menerima request dari browser dan
menentukan apakah halaman yang dibuka adalah daftar, form tambah,
form edit, atau proses hapus.
BagianDAO.java membaca dan menyimpan data ke tabel
bagian.
daftar.jsp dipakai untuk menampilkan tabel data.
form.jsp dipakai untuk menambah dan mengubah data.
Langkah 1 - Buat Folder dan File
Buat file berikut sesuai urutan ini:
src/java/model/Bagian.java
src/java/dao/BagianDAO.java
src/java/controller/BagianServlet.java
web/WEB-INF/views/bagian/daftar.jsp
web/WEB-INF/views/bagian/form.jsp
Kalau folder bagian belum ada, buat dulu di dalam
web/WEB-INF/views/.
1. src/java/model/Bagian.java
package model;
public class Bagian {
private int id;
private String namaBagian;
public Bagian() {
}
public Bagian(int id, String namaBagian) {
this.id = id;
this.namaBagian = namaBagian;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getNamaBagian() {
return namaBagian;
}
public void setNamaBagian(String namaBagian) {
this.namaBagian = namaBagian;
}
}
2. src/java/dao/BagianDAO.java
package dao;
import model.Bagian;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class BagianDAO {
public List<Bagian> findAll() throws SQLException {
String sql = "SELECT id_bagian AS id, nama_bagian "
+ "FROM bagian "
+ "ORDER BY nama_bagian ASC";
List<Bagian> bagianList = new ArrayList<>();
try (Connection conn = DBKoneksi.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
bagianList.add(mapRow(rs));
}
}
return bagianList;
}
public Bagian findById(int id) throws SQLException {
String sql = "SELECT id_bagian AS id, nama_bagian "
+ "FROM bagian "
+ "WHERE id_bagian = ?";
try (Connection conn = DBKoneksi.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, id);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
return mapRow(rs);
}
}
}
return null;
}
public void insert(Bagian bagian) throws SQLException {
String sql = "INSERT INTO bagian (nama_bagian) VALUES (?)";
try (Connection conn = DBKoneksi.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, bagian.getNamaBagian());
ps.executeUpdate();
}
}
public void update(Bagian bagian) throws SQLException {
String sql = "UPDATE bagian "
+ "SET nama_bagian = ? "
+ "WHERE id_bagian = ?";
try (Connection conn = DBKoneksi.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, bagian.getNamaBagian());
ps.setInt(2, bagian.getId());
ps.executeUpdate();
}
}
public void delete(int id) throws SQLException {
String sql = "DELETE FROM bagian WHERE id_bagian = ?";
try (Connection conn = DBKoneksi.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, id);
ps.executeUpdate();
}
}
public boolean existsNama(String namaBagian, int excludeId) throws SQLException {
String sql = "SELECT COUNT(*) "
+ "FROM bagian "
+ "WHERE LOWER(nama_bagian) = LOWER(?) "
+ "AND id_bagian <> ?";
try (Connection conn = DBKoneksi.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, namaBagian);
ps.setInt(2, excludeId);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
return rs.getInt(1) > 0;
}
}
}
return false;
}
private Bagian mapRow(ResultSet rs) throws SQLException {
Bagian bagian = new Bagian();
bagian.setId(rs.getInt("id"));
bagian.setNamaBagian(rs.getString("nama_bagian"));
return bagian;
}
}
3. src/java/controller/BagianServlet.java
package controller;
import dao.BagianDAO;
import dao.PegawaiDAO;
import model.Bagian;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@WebServlet(name = "BagianServlet", urlPatterns = {"/bagian"})
public class BagianServlet extends HttpServlet {
private static final String LIST_PAGE = "/WEB-INF/views/bagian/daftar.jsp";
private static final String FORM_PAGE = "/WEB-INF/views/bagian/form.jsp";
private final BagianDAO bagianDAO = new BagianDAO();
private final PegawaiDAO pegawaiDAO = new PegawaiDAO();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = normalize(request.getParameter("action"));
switch (action) {
case "create" -> showForm(request, response, new Bagian(), new LinkedHashMap<>());
case "edit" -> handleEdit(request, response);
default -> showList(request, response);
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String action = normalize(request.getParameter("action"));
if ("delete".equals(action)) {
handleDelete(request, response);
return;
}
handleSave(request, response);
}
private void showList(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
List<Bagian> bagianList = bagianDAO.findAll();
request.setAttribute("activeMenu", "bagian");
request.setAttribute("bagianList", bagianList);
forwardToLayout(request, response, LIST_PAGE);
} catch (SQLException e) {
throw new ServletException("Gagal mengambil data bagian.", e);
}
}
private void handleEdit(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int id = parseInt(request.getParameter("id"));
if (id <= 0) {
redirectWithMessage(response, request, "/bagian",
"Data bagian tidak valid.", "error");
return;
}
try {
Bagian bagian = bagianDAO.findById(id);
if (bagian == null) {
redirectWithMessage(response, request, "/bagian",
"Data bagian tidak ditemukan.", "error");
return;
}
showForm(request, response, bagian, new LinkedHashMap<>());
} catch (SQLException e) {
throw new ServletException("Gagal membuka form bagian.", e);
}
}
private void handleSave(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Bagian bagian = bind(request);
Map<String, String> errors = validate(bagian);
if (!errors.isEmpty()) {
showForm(request, response, bagian, errors);
return;
}
try {
if (bagian.getId() > 0) {
bagianDAO.update(bagian);
} else {
bagianDAO.insert(bagian);
}
redirectWithMessage(response, request, "/bagian",
"Data bagian berhasil disimpan.", "success");
} catch (SQLException e) {
errors.put("general", "Gagal menyimpan data bagian.");
showForm(request, response, bagian, errors);
}
}
private void handleDelete(HttpServletRequest request, HttpServletResponse response)
throws IOException {
int id = parseInt(request.getParameter("id"));
if (id <= 0) {
redirectWithMessage(response, request, "/bagian",
"Data bagian tidak valid.", "error");
return;
}
try {
Bagian bagian = bagianDAO.findById(id);
if (bagian == null) {
redirectWithMessage(response, request, "/bagian",
"Data bagian tidak ditemukan.", "error");
return;
}
int totalPegawai = pegawaiDAO.countByBagianId(id);
if (totalPegawai > 0) {
redirectWithMessage(response, request, "/bagian",
"Bagian masih dipakai oleh pegawai.", "error");
return;
}
bagianDAO.delete(id);
redirectWithMessage(response, request, "/bagian",
"Data bagian berhasil dihapus.", "success");
} catch (SQLException e) {
redirectWithMessage(response, request, "/bagian",
"Gagal menghapus data bagian.", "error");
}
}
private void showForm(HttpServletRequest request, HttpServletResponse response,
Bagian bagian, Map<String, String> errors)
throws ServletException, IOException {
request.setAttribute("activeMenu", "bagian");
request.setAttribute("bagian", bagian);
request.setAttribute("errors", errors);
request.setAttribute("formTitle", bagian.getId() > 0 ? "Edit Bagian" : "Tambah Bagian");
forwardToLayout(request, response, FORM_PAGE);
}
private Bagian bind(HttpServletRequest request) {
Bagian bagian = new Bagian();
bagian.setId(parseInt(request.getParameter("id")));
bagian.setNamaBagian(trimToNull(request.getParameter("namaBagian")));
return bagian;
}
private Map<String, String> validate(Bagian bagian) {
Map<String, String> errors = new LinkedHashMap<>();
if (bagian.getNamaBagian() == null || bagian.getNamaBagian().isBlank()) {
errors.put("namaBagian", "Nama bagian wajib diisi.");
return errors;
}
try {
if (bagianDAO.existsNama(bagian.getNamaBagian(), bagian.getId())) {
errors.put("namaBagian", "Nama bagian sudah digunakan.");
}
} catch (SQLException e) {
errors.put("general", "Gagal memeriksa data bagian.");
}
return errors;
}
private void forwardToLayout(HttpServletRequest request, HttpServletResponse response,
String contentPage) throws ServletException, IOException {
request.setAttribute("contentPage", contentPage);
request.getRequestDispatcher("/index.jsp").forward(request, response);
}
private void redirectWithMessage(HttpServletResponse response, HttpServletRequest request,
String path, String message, String type) throws IOException {
String target = request.getContextPath() + path
+ "?message=" + URLEncoder.encode(message, StandardCharsets.UTF_8)
+ "&type=" + URLEncoder.encode(type, StandardCharsets.UTF_8);
response.sendRedirect(target);
}
private String normalize(String value) {
return value == null ? "" : value.trim().toLowerCase();
}
private int parseInt(String value) {
try {
return Integer.parseInt(value);
} catch (Exception e) {
return 0;
}
}
private String trimToNull(String value) {
if (value == null) {
return null;
}
String trimmed = value.trim();
return trimmed.isEmpty() ? null : trimmed;
}
}
4. web/WEB-INF/views/bagian/daftar.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<div class="page-header">
<h2>Entry Data Bagian</h2>
</div>
<c:if test="${not empty param.message}">
<div class="${param.type == 'error' ? 'error' : 'success'}">
<c:out value="${param.message}"/>
</div>
</c:if>
<div class="table-toolbar">
<a href="${pageContext.request.contextPath}/bagian?action=create" class="btn btn-add">+ Tambah Bagian</a>
</div>
<div class="card">
<c:choose>
<c:when test="${empty bagianList}">
<div class="info">Belum ada data bagian. Silakan tambahkan data pertama.</div>
</c:when>
<c:otherwise>
<table>
<thead>
<tr>
<th>No</th>
<th>Nama Bagian</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
<c:forEach var="bagian" items="${bagianList}" varStatus="loop">
<tr class="${loop.index % 2 == 1 ? 'genap' : ''}">
<td>${loop.index + 1}</td>
<td><c:out value="${bagian.namaBagian}"/></td>
<td>
<div class="table-actions">
<a class="btn btn-warning"
href="${pageContext.request.contextPath}/bagian?action=edit&id=${bagian.id}">
Edit
</a>
<form class="inline-form"
method="post"
action="${pageContext.request.contextPath}/bagian"
onsubmit="return confirm('Hapus data bagian ini?');">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="${bagian.id}">
<button type="submit" class="btn btn-danger">Hapus</button>
</form>
</div>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</c:otherwise>
</c:choose>
</div>
5. web/WEB-INF/views/bagian/form.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<div class="page-header">
<h2>Entry Data Bagian</h2>
</div>
<div class="card">
<h3><c:out value="${formTitle}" default="Form Bagian"/></h3>
<c:if test="${not empty errors.general}">
<div class="error"><c:out value="${errors.general}"/></div>
</c:if>
<form method="post" action="${pageContext.request.contextPath}/bagian">
<input type="hidden" name="id" value="${bagian.id}">
<div class="form-group">
<label for="namaBagian">Nama Bagian</label>
<input type="text"
id="namaBagian"
name="namaBagian"
value="${bagian.namaBagian}"
placeholder="Contoh: Administrasi"
required>
<c:if test="${not empty errors.namaBagian}">
<div class="error"><c:out value="${errors.namaBagian}"/></div>
</c:if>
</div>
<div class="form-actions">
<button type="submit" class="btn-primary">
<c:choose>
<c:when test="${bagian.id > 0}">Update</c:when>
<c:otherwise>Simpan</c:otherwise>
</c:choose>
</button>
<a href="${pageContext.request.contextPath}/bagian" class="btn btn-secondary">Kembali</a>
</div>
</form>
</div>
Langkah 2 - Sambungkan ke Menu Admin
Setelah model, DAO, controller, dan view selesai, hubungkan halaman ini ke menu admin.
Hal yang perlu dicek:
- menu `Entry Data Bagian` ada di `sidebar.jsp`
- route `/bagian` bisa dibuka dari menu
- tombol tambah, edit, dan hapus sudah mengarah ke `BagianServlet`
- tabel dan form tetap rapi dengan bantuan `style.css`
BagianServlet.java sudah mengatur data dan validasi,
jadi pada tahap ini yang penting adalah memastikan halaman bisa
diakses dari navigasi admin.
Pengujian
Lakukan pengujian berikut:
- Buka
/bagian. - Tambahkan satu data bagian baru.
- Edit data bagian yang baru dibuat.
- Coba simpan nama bagian yang sama.
- Coba hapus bagian yang masih dipakai pegawai.
Troubleshooting
| Masalah | Penyebab | Solusi |
|---|---|---|
| Data tidak tampil | Tabel bagian masih kosong |
Tambahkan data bagian terlebih dahulu |
| Nama bagian ditolak | Nama sudah dipakai data lain | Gunakan nama yang berbeda |
| Data tidak bisa dihapus | Masih dipakai pegawai | Pindahkan pegawai ke bagian lain dulu |
| Form kembali kosong | Validasi gagal | Periksa pesan error di form |
Tugas Praktikum
- Buat folder dan file CRUD data bagian.
- Tambahkan minimal 2 data bagian baru.
- Coba hapus satu bagian yang masih dipakai pegawai, lalu catat pesan yang muncul.
Kesimpulan
CRUD data bagian dibangun dari servlet, DAO, model, dan dua view JSP. Alur ini bisa dipakai sebagai pola dasar untuk CRUD data lain di pertemuan berikutnya.