1. 簡介
在本教程中,我們將學習如何在 Spring Boot 應用程序中驗證 <em >Boolean</em> 類型,並探討各種驗證方法。此外,我們還將驗證不同 Spring Boot 應用程序層(例如控制器或服務層)的 <em >Boolean</em> 類型對象。
2. 編程驗證
`Boolean 類提供了兩個關鍵方法來創建類的實例:Boolean.valueOf() 和 Boolean.parseBoolean()。
Boolean.valueOf() 可以接受 <em>String</em> 和 <em>boolean</em> 值。 它會檢查輸入字段的值是否為 <em>true</em> 或 <em>false</em>,並相應地提供一個 <em>Boolean</em> 對象。 <em>Boolean.parseBoolean()</em> 方法僅接受字符串值。
這些方法不區分大小寫——例如,“true”、“True”、“TRUE”、“false”、“False” 和 “FALSE” 都是可接受的輸入。
讓我們通過一個單元測試來驗證 <em>String</em> 到 <em>Boolean</em> 的轉換:
@Test
void givenInputAsString_whenStringToBoolean_thenValidBooleanConversion() {
assertEquals(Boolean.TRUE, Boolean.valueOf("TRUE"));
assertEquals(Boolean.FALSE, Boolean.valueOf("false"));
assertEquals(Boolean.TRUE, Boolean.parseBoolean("True"));
}我們現在將對從原始布爾值轉換為 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 到布爾值的轉換。我們可以使用自定義序列化器反序列化自定義的布爾值表示形式。
讓我們考慮一個場景,我們想要消費以 + (表示 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. 布爾值驗證示例
為了演示這一點,我們將同時在控制器和服務層使用 Bean 約束以及自定義 JSON 解析器。讓我們創建一個名為 BooleanObject 的自定義對象,其中包含四個 Boolean 類型的參數。每個參數將採用不同的驗證方法:
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 將對象傳遞到 REST 端點時,我們可以使用 @Valid 註解來驗證該對象。 當我們對方法參數應用 @Valid 註解時,我們指示 Spring 驗證相應的用户對象:
@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 異常。為了處理這種情況,可以使用帶有相關 ExceptionHandler 方法的 ControllerAdvice。讓我們創建三個方法來處理來自 Controller 和 Service 層的相應異常:
@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();
}
}在測試 REST 功能之前,我們建議先通過 Spring Boot 中的 API 進行測試。下面我們來創建 Controller 測試類結構:
@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. 驗證 <em @NotNull/> 註解
讓我們看看 <em @NotNull/> 註解的工作方式。當我們將帶有 null Boolean 參數的 BooleanObject 傳遞時,@Valid 註解將驗證 Bean 並拋出一個“400 Bad Request” HTTP 響應:
@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 註解
接下來,我們將測試 @AssertTrue 註解的工作原理。當我們將 BooleanObject 與一個 false Boolean 參數一起傳遞時,@Valid 註解將驗證 Bean 並拋出一個“400 Bad Request” HTTP 響應。如果捕獲響應體,我們可以獲取 @AssertTrue 註解內部設置的錯誤消息:
@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);
}讓我們也檢查一下如果提供 null 的情況。由於我們僅對該字段進行了 @AssertTrue 的標註,但未進行 @NotNull 的標註,因此不會產生任何驗證錯誤:
@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 註解
我們將瞭解 @AssertFalse 的工作原理。當我們將 true 值傳遞給 @AssertFalse 參數時,帶有 @Valid 的註解會拋出錯誤請求。我們可以從響應體中獲取與 @AssertFalse 註解關聯的錯誤消息:
@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);
}再次,讓我們看看如果提供 null 會發生什麼。我們對該字段進行了標註,包括了 @AssertFalse 和 @NotNull,因此將會得到一個驗證錯誤:
@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 解序列化器針對 Boolean 類型
讓我們使用自定義 JSON 解序列化器驗證帶有標記的參數。自定義解序列化器僅接受“+”和“-”值。如果傳遞任何其他值,驗證將失敗並觸發錯誤。讓我們在輸入 JSON 中傳遞“plus”文本值,並查看驗證過程:
@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 註解放置在方法參數上。 組合這兩種註解將導致 Spring Boot 驗證對象。
與在控制器層中使用的 @RequestBody 註解不同,服務層中的驗證針對簡單的 Java 對象進行,因此 框架會在驗證失敗時引發 ConstraintViolationException。
在控制器層創建或修改的對象隨後傳遞到服務層進行處理時,服務層驗證是首選。
以下是此服務類的基本框架:
@Service
@Validated
public class ValidationService {
public void processBoolean(@Valid BooleanObject booleanObj) {
// further processing
}
}在上一節中,我們創建了一個端點來測試服務層和異常處理方法,用於處理 ConstraintViolationException。現在,我們來編寫一個新的測試用例來檢查這一點:
@Test
void givenAllBooleanFieldsValid_whenServiceValidationFails_thenErrorResponse() throws Exception {
mockMvc.perform(post("/validateBooleanAtService").contentType("application/json"))
.andExpect(status().isInternalServerError());
}8. 結論
我們學習瞭如何使用三種方法在控制器和服務層驗證布爾型:程序驗證、Bean 驗證和使用自定義 JSON 解析器。