Mastering Spring Boot Parameter Validation: 6 Powerful Techniques

This article walks you through six essential validation strategies for Spring Boot applications, from using JSR‑303 annotations and global exception handling to custom validators, validation groups, cross‑field checks, and integrating a Drools rule engine, all illustrated with complete code examples and best‑practice tips.

Su San Talks Tech
Su San Talks Tech
Su San Talks Tech
Mastering Spring Boot Parameter Validation: 6 Powerful Techniques

First Layer: JSR Specification Basics

1.1 HibernateValidator Quick Start

Use the Hibernate Validator framework to perform parameter validation. Example DTO with annotation constraints:

public class UserDTO {
    @NotBlank(message = "名称不能为空")
    private String name;

    @NotNull(message = "年龄不能为空")
    private Integer age;

    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号不合法")
    private String phone;
}

@PostMapping("/register")
public Result register(@Valid @RequestBody UserDTO user) {
    // business logic ...
}

Technical Points:

Include spring-boot-starter-validation dependency.

Place @Valid on method parameters (not on DTO class).

Handle validation errors via BindingResult.

Second Layer: Global Exception Handling

2.1 Unified Exception Interceptor

Capture validation exceptions globally so internal errors are not exposed to users.

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result handleValidException(MethodArgumentNotValidException e) {
        BindingResult result = e.getBindingResult();
        return Result.fail(result.getFieldError().getDefaultMessage());
    }
}

public class Result<T> {
    private Integer code;
    private String msg;
    private T data;
    public static <T> Result<T> fail(String message) {
        return new Result<>(500, message, null);
    }
}

Anti‑scraping Measures:

Do not expose raw field names to the front‑end.

Manage error messages centrally (e.g., via i18n).

Third Layer: Custom Validation Mastery

3.1 Phone/Email Dual Validation

Create a custom annotation when built‑in constraints are insufficient.

@Target({FIELD, PARAMETER})
@Retention(RUNTIME)
@Constraint(validatedBy = ContactValidator.class)
public @interface Contact {
    String message() default "联系方式格式错误";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

public class ContactValidator implements ConstraintValidator<Contact, String> {
    private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
    private static final Pattern EMAIL_PATTERN = Pattern.compile("^\\w+@\\w+\\.\\w+$");
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return PHONE_PATTERN.matcher(value).matches() || EMAIL_PATTERN.matcher(value).matches();
    }
}

Advanced tips: dynamically build error messages with context.buildConstraintViolationWithTemplate() and inject Spring beans into validators.

Fourth Layer: Group Validation

4.1 Different Rules for Create/Update

Define validation groups to apply distinct constraints in different CRUD scenarios.

public interface CreateGroup {}
public interface UpdateGroup {}

public class ProductDTO {
    @Null(groups = UpdateGroup.class)
    @NotNull(groups = CreateGroup.class)
    private Long id;

    @NotBlank(groups = {CreateGroup.class, UpdateGroup.class})
    private String name;
}

@PostMapping("/create")
public Result create(@Validated(CreateGroup.class) @RequestBody ProductDTO dto) {
    // creation logic
}

Notes: the Default group always applies unless explicitly overridden; use @ConvertGroup for group conversion.

Fifth Layer: Cross‑Field Validation

5.1 Password Confirmation Check

Apply a class‑level custom annotation to validate relationships between fields.

@Target(TYPE)
@Retention(RUNTIME)
@Constraint(validatedBy = PasswordValidator.class)
public @interface PasswordValid {
    String message() default "两次密码不一致";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

public class PasswordValidator implements ConstraintValidator<PasswordValid, UserDTO> {
    @Override
    public boolean isValid(UserDTO user, ConstraintValidatorContext context) {
        return user.getPassword().equals(user.getConfirmPassword());
    }
}

@PasswordValid
public class UserDTO {
    private String password;
    private String confirmPassword;
}

Sixth Layer: Rule Engine Integration

6.1 Three Levels of Rule Validation

Hard‑coded if‑else checks (bronze).

Configuration‑driven rules stored in a database (silver).

Dynamic Drools rule engine (gold).

6.2 Drools Rule File Example

// credit_rule.drl
rule "白领贷基础校验"
    when
        $req : LoanRequest(occupation == "白领", salary > 10000, age >= 25 && age <= 45)
    then
        $req.setRiskScore(-10);
end

rule "高危行业拦截"
    when
        $req : LoanRequest(industry in ("赌博业", "传销"), location contains "缅甸")
    then
        throw new ValidationException("阁下莫非是缅北战神?");
end
Rule engine diagram
Rule engine diagram

6.3 Spring Boot Drools Configuration

@Configuration
public class DroolsConfig {
    @Bean
    public KieContainer kieContainer() {
        KieServices ks = KieServices.Factory.get();
        KieFileSystem kfs = ks.newKieFileSystem();
        Resource resource = new ClassPathResource("rules/credit_rule.drl");
        kfs.write(ks.getResources().newInputStreamResource(resource.getInputStream()).setTargetPath("credit_rule.drl"));
        KieBuilder kieBuilder = ks.newKieBuilder(kfs).buildAll();
        return ks.newKieContainer(kieBuilder.getKieModule().getReleaseId());
    }
}

@PostMapping("/apply")
public Result applyLoan(@RequestBody LoanRequest request) {
    kieSession.insert(request);
    kieSession.fireAllRules();
    return riskService.process(request);
}

6.4 Sandbox Protection

Limit the number of eval() calls in rules.

Create a separate KieSession per request.

Set rule execution timeout to prevent runaway processing.

6.5 Counter‑measures

Route rule submissions through an approval workflow.

Disable update / modify keywords in production.

Implement version rollback for rule sets.

Master Guide: Validation Levels

Level

Technique

Difficulty

Applicable Scenario

Impact

Bronze

if‑else hard coding

★☆☆

Small utility classes

⚡⚡⚡

Silver

JSR annotation magic

★★☆

Typical CRUD

⚡⚡

Gold

Global exception interception

★★★

RESTful APIs

Platinum

Custom validation rules

★★★☆

Complex business logic

Diamond

Composite condition validation

★★★★

Cross‑field constraints

King

Rule engine integration

★★★★★

Dynamic risk scenarios

Avoid Common Pitfalls

Do not stack more than three validation layers in the controller; delegate to the service layer.

Separate business rule validation from basic format validation.

Always keep server‑side validation; client‑side checks only guard against accidental misuse.

Hide sensitive details in error messages (e.g., use generic "account or password incorrect").

Effective parameter validation is invisible until it fails; a well‑designed validation layer prevents system crashes and protects both users and services.

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.

Exception HandlingSpring BootCustom AnnotationHibernate ValidatorParameter ValidationDrools
Su San Talks Tech
Written by

Su San Talks Tech

Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.

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.