1.使用驗證註解
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;
2.使用自訂驗證註解
雖然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
類別中定義的驗證邏輯。
3.在伺服器端驗證
除了前端或客戶端做了驗證意外,伺服器端驗證輸入是至關重要的。它可以確保在處理或儲存任何惡意或格式錯誤的資料之前將其捕獲,這對於應用程式的安全性和穩定性至關重要。
假設我們有一個允許使用者建立新帳戶的 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
參數以觸發驗證過程。
4.提供有意義的錯誤訊息
當驗證失敗時,必須提供清晰簡潔的錯誤訊息來描述出了什麼問題以及如何修復它。
這是一個範例,如果我們有一個允許使用者建立新使用者的 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
物件來捕獲任何驗證錯誤。
5.将 i18n 用于错误消息
如果你的应用程序支持多种语言,则必须使用国际化 (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”标头以用户的首选语言显示。
6.使用分组验证
验证组是 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
字段必须非空。否则,所有三个字段都将正常验证。
7.对复杂逻辑使用跨域验证
如果需要验证跨多个字段的复杂输入规则,可以使用跨字段验证来保持验证逻辑的组织性和可维护性。跨字段验证可确保所有输入值均有效且彼此一致,从而防止出现意外行为。
假设我们有一个表单,用户可以在其中输入任务的开始日期和结束日期,并且我们希望确保结束日期不早于开始日期。我们可以使用跨域验证来实现这一点。
首先,我们定义一个自定义验证注解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; }
现在,当用户提交表单时,验证框架将自动检查结束日期是否晚于开始日期,如果不是,则提供有意义的错误消息。
8.对验证错误使用异常处理
可以使用异常处理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 抛出的任何验证错误都将被捕获并以结构化和有意义的格式返回给用户,从而更容易理解和解决问题。
9.测试你的验证逻辑
需要为你的验证逻辑编写单元测试,以帮助确保它正常工作。
@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
对象并检查是否返回了预期的验证错误。
10.考虑客户端验证
客户端验证可以通过向用户提供即时反馈并减少对服务器的请求数量来改善用户体验。但是,不应依赖它作为验证输入的唯一方法。客户端验证很容易被绕过或操纵,因此必须在服务器端验证输入,以确保安全性和数据完整性。
以上是SpringBoot參數驗證的技巧有哪些的詳細內容。更多資訊請關注PHP中文網其他相關文章!

新興技術對Java的平台獨立性既有威脅也有增強。 1)雲計算和容器化技術如Docker增強了Java的平台獨立性,但需要優化以適應不同雲環境。 2)WebAssembly通過GraalVM編譯Java代碼,擴展了其平台獨立性,但需與其他語言競爭性能。

不同JVM實現都能提供平台獨立性,但表現略有不同。 1.OracleHotSpot和OpenJDKJVM在平台獨立性上表現相似,但OpenJDK可能需額外配置。 2.IBMJ9JVM在特定操作系統上表現優化。 3.GraalVM支持多語言,需額外配置。 4.AzulZingJVM需特定平台調整。

平台獨立性通過在多種操作系統上運行同一套代碼,降低開發成本和縮短開發時間。具體表現為:1.減少開發時間,只需維護一套代碼;2.降低維護成本,統一測試流程;3.快速迭代和團隊協作,簡化部署過程。

Java'splatformindependencefacilitatescodereusebyallowingbytecodetorunonanyplatformwithaJVM.1)Developerscanwritecodeonceforconsistentbehavioracrossplatforms.2)Maintenanceisreducedascodedoesn'tneedrewriting.3)Librariesandframeworkscanbesharedacrossproj

要解決Java應用程序中的平台特定問題,可以採取以下步驟:1.使用Java的System類查看系統屬性以了解運行環境。 2.利用File類或java.nio.file包處理文件路徑。 3.根據操作系統條件加載本地庫。 4.使用VisualVM或JProfiler優化跨平台性能。 5.通過Docker容器化確保測試環境與生產環境一致。 6.利用GitHubActions在多個平台上進行自動化測試。這些方法有助於有效地解決Java應用程序中的平台特定問題。

類加載器通過統一的類文件格式、動態加載、雙親委派模型和平台無關的字節碼,確保Java程序在不同平台上的一致性和兼容性,實現平台獨立性。

Java編譯器生成的代碼是平台無關的,但最終執行的代碼是平台特定的。 1.Java源代碼編譯成平台無關的字節碼。 2.JVM將字節碼轉換為特定平台的機器碼,確保跨平台運行但性能可能不同。

多線程在現代編程中重要,因為它能提高程序的響應性和資源利用率,並處理複雜的並發任務。 JVM通過線程映射、調度機制和同步鎖機制,在不同操作系統上確保多線程的一致性和高效性。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

記事本++7.3.1
好用且免費的程式碼編輯器

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),