4 提供有意義的錯(cuò)誤信息
當(dāng)驗(yàn)證失敗時(shí),必須提供清晰簡(jiǎn)潔的錯(cuò)誤消息來描述出了什么問題以及如何修復(fù)它。
這是一個(gè)示例,如果我們有一個(gè)允許用戶創(chuàng)建新用戶的 RESTful API
。我們要確保姓名和電子郵件地址字段不為空,年齡在 18 到 99 歲之間,除了這些字段,如果用戶嘗試使用重復(fù)的“用戶名”創(chuàng)建帳戶,我們還會(huì)提供明確的錯(cuò)誤消息或“電子郵件”。
為此,我們可以定義一個(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)證注釋提供了自定義錯(cuò)誤消息。
接下來,在我們的 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
對(duì)象的驗(yàn)證,并使用BindingResult
對(duì)象來捕獲任何驗(yàn)證錯(cuò)誤。
5 將 i18n 用于錯(cuò)誤消息
如果你的應(yīng)用程序支持多種語言,則必須使用國(guó)際化 (i18n) 以用戶首選語言顯示錯(cuò)誤消息。
以下是在 Spring Boot 應(yīng)用程序中使用 i18n 處理錯(cuò)誤消息的示例
- 首先,在資源目錄下創(chuàng)建一個(gè)包含默認(rèn)錯(cuò)誤消息的
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.
- 接下來,為每種支持的語言創(chuàng)建一個(gè)
messages_xx.properties
文件,例如,中文的messages_zh_CN.properties
。
user.name.required=名稱不能為空.
user.email.invalid=無效的email格式.
user.age.invalid=年齡必須在18到99歲之間.
- 然后,更新您的驗(yàn)證注釋以使用本地化的錯(cuò)誤消息
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;
}
}
- 現(xiàn)在,當(dāng)發(fā)生驗(yàn)證錯(cuò)誤時(shí),錯(cuò)誤消息將根據(jù)隨請(qǐng)求發(fā)送的“Accept-Language”標(biāo)頭以用戶的首選語言顯示。
6 使用分組驗(yàn)證
驗(yàn)證組是 Spring Boot 驗(yàn)證框架的一個(gè)強(qiáng)大功能,允許您根據(jù)其他輸入值或應(yīng)用程序狀態(tài)應(yīng)用條件驗(yàn)證規(guī)則。
現(xiàn)在有一個(gè)包含三個(gè)字段的User
類的情況下:firstName
、lastName
和email
。我們要確保如果 email
字段為空,則 firstName
或 lastName
字段必須非空。否則,所有三個(gè)字段都應(yīng)該正常驗(yàn)證。
為此,我們將定義兩個(gè)驗(yàn)證組:EmailNotEmpty
和 Default
。EmailNotEmpty
組將包含當(dāng) email
字段不為空時(shí)的驗(yàn)證規(guī)則,而 Default
組將包含所有三個(gè)字段的正常驗(yàn)證規(guī)則。
- 創(chuàng)建帶有驗(yàn)證組的
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 {}
}
- 請(qǐng)注意,我們?cè)?code>User類中定義了兩個(gè)接口,
EmailNotEmpty
和Default
。這些將作為我們的驗(yàn)證組。
- 接下來,我們更新
Controller
使用這些驗(yàn)證組
@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
注釋添加到我們的控制器,表明我們想要使用驗(yàn)證組。我們還更新了createUser
方法,將兩個(gè)User
對(duì)象作為輸入,一個(gè)在email
字段不為空時(shí)使用,另一個(gè)在它為空時(shí)使用。 @Validated
注釋用于指定將哪個(gè)驗(yàn)證組應(yīng)用于每個(gè)User
對(duì)象。對(duì)于userWithEmail
參數(shù),我們指定了EmailNotEmpty
組,而對(duì)于userWithoutEmail
參數(shù),我們指定了Default
組。
- 進(jìn)行這些更改后,現(xiàn)在將根據(jù)“電子郵件”字段是否為空對(duì)“用戶”類進(jìn)行不同的驗(yàn)證。如果為空,則
firstName
或lastName
字段必須非空。否則,所有三個(gè)字段都將正常驗(yàn)證。
7 對(duì)復(fù)雜邏輯使用跨域驗(yàn)證
如果需要驗(yàn)證跨多個(gè)字段的復(fù)雜輸入規(guī)則,可以使用跨字段驗(yàn)證來保持驗(yàn)證邏輯的組織性和可維護(hù)性。跨字段驗(yàn)證可確保所有輸入值均有效且彼此一致,從而防止出現(xiàn)意外行為。
假設(shè)我們有一個(gè)表單,用戶可以在其中輸入任務(wù)的開始日期和結(jié)束日期,并且我們希望確保結(jié)束日期不早于開始日期。我們可以使用跨域驗(yàn)證來實(shí)現(xiàn)這一點(diǎn)。
- 首先,我們定義一個(gè)自定義驗(yàn)證注解
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 {};
}
- 然后,我們創(chuàng)建驗(yàn)證器
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
注釋應(yīng)用于我們的表單對(duì)象TaskForm
:
@EndDateAfterStartDate
public class TaskForm {
@NotNull
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate startDate;
@NotNull
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate endDate;
}
現(xiàn)在,當(dāng)用戶提交表單時(shí),驗(yàn)證框架將自動(dòng)檢查結(jié)束日期是否晚于開始日期,如果不是,則提供有意義的錯(cuò)誤消息。
8 對(duì)驗(yàn)證錯(cuò)誤使用異常處理
可以使用異常處理ExceptionHandler
來統(tǒng)一捕獲和處理驗(yàn)證錯(cuò)誤。
以下是如何在 Spring Boot 中使用異常處理來處理驗(yàn)證錯(cuò)誤的示例:
@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);
}
}
在這里,我們創(chuàng)建了一個(gè)用 @RestControllerAdvice
注解的 RestExceptionHandler
類來處理我們的 REST API 拋出的異常。然后我們創(chuàng)建一個(gè)用@ExceptionHandler
注解的方法來處理在驗(yàn)證失敗時(shí)拋出的 MethodArgumentNotValidException
。
在處理程序方法中,我們創(chuàng)建了一個(gè) Map
對(duì)象來保存錯(cuò)誤響應(yīng)的詳細(xì)信息,包括時(shí)間戳、HTTP 狀態(tài)代碼和錯(cuò)誤消息列表。我們使用 MethodArgumentNotValidException
對(duì)象的 getBindingResult()
方法獲取所有驗(yàn)證錯(cuò)誤并將它們添加到錯(cuò)誤消息列表中。
最后,我們返回一個(gè)包含錯(cuò)誤響應(yīng)詳細(xì)信息的ResponseEntity
對(duì)象,包括作為響應(yīng)主體的錯(cuò)誤消息列表、HTTP 標(biāo)頭和 HTTP 狀態(tài)代碼。
有了這個(gè)異常處理代碼,我們的 REST API 拋出的任何驗(yàn)證錯(cuò)誤都將被捕獲并以結(jié)構(gòu)化和有意義的格式返回給用戶,從而更容易理解和解決問題。
9 測(cè)試你的驗(yàn)證邏輯
需要為你的驗(yàn)證邏輯編寫單元測(cè)試,以幫助確保它正常工作。
@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
我們使用 JUnit 5 編寫一個(gè)測(cè)試來驗(yàn)證具有無效電子郵件地址的“用戶”對(duì)象。然后我們使用 Validator
接口來驗(yàn)證 User
對(duì)象并檢查是否返回了預(yù)期的驗(yàn)證錯(cuò)誤。
10 考慮客戶端驗(yàn)證
客戶端驗(yàn)證可以通過向用戶提供即時(shí)反饋并減少對(duì)服務(wù)器的請(qǐng)求數(shù)量來改善用戶體驗(yàn)。但是,不應(yīng)依賴它作為驗(yàn)證輸入的唯一方法。客戶端驗(yàn)證很容易被繞過或操縱,因此必須在服務(wù)器端驗(yàn)證輸入,以確保安全性和數(shù)據(jù)完整性。
總結(jié)
有效的驗(yàn)證對(duì)于任何 Web 應(yīng)用程序的穩(wěn)定性和安全性都是必不可少的。Spring Boot 提供了一套工具和庫(kù)來簡(jiǎn)化驗(yàn)證邏輯并使其更易于維護(hù)。通過遵循本文中討論的最佳實(shí)踐,您可以確保您的驗(yàn)證組件有效并提供出色的用戶體驗(yàn)。
-
參數(shù)
+關(guān)注
關(guān)注
11文章
1865瀏覽量
32847 -
spring
+關(guān)注
關(guān)注
0文章
340瀏覽量
14870 -
驗(yàn)證
+關(guān)注
關(guān)注
0文章
62瀏覽量
15444 -
Boot
+關(guān)注
關(guān)注
0文章
153瀏覽量
36525
發(fā)布評(píng)論請(qǐng)先 登錄
Spring Boot嵌入式Web容器原理是什么
Spring Boot從零入門1 詳述
Spring Boot實(shí)現(xiàn)各種參數(shù)校驗(yàn)
Spring Boot特有的實(shí)踐
強(qiáng)大的Spring Boot 3.0要來了
Spring Boot Web相關(guān)的基礎(chǔ)知識(shí)
簡(jiǎn)述Spring Boot數(shù)據(jù)校驗(yàn)
SpringBoot參數(shù)驗(yàn)證的10個(gè)技巧1
在Spring Boot中如何使用定時(shí)任務(wù)
Spring Boot應(yīng)用中如何做好參數(shù)校驗(yàn)?
Spring Boot Actuator快速入門
Spring Boot啟動(dòng) Eureka流程

Spring Boot的啟動(dòng)原理

評(píng)論