您好,登錄后才能下訂單哦!
這篇文章主要介紹“SpringBoot參數驗證的技巧有哪些”,在日常操作中,相信很多人在SpringBoot參數驗證的技巧有哪些問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”SpringBoot參數驗證的技巧有哪些”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
Spring Boot
提供了內置的驗證注解,可以幫助簡單、快速地對輸入字段進行驗證,例如檢查 null 或空字段、強制執行長度限制、使用正則表達式驗證模式以及驗證電子郵件地址。
一些最常用的驗證注釋包括:
@NotNull
:指定字段不能為空。
@NotEmpty
:指定列表字段不能為空。
@NotBlank
:指定字符串字段不得為空或僅包含空格。
@Min
和 @Max
:指定數字字段的最小值和最大值。
@Pattern
:指定字符串字段必須匹配的正則表達式模式。
@Email
:指定字符串字段必須是有效的電子郵件地址。
具體用法參考下面例子:
public class User { @NotNull private Long id; @NotBlank @Size(min = 2, max = 50) private String firstName; @NotBlank @Size(min = 2, max = 50) private String lastName; @Email private String email; @NotNull @Min(18) @Max(99) private Integer age; @NotEmpty private List<String> hobbies; @Pattern(regexp = "[A-Z]{2}\d{4}") private String employeeId;
雖然 Spring Boot 的內置驗證注釋很有用,但它們可能無法涵蓋所有情況。如果有特殊參數驗證的場景,可以使用 Spring 的 JSR 303 驗證框架創建自定義驗證注釋。自定義注解可以讓你的的驗證邏輯更具可重用性和可維護性。
假設我們有一個應用程序,用戶可以在其中創建帖子。每個帖子都應該有一個標題和一個正文,并且標題在所有帖子中應該是唯一的。雖然 Spring Boot 提供了用于檢查字段是否為空的內置驗證注釋,但它沒有提供用于檢查唯一性的內置驗證注釋。在這種情況下,我們可以創建一個自定義驗證注解來處理這種情況。
首先,我們創建自定義約束注解UniqueTitle
:
@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = UniqueTitleValidator.class) public @interface UniqueTitle { String message() default "Title must be unique"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
接下來,我們創建一個PostRepository
接口,目的是從數據庫中檢索帖子:
public interface PostRepository extends JpaRepository<Post, Long> { Post findByTitle(String title); }
然后我們需要定義驗證器類 UniqueTitleValidator
,如下所示:
@Component public class UniqueTitleValidator implements ConstraintValidator<UniqueTitle, String> { @Autowired private PostRepository postRepository; @Override public boolean isValid(String title, ConstraintValidatorContext context) { if (title == null) { return true; } return Objects.isNull(postRepository.findByTitle(title)); } }
UniqueTitleValidator
實現了ConstraintValidator
接口,它有兩個泛型類型:第一個是自定義注解UniqueTitle
,第二個是正在驗證的字段類型(在本例中為String
). 我們還自動裝配了PostRepository
類以從數據庫中檢索帖子。
isValid()
方法通過查詢 PostRepository
來檢查 title
是否為 null 或者它是否是唯一的。如果 title
為 null 或唯一,則驗證成功,并返回 true。
定義了自定義驗證注釋和驗證器類后,我們現在可以使用它來驗證 Spring Boot 應用程序中的帖子標題:
public class Post { @UniqueTitle private String title; @NotNull private String body; }
我們已將 @UniqueTitle
注釋應用于 Post
類中的 title
變量。驗證此字段時,這將觸發 UniqueTitleValidator
類中定義的驗證邏輯。
除了前端或者客戶端做了驗證意外,服務器端驗證輸入是至關重要的。它可以確保在處理或存儲任何惡意或格式錯誤的數據之前將其捕獲,這對于應用程序的安全性和穩定性至關重要。
假設我們有一個允許用戶創建新帳戶的 REST
端點。端點需要一個包含用戶用戶名和密碼的 JSON 請求體。為確保輸入有效,我們可以創建一個 DTO(數據傳輸對象)類并將驗證注釋應用于其字段:
public class UserDTO { @NotBlank private String username; @NotBlank private String password; }
我們使用@NotBlank
注解來確保username
和password
字段不為空或 null。
接下來,我們可以創建一個控制器方法來處理 HTTP POST 請求并在創建新用戶之前驗證輸入:
@RestController @RequestMapping("/users") @Validated public class UserController { @Autowired private UserService userService; @PostMapping public ResponseEntity<String> createUser(@Valid @RequestBody UserDTO userDto) { userService.createUser(userDto); return ResponseEntity.status(HttpStatus.CREATED).body("User created successfully"); } }
我們使用 Spring 的@Validated
注解來啟用方法級驗證,我們還將 @Valid
注釋應用于 userDto
參數以觸發驗證過程。
當驗證失敗時,必須提供清晰簡潔的錯誤消息來描述出了什么問題以及如何修復它。
這是一個示例,如果我們有一個允許用戶創建新用戶的 RESTful API
。我們要確保姓名和電子郵件地址字段不為空,年齡在 18 到 99 歲之間,除了這些字段,如果用戶嘗試使用重復的“用戶名”創建帳戶,我們還會提供明確的錯誤消息或“電子郵件”。
為此,我們可以定義一個帶有必要驗證注釋的模型類 User,如下所示:
public class User { @NotBlank(message = "用戶名不能為空") private String name; @NotBlank(message = "Email不能為空") @Email(message = "無效的Emaild地址") private String email; @NotNull(message = "年齡不能為空") @Min(value = 18, message = "年齡必須大于18") @Max(value = 99, message = "年齡必須小于99") private Integer age; }
我們使用 message屬性為每個驗證注釋提供了自定義錯誤消息。
接下來,在我們的 Spring 控制器中,我們可以處理表單提交并使用 @Valid
注釋驗證用戶輸入:
@RestController @RequestMapping("/users") public class UserController { @Autowired private UserService userService; @PostMapping public ResponseEntity<String> createUser(@Valid @RequestBody User user, BindingResult result) { if (result.hasErrors()) { List<String> errorMessages = result.getAllErrors().stream() .map(DefaultMessageSourceResolvable::getDefaultMessage) .collect(Collectors.toList()); return ResponseEntity.badRequest().body(errorMessages.toString()); } // save the user to the database using UserService userService.saveUser(user); return ResponseEntity.status(HttpStatus.CREATED).body("User created successfully"); } }
我們使用 @Valid
注釋來觸發 User
對象的驗證,并使用 BindingResult
對象來捕獲任何驗證錯誤。
如果你的應用程序支持多種語言,則必須使用國際化 (i18n) 以用戶首選語言顯示錯誤消息。
以下是在 Spring Boot 應用程序中使用 i18n 處理錯誤消息的示例
首先,在資源目錄下創建一個包含默認錯誤消息的 messages.properties
文件
# messages.properties user.name.required=Name is required. user.email.invalid=Invalid email format. user.age.invalid=Age must be a number between 18 and 99.
接下來,為每種支持的語言創建一個 messages_xx.properties
文件,例如,中文的 messages_zh_CN.properties
。
user.name.required=名稱不能為空. user.email.invalid=無效的email格式. user.age.invalid=年齡必須在18到99歲之間.
然后,更新您的驗證注釋以使用本地化的錯誤消息
public class User { @NotNull(message = "{user.id.required}") private Long id; @NotBlank(message = "{user.name.required}") private String name; @Email(message = "{user.email.invalid}") private String email; @NotNull(message = "{user.age.required}") @Min(value = 18, message = "{user.age.invalid}") @Max(value = 99, message = "{user.age.invalid}") private Integer age; }
最后,在 Spring 配置文件中配置 MessageSource bean
以加載 i18n
消息文件
@Configuration public class AppConfig { @Bean public MessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setBasename("messages"); messageSource.setDefaultEncoding("UTF-8"); return messageSource; } @Bean public LocalValidatorFactoryBean validator() { LocalValidatorFactoryBean validatorFactoryBean = new LocalValidatorFactoryBean(); validatorFactoryBean.setValidationMessageSource(messageSource()); return validatorFactoryBean; } }
現在,當發生驗證錯誤時,錯誤消息將根據隨請求發送的“Accept-Language”標頭以用戶的首選語言顯示。
驗證組是 Spring Boot 驗證框架的一個強大功能,允許您根據其他輸入值或應用程序狀態應用條件驗證規則。
現在有一個包含三個字段的User
類的情況下:firstName
、lastName
和email
。我們要確保如果 email
字段為空,則 firstName
或 lastName
字段必須非空。否則,所有三個字段都應該正常驗證。
為此,我們將定義兩個驗證組:EmailNotEmpty
和 Default
。EmailNotEmpty
組將包含當 email
字段不為空時的驗證規則,而 Default
組將包含所有三個字段的正常驗證規則。
創建帶有驗證組的 User
類
public class User { @NotBlank(groups = Default.class) private String firstName; @NotBlank(groups = Default.class) private String lastName; @Email(groups = EmailNotEmpty.class) private String email; // getters and setters omitted for brevity public interface EmailNotEmpty {} public interface Default {} }
請注意,我們在User
類中定義了兩個接口,EmailNotEmpty
和 Default
。這些將作為我們的驗證組。
接下來,我們更新Controller
使用這些驗證組
@RestController @RequestMapping("/users") @Validated public class UserController { public ResponseEntity<String> createUser( @Validated({org.example.model.ex6.User.EmailNotEmpty.class}) @RequestBody User userWithEmail, @Validated({User.Default.class}) @RequestBody User userWithoutEmail) { // Create the user and return a success response } }
我們已將@Validated
注釋添加到我們的控制器,表明我們想要使用驗證組。我們還更新了 createUser
方法,將兩個 User
對象作為輸入,一個在 email
字段不為空時使用,另一個在它為空時使用。
@Validated
注釋用于指定將哪個驗證組應用于每個 User
對象。對于 userWithEmail
參數,我們指定了 EmailNotEmpty
組,而對于 userWithoutEmail
參數,我們指定了 Default
組。
進行這些更改后,現在將根據“電子郵件”字段是否為空對“用戶”類進行不同的驗證。如果為空,則 firstName
或 lastName
字段必須非空。否則,所有三個字段都將正常驗證。
如果需要驗證跨多個字段的復雜輸入規則,可以使用跨字段驗證來保持驗證邏輯的組織性和可維護性。跨字段驗證可確保所有輸入值均有效且彼此一致,從而防止出現意外行為。
假設我們有一個表單,用戶可以在其中輸入任務的開始日期和結束日期,并且我們希望確保結束日期不早于開始日期。我們可以使用跨域驗證來實現這一點。
首先,我們定義一個自定義驗證注解EndDateAfterStartDate
:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = EndDateAfterStartDateValidator.class) public @interface EndDateAfterStartDate { String message() default "End date must be after start date"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
然后,我們創建驗證器EndDateAfterStartDateValidator
:
public class EndDateAfterStartDateValidator implements ConstraintValidator<EndDateAfterStartDate, TaskForm> { @Override public boolean isValid(TaskForm taskForm, ConstraintValidatorContext context) { if (taskForm.getStartDate() == null || taskForm.getEndDate() == null) { return true; } return taskForm.getEndDate().isAfter(taskForm.getStartDate()); } }
最后,我們將EndDateAfterStartDate
注釋應用于我們的表單對象TaskForm
:
@EndDateAfterStartDate public class TaskForm { @NotNull @DateTimeFormat(pattern = "yyyy-MM-dd") private LocalDate startDate; @NotNull @DateTimeFormat(pattern = "yyyy-MM-dd") private LocalDate endDate; }
現在,當用戶提交表單時,驗證框架將自動檢查結束日期是否晚于開始日期,如果不是,則提供有意義的錯誤消息。
可以使用異常處理ExceptionHandler
來統一捕獲和處理驗證錯誤。
以下是如何在 Spring Boot 中使用異常處理來處理驗證錯誤的示例:
@RestControllerAdvice public class RestExceptionHandler extends ResponseEntityExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { Map<String, Object> body = new LinkedHashMap<>(); body.put("timestamp", LocalDateTime.now()); body.put("status", status.value()); // Get all errors List<String> errors = ex.getBindingResult() .getFieldErrors() .stream() .map(x -> x.getDefaultMessage()) .collect(Collectors.toList()); body.put("errors", errors); return new ResponseEntity<>(body, headers, status); } }
在這里,我們創建了一個用 @RestControllerAdvice
注解的 RestExceptionHandler
類來處理我們的 REST API 拋出的異常。然后我們創建一個用 @ExceptionHandler
注解的方法來處理在驗證失敗時拋出的 MethodArgumentNotValidException
。
在處理程序方法中,我們創建了一個 Map
對象來保存錯誤響應的詳細信息,包括時間戳、HTTP 狀態代碼和錯誤消息列表。我們使用 MethodArgumentNotValidException
對象的 getBindingResult()
方法獲取所有驗證錯誤并將它們添加到錯誤消息列表中。
最后,我們返回一個包含錯誤響應詳細信息的ResponseEntity
對象,包括作為響應主體的錯誤消息列表、HTTP 標頭和 HTTP 狀態代碼。
有了這個異常處理代碼,我們的 REST API 拋出的任何驗證錯誤都將被捕獲并以結構化和有意義的格式返回給用戶,從而更容易理解和解決問題。
需要為你的驗證邏輯編寫單元測試,以幫助確保它正常工作。
@DataJpaTest public class UserValidationTest { @Autowired private TestEntityManager entityManager; @Autowired private Validator validator; @Test public void testValidation() { User user = new User(); user.setFirstName("John"); user.setLastName("Doe"); user.setEmail("invalid email"); Set<ConstraintViolation<User>> violations = validator.validate(user); assertEquals(1, violations.size()); assertEquals("must be a well-formed email address", violations.iterator().next().getMessage()); } }
我們使用 JUnit 5 編寫一個測試來驗證具有無效電子郵件地址的“用戶”對象。然后我們使用 Validator
接口來驗證 User
對象并檢查是否返回了預期的驗證錯誤。
客戶端驗證可以通過向用戶提供即時反饋并減少對服務器的請求數量來改善用戶體驗。但是,不應依賴它作為驗證輸入的唯一方法。客戶端驗證很容易被繞過或操縱,因此必須在服務器端驗證輸入,以確保安全性和數據完整性。
到此,關于“SpringBoot參數驗證的技巧有哪些”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。