Tujuan Praktikum
Setelah praktikum ini, mahasiswa mampu:
- Menjelaskan alur dashboard admin pada aplikasi.
- Membuat file controller, DAO, dan view untuk dashboard.
-
Menghubungkan dashboard ke layout utama
index.jsp. - Menampilkan menu admin dari
sidebar.jsp. - Menguji tampilan dashboard dari browser.
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/dashboard`
- File `web/index.jsp`
- File `web/WEB-INF/views/partials/header.jsp`
- File `web/WEB-INF/views/partials/sidebar.jsp`
- File `web/WEB-INF/views/partials/footer.jsp`
- File `web/assets/css/style.css`
- Data bagian, pegawai, user, dan presensi di database
Konsep Singkat
Dashboard admin adalah halaman ringkasan untuk user dengan role
admin.
Alurnya seperti ini:
/dashboard -> DashboardServlet.java -> DashboardDAO.java -> dashboard/admin.jsp
DashboardServlet.java menerima request dari browser
lalu menyiapkan data untuk view.
DashboardDAO.java mengambil data ringkasan dari
database.
dashboard/admin.jsp menampilkan hasilnya dalam bentuk
kartu dan grafik.
index.jsp dipakai sebagai layout utama, sedangkan
sidebar.jsp menampilkan menu admin.
Jika tampilan butuh penyesuaian, update juga
web/assets/css/style.css.
Langkah 1 - Buat Folder dan File Dasar
Buat file berikut sesuai urutan ini:
src/java/model/ChartItem.java
src/java/dao/DashboardDAO.java
src/java/controller/DashboardServlet.java
web/WEB-INF/views/dashboard/admin.jsp
web/WEB-INF/views/dashboard/pegawai.jsp
Kalau folder dashboard belum ada, buat dulu di dalam
web/WEB-INF/views/.
1. src/java/model/ChartItem.java
package model;
public class ChartItem {
private String label;
private int value;
private int percent;
public ChartItem() {
}
public ChartItem(String label, int value, int percent) {
this.label = label;
this.value = value;
this.percent = percent;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public int getPercent() {
return percent;
}
public void setPercent(int percent) {
this.percent = percent;
}
}
2. src/java/dao/DashboardDAO.java
package dao;
import model.ChartItem;
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 DashboardDAO {
public int countBagian() throws SQLException {
return count("SELECT COUNT(*) FROM bagian");
}
public int countPegawaiAktif() throws SQLException {
return count("SELECT COUNT(*) FROM pegawai WHERE COALESCE(status_pegawai, 'Aktif') = 'Aktif'");
}
public int countUserAktif() throws SQLException {
return count("SELECT COUNT(*) FROM users WHERE COALESCE(status_user, 'Aktif') = 'Aktif'");
}
public int countPresensiDatangHariIni() throws SQLException {
return count("SELECT COUNT(*) FROM presensi WHERE tanggal = CURDATE() AND jam_masuk IS NOT NULL");
}
public int countPresensiPulangHariIni() throws SQLException {
return count("SELECT COUNT(*) FROM presensi WHERE tanggal = CURDATE() AND jam_pulang IS NOT NULL");
}
public int countPresensiBelumHariIni() throws SQLException {
return Math.max(0, countPegawaiAktif() - countPresensiDatangHariIni());
}
public int countPresensiBulanIni(int pegawaiId) throws SQLException {
String sql = "SELECT COUNT(*) FROM presensi "
+ "WHERE id_pegawai = ? "
+ "AND YEAR(tanggal) = YEAR(CURDATE()) "
+ "AND MONTH(tanggal) = MONTH(CURDATE()) "
+ "AND jam_masuk IS NOT NULL";
return countByPegawai(sql, pegawaiId);
}
public int countPulangBulanIni(int pegawaiId) throws SQLException {
String sql = "SELECT COUNT(*) FROM presensi "
+ "WHERE id_pegawai = ? "
+ "AND YEAR(tanggal) = YEAR(CURDATE()) "
+ "AND MONTH(tanggal) = MONTH(CURDATE()) "
+ "AND jam_pulang IS NOT NULL";
return countByPegawai(sql, pegawaiId);
}
public List<ChartItem> findPegawaiByBagian() throws SQLException {
String sql = "SELECT b.nama_bagian AS label, COUNT(p.id_pegawai) AS total "
+ "FROM bagian b "
+ "LEFT JOIN pegawai p ON p.id_bagian = b.id_bagian "
+ "GROUP BY b.id_bagian, b.nama_bagian "
+ "ORDER BY total DESC, b.nama_bagian ASC";
return findChartItems(sql);
}
public List<ChartItem> findPresensiLastSevenDays() throws SQLException {
String sql = "SELECT DATE_FORMAT(tanggal, '%d/%m') AS label, COUNT(*) AS total "
+ "FROM presensi "
+ "WHERE tanggal >= DATE_SUB(CURDATE(), INTERVAL 6 DAY) "
+ "AND jam_masuk IS NOT NULL "
+ "GROUP BY tanggal "
+ "ORDER BY tanggal ASC";
return findChartItems(sql);
}
public List<ChartItem> findAdminTodayStatus() throws SQLException {
List<ChartItem> items = new ArrayList<>();
int datang = countPresensiDatangHariIni();
int pulang = countPresensiPulangHariIni();
int belum = countPresensiBelumHariIni();
int max = Math.max(1, Math.max(datang, Math.max(pulang, belum)));
items.add(new ChartItem("Sudah Datang", datang, toPercent(datang, max)));
items.add(new ChartItem("Sudah Pulang", pulang, toPercent(pulang, max)));
items.add(new ChartItem("Belum Presensi", belum, toPercent(belum, max)));
return items;
}
public List<ChartItem> findPegawaiMonthStatus(int pegawaiId) throws SQLException {
List<ChartItem> items = new ArrayList<>();
int hadir = countPresensiBulanIni(pegawaiId);
int pulang = countPulangBulanIni(pegawaiId);
int belumPulang = Math.max(0, hadir - pulang);
int max = Math.max(1, Math.max(hadir, Math.max(pulang, belumPulang)));
items.add(new ChartItem("Hadir Bulan Ini", hadir, toPercent(hadir, max)));
items.add(new ChartItem("Pulang Tercatat", pulang, toPercent(pulang, max)));
items.add(new ChartItem("Belum Pulang", belumPulang, toPercent(belumPulang, max)));
return items;
}
public List<ChartItem> findPegawaiLastSevenDays(int pegawaiId) throws SQLException {
String sql = "SELECT DATE_FORMAT(tanggal, '%d/%m') AS label, COUNT(*) AS total "
+ "FROM presensi "
+ "WHERE id_pegawai = ? "
+ "AND tanggal >= DATE_SUB(CURDATE(), INTERVAL 6 DAY) "
+ "AND jam_masuk IS NOT NULL "
+ "GROUP BY tanggal "
+ "ORDER BY tanggal ASC";
List<ChartItem> items = new ArrayList<>();
try (Connection conn = DBKoneksi.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, pegawaiId);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
int total = rs.getInt("total");
items.add(new ChartItem(rs.getString("label"), total, total > 0 ? 100 : 0));
}
}
}
return items;
}
private int count(String sql) throws SQLException {
try (Connection conn = DBKoneksi.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
return rs.getInt(1);
}
}
return 0;
}
private int countByPegawai(String sql, int pegawaiId) throws SQLException {
try (Connection conn = DBKoneksi.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, pegawaiId);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
return rs.getInt(1);
}
}
}
return 0;
}
private List<ChartItem> findChartItems(String sql) throws SQLException {
List<ChartItem> items = new ArrayList<>();
int max = 1;
try (Connection conn = DBKoneksi.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
int total = rs.getInt("total");
max = Math.max(max, total);
items.add(new ChartItem(rs.getString("label"), total, 0));
}
}
for (ChartItem item : items) {
item.setPercent(toPercent(item.getValue(), max));
}
return items;
}
private int toPercent(int value, int max) {
if (value <= 0 || max <= 0) {
return 0;
}
return Math.max(6, Math.round((value * 100f) / max));
}
}
3. src/java/controller/DashboardServlet.java
package controller;
import dao.DashboardDAO;
import dao.PegawaiDAO;
import dao.PresensiDAO;
import model.Pegawai;
import model.Presensi;
import model.User;
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 jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.sql.SQLException;
@WebServlet(name = "DashboardServlet", urlPatterns = {"/dashboard"})
public class DashboardServlet extends HttpServlet {
private static final String ADMIN_PAGE = "/WEB-INF/views/dashboard/admin.jsp";
private static final String PEGAWAI_PAGE = "/WEB-INF/views/dashboard/pegawai.jsp";
private final DashboardDAO dashboardDAO = new DashboardDAO();
private final PegawaiDAO pegawaiDAO = new PegawaiDAO();
private final PresensiDAO presensiDAO = new PresensiDAO();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
User user = getUserLogin(request);
request.setAttribute("activeMenu", "home");
try {
if (user != null && user.isPegawai()) {
showPegawaiDashboard(request, response, user);
return;
}
showAdminDashboard(request, response);
} catch (SQLException e) {
throw new ServletException("Gagal membuka dashboard.", e);
}
}
private void showAdminDashboard(HttpServletRequest request, HttpServletResponse response)
throws SQLException, ServletException, IOException {
request.setAttribute("totalPegawaiAktif", dashboardDAO.countPegawaiAktif());
request.setAttribute("totalBagian", dashboardDAO.countBagian());
request.setAttribute("totalUserAktif", dashboardDAO.countUserAktif());
request.setAttribute("totalDatangHariIni", dashboardDAO.countPresensiDatangHariIni());
request.setAttribute("totalPulangHariIni", dashboardDAO.countPresensiPulangHariIni());
request.setAttribute("totalBelumPresensiHariIni", dashboardDAO.countPresensiBelumHariIni());
request.setAttribute("pegawaiByBagian", dashboardDAO.findPegawaiByBagian());
request.setAttribute("presensiLastSevenDays", dashboardDAO.findPresensiLastSevenDays());
request.setAttribute("presensiTodayStatus", dashboardDAO.findAdminTodayStatus());
forwardToLayout(request, response, ADMIN_PAGE);
}
private void showPegawaiDashboard(HttpServletRequest request, HttpServletResponse response, User user)
throws SQLException, ServletException, IOException {
if (user.getPegawaiId() == null || user.getPegawaiId() <= 0) {
request.setAttribute("message", "Akun ini belum terhubung ke data pegawai.");
forwardToLayout(request, response, PEGAWAI_PAGE);
return;
}
Pegawai pegawai = pegawaiDAO.findById(user.getPegawaiId());
Presensi presensiHariIni = presensiDAO.findTodayByPegawaiId(user.getPegawaiId());
request.setAttribute("pegawai", pegawai);
request.setAttribute("presensiHariIni", presensiHariIni);
request.setAttribute("hadirBulanIni", dashboardDAO.countPresensiBulanIni(user.getPegawaiId()));
request.setAttribute("pulangBulanIni", dashboardDAO.countPulangBulanIni(user.getPegawaiId()));
request.setAttribute("presensiMonthStatus", dashboardDAO.findPegawaiMonthStatus(user.getPegawaiId()));
request.setAttribute("presensiLastSevenDays", dashboardDAO.findPegawaiLastSevenDays(user.getPegawaiId()));
forwardToLayout(request, response, PEGAWAI_PAGE);
}
private User getUserLogin(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session == null) {
return null;
}
Object user = session.getAttribute("userLogin");
return user instanceof User ? (User) user : null;
}
private void forwardToLayout(HttpServletRequest request, HttpServletResponse response,
String contentPage) throws ServletException, IOException {
request.setAttribute("contentPage", contentPage);
request.getRequestDispatcher("/index.jsp").forward(request, response);
}
}
4. web/WEB-INF/views/dashboard/admin.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<div class="page-header">
<h2>Dashboard Admin</h2>
</div>
<div class="stats-grid">
<div class="stat-card">
<span>Pegawai Aktif</span>
<strong>${totalPegawaiAktif}</strong>
</div>
<div class="stat-card">
<span>Bagian</span>
<strong>${totalBagian}</strong>
</div>
<div class="stat-card">
<span>User Aktif</span>
<strong>${totalUserAktif}</strong>
</div>
<div class="stat-card">
<span>Datang Hari Ini</span>
<strong>${totalDatangHariIni}</strong>
</div>
</div>
<div class="dashboard-grid">
<div class="card">
<h3>Status Presensi Hari Ini</h3>
<div class="chart-list">
<c:forEach var="item" items="${presensiTodayStatus}">
<div class="chart-row">
<div class="chart-row__meta">
<span><c:out value="${item.label}"/></span>
<strong>${item.value}</strong>
</div>
<div class="chart-track">
<div class="chart-fill chart-fill--green" style="width: ${item.percent}%"></div>
</div>
</div>
</c:forEach>
</div>
</div>
<div class="card">
<h3>Pegawai per Bagian</h3>
<c:choose>
<c:when test="${empty pegawaiByBagian}">
<div class="info">Belum ada data bagian.</div>
</c:when>
<c:otherwise>
<div class="chart-list">
<c:forEach var="item" items="${pegawaiByBagian}">
<div class="chart-row">
<div class="chart-row__meta">
<span><c:out value="${item.label}"/></span>
<strong>${item.value}</strong>
</div>
<div class="chart-track">
<div class="chart-fill" style="width: ${item.percent}%"></div>
</div>
</div>
</c:forEach>
</div>
</c:otherwise>
</c:choose>
</div>
</div>
<div class="card">
<h3>Tren Presensi 7 Hari Terakhir</h3>
<c:choose>
<c:when test="${empty presensiLastSevenDays}">
<div class="info">Belum ada data presensi 7 hari terakhir.</div>
</c:when>
<c:otherwise>
<div class="bar-chart">
<c:forEach var="item" items="${presensiLastSevenDays}">
<div class="bar-chart__item">
<div class="bar-chart__bar" style="height: ${item.percent}%">
<span>${item.value}</span>
</div>
<small><c:out value="${item.label}"/></small>
</div>
</c:forEach>
</div>
</c:otherwise>
</c:choose>
</div>
5. web/WEB-INF/views/dashboard/pegawai.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<div class="page-header">
<h2>Dashboard Pegawai</h2>
</div>
<c:if test="${not empty message}">
<div class="info"><c:out value="${message}"/></div>
</c:if>
<c:if test="${not empty pegawai}">
<div class="stats-grid">
<div class="stat-card">
<span>Nama Pegawai</span>
<strong><c:out value="${pegawai.namaPegawai}"/></strong>
</div>
<div class="stat-card">
<span>Bagian</span>
<strong><c:out value="${pegawai.bagianNama}"/></strong>
</div>
<div class="stat-card">
<span>Hadir Bulan Ini</span>
<strong>${hadirBulanIni}</strong>
</div>
<div class="stat-card">
<span>Pulang Tercatat</span>
<strong>${pulangBulanIni}</strong>
</div>
</div>
<div class="dashboard-grid">
<div class="card">
<h3>Presensi Hari Ini</h3>
<div class="presensi-status">
<div>
<span>Jam Datang</span>
<strong><c:out value="${presensiHariIni.jamMasuk}" default="-"/></strong>
</div>
<div>
<span>Jam Pulang</span>
<strong><c:out value="${presensiHariIni.jamPulang}" default="-"/></strong>
</div>
</div>
<div class="quick-actions">
<a href="${pageContext.request.contextPath}/presensi" class="btn btn-add">Buka Presensi</a>
<a href="${pageContext.request.contextPath}/profile" class="btn btn-secondary">Profile</a>
</div>
</div>
<div class="card">
<h3>Ringkasan Bulan Ini</h3>
<div class="chart-list">
<c:forEach var="item" items="${presensiMonthStatus}">
<div class="chart-row">
<div class="chart-row__meta">
<span><c:out value="${item.label}"/></span>
<strong>${item.value}</strong>
</div>
<div class="chart-track">
<div class="chart-fill chart-fill--green" style="width: ${item.percent}%"></div>
</div>
</div>
</c:forEach>
</div>
</div>
</div>
<div class="card">
<h3>Presensi 7 Hari Terakhir</h3>
<c:choose>
<c:when test="${empty presensiLastSevenDays}">
<div class="info">Belum ada data presensi 7 hari terakhir.</div>
</c:when>
<c:otherwise>
<div class="bar-chart">
<c:forEach var="item" items="${presensiLastSevenDays}">
<div class="bar-chart__item">
<div class="bar-chart__bar" style="height: ${item.percent}%">
<span>${item.value}</span>
</div>
<small><c:out value="${item.label}"/></small>
</div>
</c:forEach>
</div>
</c:otherwise>
</c:choose>
</div>
</c:if>
Perhatikan urutan file di atas. Kode dibaca dari model, lalu DAO, lalu controller, lalu view.
Langkah 2 - Sambungkan ke Layout Utama
Setelah file utama selesai dibuat, pastikan dashboard masuk ke layout yang sudah ada.
Hal yang perlu dicek:
- `web/index.jsp` memanggil `contentPage` dari servlet
- `web/WEB-INF/views/partials/sidebar.jsp` menampilkan menu admin
- `web/assets/css/style.css` mendukung kartu, grafik, dan sidebar
Untuk dashboard admin, menu yang muncul adalah:
- Home
- Entry Data Bagian
- Entry Data Pegawai
- Manajemen User
Jika tampilan dashboard belum rapi, sesuaikan class CSS yang
dipakai di admin.jsp dan pegawai.jsp.
Pengujian
Lakukan pengujian berikut:
- Login sebagai admin.
- Buka
/dashboard. - Pastikan kartu dan grafik tampil.
- Ubah data di database, lalu refresh halaman.
- Pastikan menu
Hometerlihat aktif.
Troubleshooting
| Masalah | Penyebab | Solusi |
|---|---|---|
| Halaman tidak tampil | Route /dashboard belum dibuat |
Periksa DashboardServlet.java |
| Data angka kosong | Database belum berisi data | Isi bagian, pegawai, user, dan presensi |
| Grafik tidak muncul | Atribut request belum dikirim | Periksa isi DashboardServlet |
| Tampilan berantakan | Class CSS belum ada | Update style.css |
Tugas Praktikum
- Buat dashboard admin sesuai struktur file di atas.
- Tambahkan data di database lalu lihat perubahan angka.
- Catat file apa saja yang terlibat dalam dashboard.
Kesimpulan
Dashboard admin dibangun dari controller, DAO, view, dan layout utama. Data ringkasan diambil dari database lalu ditampilkan sebagai kartu dan grafik.