Master Java Exception Handling in Spring MVC: Custom Exceptions & Global Advice

This article explains how to design and implement robust Java exception handling for business systems using Spring MVC, covering when to create custom exceptions, how to structure service and controller code, and how to centralize error responses with @ControllerAdvice for clean, maintainable backend development.

Programmer DD
Programmer DD
Programmer DD
Master Java Exception Handling in Spring MVC: Custom Exceptions & Global Advice

Why Proper Exception Handling Matters

In large‑scale business systems the majority of bugs stem from unclear error handling, tightly coupled service‑controller code, and missing stack traces, which make debugging and maintenance difficult. Using Spring’s exception mechanism can separate business failures from programming errors and provide clear feedback to callers.

When to Define Custom Exceptions

Throwing a generic AppException everywhere wastes log space and hides the real failure point.

Having only one exception type prevents precise categorisation of error conditions.

Future changes to the exception class become painful because callers must be updated.

Implementing a Business Exception

public class ServiceException extends RuntimeException {
    /** Business processing failure */
    public ServiceException(String reason) {
        super(reason);
    }
}

Controller Layer Example

@PutMapping("{userID}")
public JSONResult updateUser(@PathVariable("userID") Integer userID,
                             @RequestBody UpdateUserForm userForm) {
    User user = new User();
    BeanUtils.copyProperties(userForm, user);
    user.setUserId(userID);
    userService.updateUser(user);
    JSONResult json = new JSONResult();
    json.put("user", user);
    return json;
}

Service Layer Validation and Throwing Exceptions

public void updateUser(User user) {
    User userOrig = userDao.getUserById(user.getUserID());
    if (userOrig == null) {
        throw new ServiceException("User does not exist");
    }
    if (userOrig.isLocked()) {
        throw new ServiceException("User is locked, cannot modify");
    }
    if (!user.getVersion().equals(userOrig.getVersion())) {
        throw new ServiceException("User has been modified by another transaction");
    }
    // TODO: persist user data
}

Global Exception Handling with @ControllerAdvice

@ControllerAdvice(basePackages = {"com.xxx.xxx.bussiness.xxx"})
public class ModuleControllerAdvice {
    private static final Logger LOGGER = LoggerFactory.getLogger(ModuleControllerAdvice.class);
    private static final Logger SERVICE_LOGGER = LoggerFactory.getLogger(ServiceException.class);

    @ExceptionHandler(ServiceException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    private JSONResult handleServiceException(ServiceException exception) {
        String message = "Business processing failed, reason: " + exception.getLocalizedMessage();
        SERVICE_LOGGER.info(message);
        JSONResult json = new JSONResult();
        json.setCode(500001); // 500000 system error, 500001 business error
        json.setMessage(message);
        return json;
    }
}

Classification of Exceptions

Logical exceptions – represent business rule violations that the user caused.

Code errors – programming bugs such as NullPointerException or IllegalArgumentException.

Domain‑specific exceptions – special cases that cannot be anticipated in generic code.

Key Takeaways

Separate business exceptions from system errors and log them independently.

Prefer unchecked (RuntimeException) for business failures to avoid changing method signatures.

Use a single exception class that carries a clear reason message and handle it centrally with @ControllerAdvice.

Never use try‑catch for normal business flow; let exceptions interrupt execution and let the framework manage the response.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaBackend DevelopmentException HandlingSpring MVCcustom-exceptionControllerAdvice
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.