Spring Boot Validation

SpringBoot 参数校验

校验框架

Bean 校验框架的事实标准:Hibernate Validator

依赖

从 SpringBoot 2.3 开始,需要显式地引入 spring-boot-starter-validation 依赖

领域模型

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "users") // user 是数据库的保留字
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @NotBlank(message = "Name is mandatory")
    private String name;

    @NotBlank(message = "Email is mandatory")
    private String email;
}

使用 @NotBlank 注解表示 name 和 email 的值不能为空。

数据访问层:

public interface UserRepository extends JpaRepository<User, Long> {}

控制器层

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @PostMapping
    public User addUser(@Valid @RequestBody User user) {
        return userService.addUser(user);
    }
}

当 SpringBoot 发现一个带有 @Valid 注解的参数,它会自动装配 Hibernate Validation 并校验该参数。
在校验失败时,抛出 MethodArgumentNotValidException 异常。

全局异常处理

/**
 * 全局校验异常处理
 * */
@ControllerAdvice
public class ValidExceptionHandler {

    /**
     * 以 JSON 格式返回校验异常信息
     * */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public Map<String, String> handleValidationException(MethodArgumentNotValidException e) {
        Map<String, String> errors = new HashMap<>();
        e.getBindingResult()
                .getAllErrors()
                .forEach(error -> {
                    String fieldName = ((FieldError)error).getField(); // 字段名
                    String errorMessage = error.getDefaultMessage(); // 校验失败信息
                    errors.put(fieldName, errorMessage);
                });
        return errors;
    }
}

测试

@WebMvcTest
class UserControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    private ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 参数校验成功测试
     * */
    @Test
    public void whenPostRequestToUserAndValidUser_thenCorrectResponse() throws Exception {
        User user = User.builder()
                .name("Alex")
                .email("alex@gamil.com")
                .build();
        String json = objectMapper.writeValueAsString(user);
        mockMvc.perform(post("/user")
                .content(json)
                .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk());
    }

    /**
     * 参数校验失败测试
     * */
    @Test
    public void whenPostRequestToUserAndInvalidUser_thenCorrectResponse() throws Exception {
        User userWithoutName = User.builder()
                .email("alex@gmail.com")
                .build();
        String json = objectMapper.writeValueAsString(userWithoutName);
        mockMvc.perform(post("/user")
                .content(json)
                .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isBadRequest())
                .andExpect(jsonPath("$.name", Is.is("Name is mandatory")));
    }
}

校验注解

注解 适用类型 说明
@Null 任何类型
@NotNull 任何类型
@NotEmpty 字符串、集合、Map 元素不能为 null 且不能为空
@NotBlank 字符串 字符串不能为 null 并且不能只包含空白字符
@Size(min=, max=) 字符串、集合、Map 容器大小,包含边界
@Max(value=) 数值 最大值
@Min(value=) 数值 最小值
@Digits(integer=, fraction=) 数值或字符串 数位
@Negative 数值 负数,不能是零
@NegativeOrZero 数值 负数或零
@Positive 数值 正数,不能是零
@PositiveOrZero 数值 正数或零
@Pattern(regex=, flags=) 字符串 字符串符合正则表达式
@Email 字符串
@DecimalMax(value=, inclusive=) 数值或字符串 最大值
@DecimalMin(value=, inclusive=) 数值或字符串 最小值
@Future 日期类型 将来日期
@FutureOrPresent 日期类型 现在或将来日期
@Past 日期类型 过去日期
@PastOrPresent 日期类型 过去或现在日期
@AssertFalse 布尔值
@AssertTrue 布尔值

数值包括:BigDecimal, BigInteger, byte, short, int, long

参阅

posted @ 2022-07-24 21:16  廖子博  阅读(75)  评论(0编辑  收藏  举报