Say Goodbye to if‑else: Elegant Parameter Validation in Spring Boot

This article walks through why manual if‑else checks are cumbersome for API input validation, introduces Java Bean Validation (JSR‑303/349/380) and its implementations, shows how to use @Validated and @Valid annotations in Spring Boot, and demonstrates unified exception handling for clean error responses.

Architect's Guide
Architect's Guide
Architect's Guide
Say Goodbye to if‑else: Elegant Parameter Validation in Spring Boot

Overview

When building reliable APIs, validating request parameters is essential to guarantee correct data persistence. The author illustrates a typical menu‑creation validation method that uses dozens of if‑else statements, which quickly becomes unreadable and hard to maintain.

Bean Validation and Implementations

Java introduced the Bean Validation specification in 2009 (JSR‑303) and has since evolved through JSR‑349 and JSR‑380 (2.0). The two most common implementations are Hibernate Validator and Apache BVal . Although Hibernate is often associated with JPA, it also provides a full Bean Validation engine. The article shows Google Trends graphs comparing the popularity of MyBatis, JPA, and Hibernate in China and worldwide, and explains that Spring Boot already pulls in spring-boot-starter-validation, which transitively includes hibernate-validator.

Annotations

The javax.validation.constraints package defines 22 constraint annotations. The author groups them as follows: @NotBlank, @NotEmpty, @NotNull, @Null – null and emptiness checks. @DecimalMax, @DecimalMin, @Digits, @Positive, @PositiveOrZero, @Max, @Min, @Negative, @NegativeOrZero – numeric range checks. @AssertFalse, @AssertTrue – boolean checks. @Size – collection or string length. @Future, @FutureOrPresent, @Past, @PastOrPresent – date checks.

Hibernate‑specific constraints such as @Range, @Length, @URL, @SafeHtml.

Quick Start

First, add the required Maven dependencies (Spring Boot starter web already brings in validation):

<project xmlns="http://maven.apache.org/POM/4.0.0" ...>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.4.RELEASE</version>
  </parent>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- other optional dependencies such as lombok, knife4j, etc. -->
  </dependencies>
</project>

Define a DTO with validation annotations:

package com.ratel.validation.entity;

import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;

@Data
public class UserAddDTO {
    @NotEmpty(message = "登录账号不能为空")
    @Length(min = 5, max = 16, message = "账号长度为 5-16 位")
    @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
    private String username;

    @NotEmpty(message = "密码不能为空")
    @Length(min = 4, max = 16, message = "密码长度为 4-16 位")
    private String password;
}

Apply validation in a controller. The class is annotated with @Validated so that all method parameters are checked. For complex objects, use @Valid on the parameter:

package com.ratel.validation.cotroller;

import com.ratel.validation.entity.UserAddDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import javax.validation.constraints.Min;

@RestController
@RequestMapping("/users")
@Validated
public class UserController {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @GetMapping("/get")
    public UserAddDTO get(@RequestParam("id") @Min(value = 1L, message = "编号必须大于 0") Integer id) {
        logger.info("[get][id: {}]", id);
        UserAddDTO dto = new UserAddDTO();
        dto.setUsername("张三");
        dto.setPassword("123456");
        return dto;
    }

    @PostMapping("/add")
    public void add(@Valid @RequestBody UserAddDTO addDTO) {
        logger.info("[add][addDTO: {}]", addDTO);
    }
}

Run the application and use Swagger (e.g., http://localhost:8080/doc.html#/home) to test the endpoints. Invalid inputs produce detailed error messages.

Differences Between @Valid and @Validated

@Validated

is a Spring‑specific annotation that enables method‑level validation via AOP (using MethodValidationInterceptor). It validates simple parameters directly, so an int or String argument does not need @Valid. @Valid is the standard Bean Validation annotation; it triggers nested validation of object graphs. When a controller method receives a POJO (e.g., UserAddDTO), @Valid ensures each field’s constraints are checked.

Exception Handling

The article provides a global @ControllerAdvice that converts validation failures into a unified JSON response ( CommonResult). It handles: MissingServletRequestParameterException → error code MISSING_REQUEST_PARAM_ERROR. ConstraintViolationException (triggered by @Validated) → error code INVALID_REQUEST_PARAM_ERROR with concatenated messages. BindException and MethodArgumentNotValidException (triggered by @Valid) → same error code with detailed messages.

Any other Exception → generic system error.

@ControllerAdvice(basePackages = "com.ratel.validation.cotroller")
public class GlobalExceptionHandler {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @ResponseBody
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public CommonResult missingServletRequestParameterExceptionHandler(HttpServletRequest req, MissingServletRequestParameterException ex) {
        logger.error("[missingServletRequestParameterExceptionHandler]", ex);
        return CommonResult.error(ServiceExceptionEnum.MISSING_REQUEST_PARAM_ERROR.getCode(),
                ServiceExceptionEnum.MISSING_REQUEST_PARAM_ERROR.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(ConstraintViolationException.class)
    public CommonResult constraintViolationExceptionHandler(HttpServletRequest req, ConstraintViolationException ex) {
        logger.error("[constraintViolationExceptionHandler]", ex);
        StringBuilder detailMessage = new StringBuilder();
        for (ConstraintViolation<?> cv : ex.getConstraintViolations()) {
            if (detailMessage.length() > 0) detailMessage.append(";");
            detailMessage.append(cv.getMessage());
        }
        return CommonResult.error(ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getCode(),
                ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getMessage() + ":" + detailMessage.toString());
    }

    // BindException and MethodArgumentNotValidException handlers omitted for brevity

    @ResponseBody
    @ExceptionHandler(Exception.class)
    public CommonResult exceptionHandler(HttpServletRequest req, Exception e) {
        logger.error("[exceptionHandler]", e);
        return CommonResult.error(ServiceExceptionEnum.SYS_ERROR.getCode(),
                ServiceExceptionEnum.SYS_ERROR.getMessage());
    }
}

Testing the Unified Response

Calling GET /users/get?id=-1 returns a 500 status because ConstraintViolationException is not specially handled. Calling POST /users/add with an invalid JSON body (e.g., username "33" and password "233") returns a 400 status and a JSON payload where the errors field contains concise messages such as “账号长度为 5-16 位” and “密码长度为 4-16 位”. The global handler concatenates these messages into a single readable string.

Bean Validation overview
Bean Validation overview
Java validation ecosystem
Java validation ecosystem
Annotation categories
Annotation categories
Spring Boot starter dependencies
Spring Boot starter dependencies
Exception handling result
Exception handling result
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.

JavaBean ValidationSpring BootREST APIHibernate Validatorparameter validation
Architect's Guide
Written by

Architect's Guide

Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.

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.