在 Spring Boot 中驗證布林類型
一、簡介
在本教程中,我們將學習如何在 Spring Boot 應用程式中驗證Boolean
類型,並了解執行驗證的各種方法。此外,我們將在各個 Spring Boot 應用程式層(例如控制器或服務層)驗證Boolean
類型的物件。
2. 程序驗證
Boolean
類別提供了兩個基本方法來建立該類別的實例: Boolean.valueOf()
和Boolean.parseBoolean()
。
Boolean.valueOf()
接受String
和boolean
值。它檢查輸入欄位的值是true
還是false
,並相應地提供一個Boolean
物件。 Boolean.parseBoolean()
方法只接受字串值。
這些方法不區分大小寫 - 例如,「true」、「True」、「TRUE」、「false」、「False」和「FALSE」都是可接受的輸入。
讓我們透過單元測試驗證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
轉換。我們可以使用自訂反序列化器反序列化布林值的自訂表示。
讓我們考慮一個場景,我們想要使用表示布林值的 JSON 數據,其中*+* (代表true
)和–
(代表false
)。讓我們編寫一個 JSON 反序列化器來實現此目的:
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 約束和自訂 JSON 反序列化器。讓我們建立一個名為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
將物件傳遞到 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
。讓我們建立三個方法來處理控制器和服務層各自拋出的例外:
@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。讓我們為控制器建立測試類別的結構:
@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
註釋
讓我們看看@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
的工作。當我們傳遞帶有false
Boolean
參數的BooleanObject
時, @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
的工作原理。當我們為AssertFalse
參數傳遞一個true值時, @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.驗證Boolean
類型的自訂 JSON 反序列化器
讓我們驗證用我們的自訂 JSON 反序列化器標記的參數。自訂解串器僅接受值“+”和“-”。如果我們傳遞任何其他值,驗證將失敗並觸發錯誤。讓我們在輸入 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
註釋放置在方法參數上。這兩個註解的組合將導致 Spring Boot 驗證物件。
與控制器層的@RequestBody
不同,服務層的驗證是針對一個簡單的 Java 物件進行的,因此框架會因驗證失敗而觸發ConstraintViolationException
.
在這種情況下,Spring 框架將傳回HttpStatus.INTERNAL_SERVER_ERROR
作為反應狀態。
對於在控制器層建立或修改然後傳遞到服務層進行處理的對象,首選服務等級驗證。
讓我們檢查一下這個服務類別的框架:
@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());
}
八、結論
我們學習如何使用三種方法在控制器和服務層驗證Boolean
類型:程式驗證、bean 驗證和使用自訂 JSON 反序列化器。本文的參考代碼可在 GitHub 上取得。