How to Add Custom Validation Rules for Admin Inputs in the Mall Project

To add custom validation rules for admin inputs in the Mall project, define a JSR-303 annotation in the validator package, implement the ConstraintValidator interface with your validation logic, and apply the annotation to DTO fields; Spring Boot's @Validated annotation on controller methods automatically enforces these constraints before business logic executes.

The macrozheng/mall repository secures its admin APIs using JSR-303 Bean Validation. When you need to enforce domain-specific constraints—such as validating that a product code matches a specific pattern or that a status flag contains only allowed values—you can extend this system without modifying existing controller code. This guide demonstrates the exact three-step pattern used in mall-admin to create and apply custom validation rules for admin input parameters.

The Validation Architecture in Mall

The project combines JSR-303 annotations with Spring’s @Validated annotation to enforce input constraints. In mall-admin/src/main/java/com/macro/mall/controller/PmsBrandController.java, the create method demonstrates this pattern by accepting a @Validated @RequestBody PmsBrandParam parameter. When Spring processes the request, it automatically triggers all validators associated with annotations on that DTO’s fields.

The system relies on two core components located in mall-admin/src/main/java/com/macro/mall/validator/:

  • FlagValidator.java – A custom annotation that defines validation metadata (allowed values, error messages) and references its validator class via @Constraint(validatedBy = FlagValidatorClass.class).
  • FlagValidatorClass.java – The implementation that contains the actual validation logic, checking whether an integer field matches predefined allowed values.

When validation fails, the global exception handler MallExceptionHandler in mall-common intercepts the error and returns a 400 Bad Request response containing the message defined in the annotation.

Creating a Custom Validation Rule

To implement a new validation rule—such as enforcing that a product code is exactly 8 alphanumeric characters—you follow a three-step pattern identical to the built-in FlagValidator implementation.

Step 1: Define the Annotation

Create a new annotation file in mall-admin/src/main/java/com/macro/mall/validator/. This annotation must be meta-annotated with @Constraint to link it to your validator implementation.

// mall-admin/src/main/java/com/macro/mall/validator/ProductCode.java
package com.macro.mall.validator;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Constraint(validatedBy = ProductCodeValidator.class)
public @interface ProductCode {
    String message() default "invalid product code";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Step 2: Implement the Validator

Implement ConstraintValidator in a companion class. The initialize method captures annotation parameters (if any), while isValid contains the logic that returns true for valid values or false for violations.

// mall-admin/src/main/java/com/macro/mall/validator/ProductCodeValidator.java
package com.macro.mall.validator;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.regex.Pattern;

public class ProductCodeValidator implements ConstraintValidator<ProductCode, String> {
    private static final Pattern PATTERN = Pattern.compile("^[A-Za-z0-9]{8}$");

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return value != null && PATTERN.matcher(value).matches();
    }
}

Step 3: Apply to the DTO

Add the annotation to fields in your request DTO located in mall-admin/src/main/java/com/macro/mall/dto/. The following example shows integration with PmsProductParam (or any admin parameter class):

// mall-admin/src/main/java/com/macro/mall/dto/PmsProductParam.java
package com.macro.mall.dto;

import com.macro.mall.validator.ProductCode;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
public class PmsProductParam {
    @ProductCode(message = "商品编码必须是8位字母或数字")
    @ApiModelProperty(value = "商品唯一编码")
    private String productCode;

    // other fields...
}

Reference Implementation: The FlagValidator Pattern

The existing FlagValidator in the codebase demonstrates the standard for boolean-like status fields. In FlagValidator.java, the annotation declares a String[] value() array that lists allowed integer values (e.g., {"0","1"}) and a default error message.

The corresponding FlagValidatorClass implements ConstraintValidator<FlagValidator, Integer>. Its initialize method stores the allowed values from the annotation, and its isValid method returns true when the supplied integer is either null (treated as optional) or matches any entry in the allowed list.

You can see this applied in PmsBrandParam.java, where factoryStatus and showStatus fields are annotated with:

@FlagValidator(value = {"0","1"}, message = "厂家状态不正确")
private Integer factoryStatus;

When an admin submits an invalid value like 2, Spring rejects the request with a 400 status and the message "厂家状态不正确" before the controller method body executes.

How Spring Enforces Validation

Spring Boot’s MethodValidationPostProcessor (enabled implicitly by the @Validated annotation on controller methods) discovers any annotation meta-marked with @Constraint. It invokes the associated validator’s isValid method before the controller logic runs.

If any constraint fails, Spring collects the errors into a BindingResult and throws a MethodArgumentNotValidException. The MallExceptionHandler in mall-common/src/main/java/com/macro/mall/common/exception/ catches this exception and formats it into a standardized JSON error response. No additional configuration is required—the validator auto-registers because it implements ConstraintValidator and the annotation carries @Constraint.

Summary

  • Define the rule: Create an annotation in mall-admin/src/main/java/com/macro/mall/validator/ and annotate it with @Constraint(validatedBy = YourValidator.class).
  • Implement the logic: Create a class implementing ConstraintValidator<YourAnnotation, FieldType> with custom validation logic in the isValid method.
  • Apply to inputs: Add the annotation to fields in DTOs located in mall-admin/src/main/java/com/macro/mall/dto/.
  • Automatic enforcement: Ensure controller methods use @Validated on request parameters; Spring automatically validates inputs and returns 400 Bad Request for violations via MallExceptionHandler.

Frequently Asked Questions

Where should I place custom validator files in the Mall project?

Place the annotation interface and validator implementation in mall-admin/src/main/java/com/macro/mall/validator/, following the pattern established by FlagValidator.java and FlagValidatorClass.java. This keeps all validation logic centralized and discoverable by Spring's component scan.

How does the Mall project format validation error responses?

Validation failures trigger the MallExceptionHandler class located in mall-common. This global exception handler catches MethodArgumentNotValidException and returns a 400 Bad Request response containing the specific error message defined in your annotation’s message() attribute (e.g., "商品编码必须是8位字母或数字").

Can I validate individual method parameters instead of entire DTOs?

Yes. You can apply your custom annotation directly to method parameters in the controller and add @Validated at the class level or method level. For example, @PostMapping("/test") public Result test(@Validated @ProductCode String code) validates the parameter directly without requiring a wrapper DTO.

Do I need to register the validator in a Spring configuration class?

No. Spring Boot auto-discovers validators that implement ConstraintValidator because the annotation is meta-annotated with @Constraint. As long as your validator class resides in a scanned package (such as com.macro.mall.validator), it automatically wires into the validation pipeline without explicit bean registration.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →