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.
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("阁下莫非是缅北战神?");
end6.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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
