前言
參數(shù)驗(yàn)證很重要,是平時(shí)開發(fā)環(huán)節(jié)中不可少的一部分,但是我想很多后端同事會偷懶,干脆不錯,這樣很可能給系統(tǒng)的穩(wěn)定性和安全性帶來嚴(yán)重的危害。那么在Spring Boot應(yīng)用中如何做好參數(shù)校驗(yàn)工作呢,本文提供了10個(gè)小技巧,你知道幾個(gè)呢?
1.使用驗(yàn)證注解
Spring Boot
提供了內(nèi)置的驗(yàn)證注解,可以幫助簡單、快速地對輸入字段進(jìn)行驗(yàn)證,例如檢查 null 或空字段、強(qiáng)制執(zhí)行長度限制、使用正則表達(dá)式驗(yàn)證模式以及驗(yàn)證電子郵件地址。
一些最常用的驗(yàn)證注釋包括:
@NotNull
:指定字段不能為空。@NotEmpty
:指定列表字段不能為空。@NotBlank
:指定字符串字段不得為空或僅包含空格。@Min
和@Max
:指定數(shù)字字段的最小值和最大值。@Pattern
:指定字符串字段必須匹配的正則表達(dá)式模式。@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
2 使用自定義驗(yàn)證注解
雖然 Spring Boot 的內(nèi)置驗(yàn)證注釋很有用,但它們可能無法涵蓋所有情況。如果有特殊參數(shù)驗(yàn)證的場景,可以使用 Spring 的 JSR 303 驗(yàn)證框架創(chuàng)建自定義驗(yàn)證注釋。自定義注解可以讓你的的驗(yàn)證邏輯更具可重用性和可維護(hù)性。
假設(shè)我們有一個(gè)應(yīng)用程序,用戶可以在其中創(chuàng)建帖子。每個(gè)帖子都應(yīng)該有一個(gè)標(biāo)題和一個(gè)正文,并且標(biāo)題在所有帖子中應(yīng)該是唯一的。雖然 Spring Boot 提供了用于檢查字段是否為空的內(nèi)置驗(yàn)證注釋,但它沒有提供用于檢查唯一性的內(nèi)置驗(yàn)證注釋。在這種情況下,我們可以創(chuàng)建一個(gè)自定義驗(yàn)證注解來處理這種情況。
首先,我們創(chuàng)建自定義約束注解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 {};
}
接下來,我們創(chuàng)建一個(gè)PostRepository
接口,目的是從數(shù)據(jù)庫中檢索帖子:
public interface PostRepository extends JpaRepository<Post, Long> {
Post findByTitle(String title);
}
然后我們需要定義驗(yàn)證器類 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
實(shí)現(xiàn)了ConstraintValidator
接口,它有兩個(gè)泛型類型:第一個(gè)是自定義注解UniqueTitle
,第二個(gè)是正在驗(yàn)證的字段類型(在本例中為String
). 我們還自動裝配了PostRepository
類以從數(shù)據(jù)庫中檢索帖子。
isValid()
方法通過查詢 PostRepository
來檢查 title
是否為 null 或者它是否是唯一的。如果 title
為 null 或唯一,則驗(yàn)證成功,并返回 true。
定義了自定義驗(yàn)證注釋和驗(yàn)證器類后,我們現(xiàn)在可以使用它來驗(yàn)證 Spring Boot 應(yīng)用程序中的帖子標(biāo)題:
public class Post {
@UniqueTitle
private String title;
@NotNull
private String body;
}
我們已將 @UniqueTitle
注釋應(yīng)用于 Post
類中的 title
變量。驗(yàn)證此字段時(shí),這將觸發(fā) UniqueTitleValidator
類中定義的驗(yàn)證邏輯。
3 在服務(wù)器端驗(yàn)證
除了前端或者客戶端做了驗(yàn)證意外,服務(wù)器端驗(yàn)證輸入是至關(guān)重要的。它可以確保在處理或存儲任何惡意或格式錯誤的數(shù)據(jù)之前將其捕獲,這對于應(yīng)用程序的安全性和穩(wěn)定性至關(guān)重要。
假設(shè)我們有一個(gè)允許用戶創(chuàng)建新帳戶的 REST
端點(diǎn)。端點(diǎn)需要一個(gè)包含用戶用戶名和密碼的 JSON 請求體。為確保輸入有效,我們可以創(chuàng)建一個(gè) DTO(數(shù)據(jù)傳輸對象)類并將驗(yàn)證注釋應(yīng)用于其字段:
public class UserDTO {
@NotBlank
private String username;
@NotBlank
private String password;
}
我們使用@NotBlank
注解來確保username
和password
字段不為空或 null。
接下來,我們可以創(chuàng)建一個(gè)控制器方法來處理 HTTP POST 請求并在創(chuàng)建新用戶之前驗(yàn)證輸入:
@RestController
@RequestMapping("/users")
@Validated
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public ResponseEntity
我們使用 Spring 的@Validated
注解來啟用方法級驗(yàn)證,我們還將 @Valid
注釋應(yīng)用于 userDto
參數(shù)以觸發(fā)驗(yàn)證過程。
4 提供有意義的錯誤信息
當(dāng)驗(yàn)證失敗時(shí),必須提供清晰簡潔的錯誤消息來描述出了什么問題以及如何修復(fù)它。
這是一個(gè)示例,如果我們有一個(gè)允許用戶創(chuàng)建新用戶的 RESTful API
。我們要確保姓名和電子郵件地址字段不為空,年齡在 18 到 99 歲之間,除了這些字段,如果用戶嘗試使用重復(fù)的“用戶名”創(chuàng)建帳戶,我們還會提供明確的錯誤消息或“電子郵件”。
為此,我們可以定義一個(gè)帶有必要驗(yàn)證注釋的模型類 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屬性為每個(gè)驗(yàn)證注釋提供了自定義錯誤消息。
接下來,在我們的 Spring 控制器中,我們可以處理表單提交并使用 @Valid
注釋驗(yàn)證用戶輸入:
@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
注釋來觸發(fā)User
對象的驗(yàn)證,并使用BindingResult
對象來捕獲任何驗(yàn)證錯誤。
-
開發(fā)
+關(guān)注
關(guān)注
0文章
359瀏覽量
40769 -
參數(shù)
+關(guān)注
關(guān)注
11文章
1727瀏覽量
31980 -
spring
+關(guān)注
關(guān)注
0文章
335瀏覽量
14277 -
SpringBoot
+關(guān)注
關(guān)注
0文章
173瀏覽量
153
發(fā)布評論請先 登錄
相關(guān)推薦
評論