1. 引言
在 Spring Boot 应用中验证 Boolean 类型是常见需求,本文将深入探讨多种验证方案。我们将覆盖控制器层和服务层的验证实现,包括程序化验证、自定义 JSON 反序列化器以及 Bean 验证注解的使用。
2. 程序化验证
Boolean 类提供了两个核心方法用于创建实例:Boolean.valueOf()
和 Boolean.parseBoolean()
。
Boolean.valueOf()
接受 String 或 boolean 值,根据输入返回 Boolean 对象Boolean.parseBoolean()
仅接受 String 值
⚠️ 注意:这些方法不区分大小写,例如 "true"、"True"、"TRUE" 等均有效。
通过单元测试验证 String 到 Boolean 的转换:
@Test
void givenInputAsString_whenStringToBoolean_thenValidBooleanConversion() {
assertEquals(Boolean.TRUE, Boolean.valueOf("TRUE"));
assertEquals(Boolean.FALSE, Boolean.valueOf("false"));
assertEquals(Boolean.TRUE, Boolean.parseBoolean("True"));
}
验证原始 boolean 到 Boolean 包装类的转换:
@Test
void givenInputAsboolean_whenbooleanToBoolean_thenValidBooleanConversion() {
assertEquals(Boolean.TRUE, Boolean.valueOf(true));
assertEquals(Boolean.FALSE, Boolean.valueOf(false));
}
3. 自定义 Jackson 反序列化器验证
Spring Boot API 常处理 JSON 数据,我们可通过自定义反序列化器验证 JSON 到 Boolean 的转换。考虑一个场景:用 +
表示 true,-
表示 false。
自定义反序列化器实现:
public class BooleanDeserializer extends JsonDeserializer<Boolean> {
@Override
public Boolean deserialize(JsonParser parser, DeserializationContext context) throws IOException {
String value = parser.getText();
if (value != null && value.equals("+")) {
return Boolean.TRUE;
} else if (value != null && value.equals("-")) {
return Boolean.FALSE;
} else {
throw new IllegalArgumentException("Only values accepted as Boolean are + and -");
}
}
}
4. Bean 验证注解
Bean 验证约束是另一种常用验证方式,需添加 spring-boot-starter-validation
依赖。Boolean 字段可用三个注解:
- ✅
@NotNull
:Boolean 字段为 null 时报错 - ✅
@AssertTrue
:Boolean 字段为 false 时报错 - ✅
@AssertFalse
:Boolean 字段为 true 时报错
⚠️ 踩坑提示:@AssertTrue
和 @AssertFalse
将 null 视为有效值!若需强制非空,必须配合 @NotNull
使用。
5. Boolean 验证示例
结合 Bean 约束和自定义反序列化器,创建包含四个 Boolean 参数的 BooleanObject
:
public class BooleanObject {
@NotNull(message = "boolField cannot be null")
Boolean boolField;
@AssertTrue(message = "trueField must have true value")
Boolean trueField;
@NotNull(message = "falseField cannot be null")
@AssertFalse(message = "falseField must have false value")
Boolean falseField;
@JsonDeserialize(using = BooleanDeserializer.class)
Boolean boolStringVar;
//getters and setters
}
6. 控制器层验证
通过 RequestBody
传递对象时,使用 @Valid
注解触发验证:
@RestController
public class ValidationController {
@Autowired
ValidationService service;
@PostMapping("/validateBoolean")
public ResponseEntity<String> processBooleanObject(@RequestBody @Valid BooleanObject booleanObj) {
return ResponseEntity.ok("BooleanObject is valid");
}
@PostMapping("/validateBooleanAtService")
public ResponseEntity<String> processBooleanObjectAtService() {
BooleanObject boolObj = new BooleanObject();
boolObj.setBoolField(Boolean.TRUE);
boolObj.setTrueField(Boolean.FALSE);
service.processBoolean(boolObj);
return ResponseEntity.ok("BooleanObject is valid");
}
}
验证失败时 Spring 抛出 MethodArgumentNotValidException
,通过 ControllerAdvice
处理异常:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public String handleValidationException(MethodArgumentNotValidException ex) {
return ex.getBindingResult()
.getFieldErrors()
.stream()
.map(e -> e.getDefaultMessage())
.collect(Collectors.joining(","));
}
@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public String handleIllegalArugmentException(IllegalArgumentException ex) {
return ex.getMessage();
}
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public String handleConstraintViolationException(ConstraintViolationException ex) {
return ex.getMessage();
}
}
测试类结构:
@ExtendWith(SpringExtension.class)
@WebMvcTest(controllers = ValidationController.class)
class ValidationControllerUnitTest {
@Autowired
private MockMvc mockMvc;
@TestConfiguration
static class EmployeeServiceImplTestContextConfiguration {
@Bean
public ValidationService validationService() {
return new ValidationService() {};
}
}
@Autowired
ValidationService service;
}
6.1. 验证 @NotNull 注解
传递 null 值时返回 400 错误:
@Test
void whenNullInputForBooleanField_thenHttpBadRequestAsHttpResponse() throws Exception {
String postBody = "{\"boolField\":null,\"trueField\":true,\"falseField\":false,\"boolStringVar\":\"+\"}";
mockMvc.perform(post("/validateBoolean").contentType("application/json")
.content(postBody))
.andExpect(status().isBadRequest());
}
6.2. 验证 @AssertTrue 注解
传递 false 值时返回错误消息:
@Test
void whenInvalidInputForTrueBooleanField_thenErrorResponse() throws Exception {
String postBody = "{\"boolField\":true,\"trueField\":false,\"falseField\":false,\"boolStringVar\":\"+\"}";
String output = mockMvc.perform(post("/validateBoolean").contentType("application/json")
.content(postBody))
.andReturn()
.getResponse()
.getContentAsString();
assertEquals("trueField must have true value", output);
}
❌ 注意:单独使用 @AssertTrue
时 null 值有效:
@Test
void whenNullInputForTrueBooleanField_thenCorrectResponse() throws Exception {
String postBody = "{\"boolField\":true,\"trueField\":null,\"falseField\":false,\"boolStringVar\":\"+\"}";
mockMvc.perform(post("/validateBoolean").contentType("application/json")
.content(postBody))
.andExpect(status().isOk());
}
6.3. 验证 @AssertFalse 注解
传递 true 值时返回错误消息:
@Test
void whenInvalidInputForFalseBooleanField_thenErrorResponse() throws Exception {
String postBody = "{\"boolField\":true,\"trueField\":true,\"falseField\":true,\"boolStringVar\":\"+\"}";
String output = mockMvc.perform(post("/validateBoolean").contentType("application/json")
.content(postBody))
.andReturn()
.getResponse()
.getContentAsString();
assertEquals("falseField must have false value", output);
}
✅ 配合 @NotNull
时 null 值会触发验证:
@Test
void whenNullInputForFalseBooleanField_thenHttpBadRequestAsHttpResponse() throws Exception {
String postBody = "{\"boolField\":true,\"trueField\":true,\"falseField\":null,\"boolStringVar\":\"+\"}";
mockMvc.perform(post("/validateBoolean").contentType("application/json")
.content(postBody))
.andExpect(status().isBadRequest());
}
6.4. 验证自定义 JSON 反序列化器
传递非法值时触发错误:
@Test
void whenInvalidBooleanFromJson_thenErrorResponse() throws Exception {
String postBody = "{\"boolField\":true,\"trueField\":true,\"falseField\":false,\"boolStringVar\":\"plus\"}";
String output = mockMvc.perform(post("/validateBoolean").contentType("application/json")
.content(postBody))
.andReturn()
.getResponse()
.getContentAsString();
assertEquals("Only values accepted as Boolean are + and -", output);
}
✅ 合法值通过验证:
@Test
void whenAllBooleanFieldsValid_thenCorrectResponse() throws Exception {
String postBody = "{\"boolField\":true,\"trueField\":true,\"falseField\":false,\"boolStringVar\":\"+\"}";
String output = mockMvc.perform(post("/validateBoolean").contentType("application/json")
.content(postBody))
.andReturn()
.getResponse()
.getContentAsString();
assertEquals("BooleanObject is valid", output);
}
7. 服务层验证
在服务层使用 @Validated
和 @Valid
组合触发验证:
@Service
@Validated
public class ValidationService {
public void processBoolean(@Valid BooleanObject booleanObj) {
// further processing
}
}
⚠️ 关键区别:服务层验证失败抛出 ConstraintViolationException
,返回 HTTP 500 状态码。
最佳实践:服务层验证适用于控制器层创建/修改后传递给服务层处理的对象。
测试服务层验证:
@Test
void givenAllBooleanFieldsValid_whenServiceValidationFails_thenErrorResponse() throws Exception {
mockMvc.perform(post("/validateBooleanAtService").contentType("application/json"))
.andExpect(status().isInternalServerError());
}
8. 总结
我们掌握了在 Spring Boot 中验证 Boolean 类型的三种核心方案:
- 程序化验证(
Boolean.valueOf()
/parseBoolean()
) - 自定义 JSON 反序列化器
- Bean 验证注解(
@NotNull
/@AssertTrue
/@AssertFalse
)
通过控制器层和服务层的实战示例,覆盖了从基础验证到复杂场景的完整解决方案。合理选择验证策略能有效提升 API 的健壮性,避免脏数据进入业务逻辑。