文档站点
Skip to content

数据校验 ​

Laravel 用 $request->validate([...]) 或 FormRequest 做校验;Spring Boot 用 Jakarta Bean Validation 标准:规则写在 DTO 字段的注解上,@Valid 触发,失败自动抛异常返回 400。

三步使用法 ​

  1. DTO 字段上加校验注解
  2. 控制器参数前加 @Valid(或 @Validated)
  3. 校验失败抛 MethodArgumentNotValidException(由 异常处理 统一转成响应)
java
@Data
public class PostDto {
    @NotBlank(message = "标题不能为空")
    @Size(max = 100, message = "标题最长 100 字")
    private String title;

    @NotBlank(message = "内容不能为空")
    private String content;

    @Min(value = 1, message = "状态最小为 1")
    private Integer status;
}
java
@PostMapping("/posts")
public Post store(@Valid @RequestBody PostDto dto) {
    return service.create(dto);
}

TIP

Laravel 的校验错误默认返回 {"title":["标题不能为空"]};Spring 默认返回 400 和一个标准错误体。返回结构如何统一,见文末和 异常处理。

常用校验注解速查 ​

注解作用类比 Laravel 规则
@NotNull非 nullrequired
@NotBlank非空(字符串去空格后非空)required
@NotEmpty非空(集合/字符串长度>0)required
@Size(min,max)长度范围min:5|max:10
@Min / @Max数值范围min / max
@Email邮箱格式email
@Pattern(regexp)正则regex:...
@Positive正整数integer + min:1
@Past / @Future时间在前后before:... / after:...
@Valid嵌套对象继续校验嵌套规则数组

@NotNull vs @NotBlank

  • @NotNull:值不是 null 就行,空字符串也通过
  • @NotBlank:非 null 且去空格后非空(字符串场景推荐用这个)

分组校验:按场景应用不同规则 ​

一个 DTO 用于「创建」和「更新」时规则不同(更新可空),用分组:

java
public interface Create {}
public interface Update {}

@Data
public class PostDto {
    @NotBlank(groups = Create.class, message = "标题不能为空")
    @Size(max = 100, groups = {Create.class, Update.class})
    private String title;
}
java
@PostMapping("/posts")
public Post store(@Validated(Create.class) @RequestBody PostDto dto) { ... }

@PutMapping("/posts/{id}")
public Post update(@Validated(Update.class) @RequestBody PostDto dto) { ... }

TIP

Laravel 里你通常会写两个 FormRequest(StorePostRequest / UpdatePostRequest)。Spring 用「分组」在一个 DTO 里实现,或直接建两个 DTO。团队可自行选择。

自定义校验规则 ​

场景:校验「标题不能包含敏感词」 ​

写一个注解:

java
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = NoBadWordsValidator.class)
public @interface NoBadWords {
    String message() default "包含敏感词";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

实现校验器:

java
public class NoBadWordsValidator implements ConstraintValidator<NoBadWords, String> {

    private static final List<String> BAD_WORDS = List.of("广告", "赌博");

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null || value.isBlank()) return true;
        return BAD_WORDS.stream().noneMatch(value::contains);
    }
}

使用:

java
@Data
public class PostDto {
    @NoBadWords
    private String title;
}

类比 Laravel

Laravel 里是 Validator::extend('no_bad_words', ...) 或规则类。Spring 里是「注解 + 校验器」成对出现,注解本身不带逻辑,逻辑全在 ConstraintValidator 里。

控制器方法参数直接校验 ​

路径参数和查询参数也能校验(用 @Validated):

java
@RestController
@Validated                       // 类上加,参数校验才生效
public class PostController {

    @GetMapping("/posts/{id}")
    public Post show(@PathVariable @Min(1) Long id,
                     @RequestParam @Size(max = 20) String keyword) {
        ...
    }
}

失败抛 ConstraintViolationException,同样交给异常处理器。

校验失败的统一响应 ​

默认的 400 响应体比较「框架味」。想统一成 {code, message, errors},在全局异常处理器里处理:

java
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ApiResponse<Void> handleValidation(MethodArgumentNotValidException ex) {
        String message = ex.getBindingResult().getFieldErrors().stream()
                .map(f -> f.getField() + ": " + f.getDefaultMessage())
                .collect(Collectors.joining("; "));
        return ApiResponse.of(400, message, null);
    }
}

完整做法见 异常处理。

校验与 Laravel 对照 ​

LaravelSpring Boot
$request->validate([...])DTO 字段注解 + @Valid
FormRequest 类DTO + 校验注解(或分组)
'title' => 'required|max:100'@NotBlank @Size(max=100)
自定义规则自定义注解 + ConstraintValidator
$validator->errors()BindingResult / 异常里的字段错误
abort(422, $errors)抛 MethodArgumentNotValidException

关于 HTTP 状态码

Laravel 校验失败默认 422;Spring 默认 400。如果团队要 REST 语义,可以在异常处理器里把校验错误映射成 422。别混用。

面向 PHP / Laravel 开发者的 Spring Boot 中文文档