Bean Validation(JSR-380)是由 Java 社群提出的一套「標準化物件(Bean)驗證」規範,定義了一組註解(Annotation)和 API,讓開發者可以以宣告式的方式(Annotation)在 Java 物件屬性、方法參數或回傳值上,定義校驗條件,並由統一的驗證引擎(如 Hibernate Validator)在執行時自動檢查是否符合這些條件。
主要特色
1. 標準化:JSR-380(也稱為 Bean Validation 2.0)是 Java EE/Jakarta EE 的一部分。
2. 宣告式:使用註解(Annotation)宣告欄位或方法參數的驗證規則。
3. 可擴充:可透過自定義 Constraint 和 ConstraintValidator 實作特殊驗證邏輯。
4. 與容器整合:支援在 Spring、Java EE、Quarkus… 等框架中,結合 @Valid 自動觸發驗證並處理錯誤。
常見註解(Constraint Annotation)
• @NotNull — 值不允許為 null
• @NotEmpty — 字串非空(null 或長度 0 均視為違規)
• @NotBlank — 字串非空且至少包含一個非空白字元
• @Size — 限制集合、字串或陣列長度(min / max)
• @Min/@Max — 數值、時間大小限制
• @Pattern — 字串需符合指定的正則表達式
• @Email — 電子郵件格式(JSR-380 新增)
• @Past/@Future — 時間型別必須在過去/未來
範例—基本用法
```java
import javax.validation.constraints.*;
public class User {
@NotNull(message="帳號不可為空")
@Size(min=4, max=20, message="帳號長度要介於4到20字元")
private String username;
@NotBlank(message="密碼不可為空")
@Size(min=6, message="密碼至少6位")
private String password;
@Min(value=18, message="年齡至少18歲")
private int age;
@Email(message="Email 格式不正確")
private String email;
// getters/setters...
}
```
程式化驗證示範
```java
import javax.validation.*;
import java.util.Set;
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
User user = new User();
// user.setUsername(null); // or invalid values…
Set<ConstraintViolation<User>> violations = validator.validate(user);
for (ConstraintViolation<User> v : violations) {
System.out.println(
"Property '" + v.getPropertyPath() + "' " +
v.getMessage());
}
```
和 Spring Boot 結合
在 Controller 方法參數上加 @Valid,並接收 BindingResult 或直接讓框架拋出例外:
```java
@PostMapping("/users")
public ResponseEntity<?> create(
@Valid @RequestBody User user,
BindingResult br) {
if (br.hasErrors()) {
// 處理驗證錯誤
}
// 正常邏輯
}
```
進階特性
• Group 驗證:可依不同情境定義多組驗證群組(Group)。
• Container Element Constraints(JSR-380 新增):可對 List<@NotNull String> 等泛型元素直接加註解。
• 自訂 Constraint:撰寫自己的註解和對應的 ConstraintValidator,實作特殊規則。
• 訊息國際化:透過 message key + Resource Bundle,提供多國語系錯誤訊息。
小結
Bean Validation(JSR-380)提供一個統一、可擴充、宣告式的驗證機制,不僅減少重複程式碼,也能與各種 Java 框架無縫整合,輕鬆地為物件或 API 請求資料加上嚴謹、可維護的驗證邏輯。
---
在 Spring(或 Spring Boot)專案中,你可以透過 Bean Validation(JSR-380,Hibernate Validator 為常見實作)來對資料做注解式(annotation-based)驗證。其中,`@Pattern` 用來驗證一個 `String` 欄位是否符合指定的正規表達式(regex)。
以下示範一個完整的流程,包括:加入相依、定義 DTO、Controller 接收請求、驗證失敗時回傳錯誤資訊。
---
1. 加入相依(以 Spring Boot 為例)
在 `pom.xml` 中加入:
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
```
或 Gradle:
```
implementation 'org.springframework.boot:spring-boot-starter-validation'
```
2. 定義 DTO(或 Entity)
假設我們要驗證使用者輸入的手機號碼 (只允許 09 開頭共 10 碼數字) 以及電子郵件:
```java
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
public class UserDto {
@NotBlank(message = "請填寫手機號碼")
@Pattern(
regexp = "^09\\d{8}$",
message = "手機號碼格式錯誤,必須以09開頭共10碼數字"
)
private String mobile;
@NotBlank(message = "請填寫電子郵件")
@Email(message = "電子郵件格式不正確")
private String email;
// getter / setter
}
```
重點:
- `regexp`:正規表達式,不含兩側的 `/ /`。
- `message`:錯誤提示,可自訂;若需要國際化,可改為 `message = "{user.email.invalid}"`,並在 `ValidationMessages.properties` 內設定。
3. 在 Controller 中啟用驗證
```java
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RestController
@RequestMapping("/api/users")
public class UserController {
@PostMapping
public ResponseEntity<?> createUser(
@Valid @RequestBody UserDto userDto,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
// 取出所有錯誤訊息
List<String> errors = bindingResult.getFieldErrors()
.stream()
.map(f -> f.getField() + ": " + f.getDefaultMessage())
.collect(Collectors.toList());
return ResponseEntity
.badRequest()
.body(Map.of("errors", errors));
}
// 驗證通過,後續處理...
return ResponseEntity.ok(Map.of("message", "建立成功"));
}
}
```
重點:
- `@Valid`:啟動資料驗證。
- `BindingResult`:攔截驗證結果,方便自訂回傳內容。
4. 在 Controller 類別上使用 `@Validated`(可驗證路徑參數、方法參數)
若要對 `@PathVariable`、`@RequestParam` 等做驗證,Controller 類級加上:
```java
import org.springframework.validation.annotation.Validated;
@RestController
@RequestMapping("/api")
@Validated
public class MyController {
@GetMapping("/items/{id}")
public ResponseEntity<?> getItem(
@PathVariable
@Pattern(regexp="\\d+", message="ID 必須為數字") String id) {
// id 通過驗證後才進來
return ResponseEntity.ok("item " + id);
}
}
```
5. 自訂 ValidationMessages.properties(國際化)
在 `src/main/resources` 下新增 `ValidationMessages.properties`:
```
user.mobile.invalid=手機號碼必須以09開頭,共10位數字
user.email.invalid=請輸入有效的電子郵件地址
```
然後在 DTO 中:
```java
@Pattern(regexp="^09\\d{8}$", message="{user.mobile.invalid}")
private String mobile;
```
6. 測試範例
使用 Postman 或 curl:
```
POST http://localhost:8080/api/users
Content-Type: application/json
{
"mobile": "091234567",
"email": "not-an-email"
}
```
可能回傳:
```json
{
"errors": [
"mobile: 手機號碼格式錯誤,必須以09開頭共10碼數字",
"email: 電子郵件格式不正確"
]
}
```
---
常見注意事項
1. Java 字串內的 `\` 必須用 `\\`。
2. `@Pattern` 僅對 `String` 型別生效,對 `null` 不會報錯(若不允許 `null`,需搭配 `@NotNull` 或 `@NotBlank`)。
3. 若要設定全域 Validator(如自訂訊息取代),可在 `@Configuration` 中定義 `LocalValidatorFactoryBean`。
這樣,你就可以透過 `@Pattern` 在 Spring 中輕鬆地為欄位加上正規表達式驗證了!