Global Error Handling
Relevant source files
The following files were used as context for generating this wiki page:- src/main/java/com/paymaster/backend/presentation/controller/GlobalExceptionHandler.java
- src/main/resources/templates/error.html
- src/main/resources/templates/fragments/layout.html
- src/main/java/com/paymaster/backend/presentation/controller/HomeController.java
- src/main/resources/static/js/app.js
- pom.xml
The PayMaster application implements a centralized error handling mechanism using Spring MVC's @ControllerAdvice. This system is designed to intercept and process exceptions thrown from any controller, ensuring a consistent and user-friendly response to both unexpected system errors and predictable business logic failures.
The mechanism distinguishes between two main types of errors: general, unexpected exceptions which render a dedicated error page, and specific, recoverable exceptions (like invalid arguments) which redirect the user with a transient notification message. This dual approach provides robust failure management while maintaining a smooth user experience for validation-related issues.
Architecture Overview
The global error handling is orchestrated by the GlobalExceptionHandler class, which is annotated with @ControllerAdvice. This annotation allows it to act as a global interceptor for exceptions. When a controller method throws an exception, Spring's DispatcherServlet directs it to the appropriate @ExceptionHandler method within GlobalExceptionHandler.
The following diagram illustrates the high-level data flow for error handling.
Server-Side Handling: GlobalExceptionHandler
The core of the error handling logic resides in GlobalExceptionHandler.java. This class defines methods to handle specific exception types.
Sources: src/main/java/com/paymaster/backend/presentation/controller/GlobalExceptionHandler.java
Class Structure
This diagram shows the GlobalExceptionHandler class and its methods for handling exceptions.
Sources: src/main/java/com/paymaster/backend/presentation/controller/GlobalExceptionHandler.java:11-12
Exception Handlers
The class implements two distinct handlers for different error scenarios.
| Exception Type | Handler Method | Action | Description |
|---|---|---|---|
java.lang.Exception | handleException | Renders error view | A catch-all for any unhandled, unexpected exceptions. It adds the error message to the Model and displays the generic error.html page. |
java.lang.IllegalArgumentException | handleIllegalArgument | Redirects to /dashboard | Handles business logic validation errors (e.g., duplicate national code). It adds the error message as a "flash attribute" and redirects the user, allowing a non-disruptive notification. |
Sources: src/main/java/com/paymaster/backend/presentation/controller/GlobalExceptionHandler.java:23-50
General Exception Handler
This handler catches any generic Exception that isn't handled by a more specific handler. It's designed for unexpected system failures.
// src/main/java/com/paymaster/backend/presentation/controller/GlobalExceptionHandler.java:23-32
@ExceptionHandler(Exception.class)
public String handleException(Exception e, Model model) {
// ثبت خطا در لاگ (باید از یک Logger استفاده شود، اما در اینجا فقط پیام اضافه میشود)
System.err.println("Unexpected error: " + e.getMessage());
model.addAttribute("errorMessage", "خطای غیرمنتظرهای رخ داد: " + e.getMessage());
// فرض میشود یک ویو به نام "error.html" وجود دارد.
return "error";
}
This method logs the error to standard error, adds the message to the Spring Model, and returns the string "error", which instructs Spring MVC to render the error.html template.
Invalid Argument Handler
This handler specifically catches IllegalArgumentException, which is used throughout the application for business rule violations, such as when attempting to save a customer with a duplicate national code.
// src/main/java/com/paymaster/backend/presentation/controller/GlobalExceptionHandler.java:42-50
@ExceptionHandler(IllegalArgumentException.class)
public String handleIllegalArgument(IllegalArgumentException e, RedirectAttributes redirectAttributes) {
System.err.println("IllegalArgumentException: " + e.getMessage());
// اضافه کردن پیام خطا به عنوان Flash Attribute تا پس از Redirect قابل دسترسی باشد.
redirectAttributes.addFlashAttribute("errorMessage", e.getMessage());
// هدایت کاربر به صفحه داشبورد یا صفحه اصلی.
return "redirect:/dashboard";
}
This method uses RedirectAttributes to add the error message as a flash attribute. Flash attributes are stored temporarily (typically in the session) and are available in the request right after the redirect, then removed. This prevents the error message from persisting across multiple requests.
Sources: src/main/java/com/paymaster/backend/presentation/controller/HomeController.java:112-121, src/main/java/com/paymaster/backend/presentation/controller/GlobalExceptionHandler.java:42-50
User Interface Error Display
The application uses two different methods to display errors to the user, corresponding to the two handler types.
1. Generic Error Page
For unrecoverable errors handled by handleException, the user is shown a full error page.
The error.html template is a simple page that displays an icon, a title, and the error message passed from the GlobalExceptionHandler via the Model.
<!-- src/main/resources/templates/error.html:13-14 -->
<h3 class="mt-4 mb-3">خطایی رخ داد!</h3>
<p class="text-muted" th:text="${errorMessage ?: 'متاسفانه مشکلی پیش آمده است. '}">متاسفانه مشکلی پیش آمده است.</p>
The th:text attribute safely displays the errorMessage from the model. If it's not present, a default message is shown.
Sources: src/main/resources/templates/error.html
2. Toast Notifications for Redirects
For validation errors handled by handleIllegalArgument, the error message is displayed as a non-intrusive "toast" notification after the user is redirected. This is a multi-step process involving the backend, a Thymeleaf fragment, and client-side JavaScript.
The following sequence diagram details this flow:
This diagram shows how a validation error triggers a redirect and results in a client-side toast notification.
Sources: src/main/java/com/paymaster/backend/presentation/controller/GlobalExceptionHandler.java:42-50, src/main/resources/templates/fragments/layout.html:112-117, src/main/resources/static/js/app.js:770-782
Thymeleaf Alert Fragment
The fragments/layout.html file contains a reusable alerts fragment. This fragment checks for the presence of errorMessage (passed as a flash attribute) and renders a Bootstrap alert. Critically, it also adds the message to a data-error-message attribute, which is used by the JavaScript.
<!-- src/main/resources/templates/fragments/layout.html:112-117 -->
<div th:if="${errorMessage}" class="alert alert-danger alert-dismissible fade show m-3" role="alert"
th:attr="data-error-message=${errorMessage}">
<i class="bi bi-exclamation-triangle me-2"></i>
<span th:text="${errorMessage}"></span>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
Client-Side Toast Display
The app.js file contains the logic to transform the server-rendered alert div into a toast notification.
// src/main/resources/static/js/app.js:770-782
setupCustomEvents: function() {
// نمایش پیامهای Flash
const successMessage = document.querySelector('[data-success-message]');
const errorMessage = document.querySelector('[data-error-message]');
if (successMessage) {
// ...
}
if (errorMessage) {
// استفاده از data-attribute
Utils.showToast(errorMessage.dataset.errorMessage, 'danger');
errorMessage.removeAttribute('data-error-message');
}
}
On page load, the setupCustomEvents function searches for an element with the data-error-message attribute. If found, it calls Utils.showToast() to display the message and then removes the attribute to prevent it from being shown again.
Sources: src/main/resources/static/js/app.js:140-157, 770-782