1. Controller参数校验简介
Spring Boot为Web开发提供了强大的参数校验机制。通过整合JSR 303(Bean Validation),可以确保请求参数的合法性,防止诸如空指针异常、参数越界等常见错误。通过注解的方式,在Controller中对请求参数进行验证,是提升应用程序稳定性和安全性的重要手段。
2. 如何在Spring Boot中实现参数校验
在Spring Boot中,@Valid
和 @Validated
注解可用于触发参数校验。通过 javax.validation.constraints
包中的注解,我们可以对Java Bean对象的属性进行详细的校验。
示例:控制器层参数校验
@PostMapping("/user")
public String addUser(@Valid @RequestBody User user, BindingResult result) {
if (result.hasErrors()) {
return "error";
}
userService.addUser(user);
return "success";
}
@Valid
: 在方法参数上,表示对参数对象进行校验。BindingResult
: 用于捕获校验错误。
示例:User类参数校验
public class User {
@NotNull(message = "用户名不能为空")
private String username;
@NotBlank(message = "密码不能为空")
private String password;
@Email(message = "邮箱格式不正确")
private String email;
// Getter 和 Setter
}
这些注解包括:
@NotNull
: 确保字段非空。@NotBlank
: 确保字段非空并且不为空格。@Email
: 校验邮箱格式是否正确。
通过这样的验证,Spring Boot确保了参数的正确性,避免了潜在的错误。
3. Maven依赖配置
为了启用验证功能,你需要在pom.xml
中添加如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
你还可以选择添加其他验证相关依赖,具体视项目需求而定。
4. 常用校验注解
- @size (min=6, max=20, message="密码长度只能在6-20之间")
- @pattern (regexp="[a-za-z0-9._%+-]+@[a-za-z0-9.-]+\.[a-za-z]{2,4}", message="请输入正确的邮件格式")
- @Length(min = 5, max = 20, message = "用户名长度必须位于5到20之间")
- @Email(message = "请输入正确的邮箱")
- @NotNull(message = "用户名称不能为空")
- @Max(value = 100, message = "年龄不能大于100岁")
- @Min(value= 18 ,message= "必须年满18岁!" )
- @AssertTrue(message = "bln4 must is true")
- @AssertFalse(message = "blnf must is falase")
- @DecimalMax(value="100",message="decim最大值是100")
- @DecimalMin(value="100",message="decim最小值是100")
- @NotNull(message = "身份证不能为空")
- @Pattern(regexp="^(\d{18,18}|\d{15,15}|(\d{17,17}[x|X]))$", message="身份证格式错误")
这些注解能够灵活地对字段进行格式、大小、范围等方面的校验。
5. @Valid与@Validated的区别及使用场景
@Valid
: 主要用于嵌套校验,即对于对象中的属性值(可能是另一个对象)进行校验。@Validated
: 支持校验分组,可以对同一实体类在不同场景下应用不同的校验规则。
示例:嵌套校验
@Data
public class TeamDTO {
@Valid
private List<MemberDTO> list; // 对成员列表进行嵌套校验
}
6. 分组校验与自定义分组
当需要对同一对象进行不同场景下的校验时,可以通过分组校验来实现。
示例:定义分组接口
public interface TestValidGroup {
interface Insert {}
interface Update {}
}
示例:指定分组校验
@PostMapping("/post")
public BaseResponse testValidPostRequest(@Validated(value = {TestValidGroup.Update.class}) @RequestBody ProjectDTO testAnnotationDto) {
return new BaseResponse(testAnnotationDto);
}
通过@Validated
的value
参数,我们可以选择不同的校验分组。
7. @GroupSequence指定校验顺序
为了确保参数校验顺序的可控性,可以使用@GroupSequence
注解来指定校验顺序,这对于某些严格的自动化测试场景非常有用。
@GroupSequence(value = {Id.class, StrValue.class})
interface Update {}
8. 快速失败机制
Hibernate Validator
支持快速失败机制,即一旦发现校验失败,就立即抛出异常,避免进一步的校验开销。
@Configuration
public class ValidConfig {
@Bean
public Validator validator() {
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
.configure()
.failFast(true)
.buildValidatorFactory();
return validatorFactory.getValidator();
}
}
9. 异常处理
Spring 提供了多种方式来处理校验失败的异常,常见的方式是使用 @ExceptionHandler
来捕获异常并返回自定义的错误响应。
@ExceptionHandler({MethodArgumentNotValidException.class,ConstraintViolationException.class,BindException.class})
public Result<?> handleValidationException(Throwable e) {
String errorMessage = e.getMessage();
if (e instanceof MethodArgumentNotValidException) {
MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
errorMessage = ex.getBindingResult().getAllErrors().stream()
.map(ObjectError::getDefaultMessage)
.collect(Collectors.joining("; "));
} else if (e instanceof ConstraintViolationException) {
ConstraintViolationException ex = (ConstraintViolationException) e;
errorMessage = ex.getConstraintViolations().stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.joining("; "));
} else if (e instanceof BindException) {
BindException ex = (BindException) e;
errorMessage = ex.getAllErrors().stream()
.map(ObjectError::getDefaultMessage)
.collect(Collectors.joining("; "));
}
return Result.failed(errorMessage);
}
10. 总结
通过整合Spring Boot和JSR 303规范中的@Valid
与@Validated
注解,我们可以实现灵活的参数校验机制。这种方式不仅提高了系统的可靠性,也确保了应用程序中参数的有效性。