|
1 |
| -数据的校验的重要性就不用说了,即使在前端对数据进行校验的情况下,我们还是要对传入后端的数据再进行一遍校验,避免用户绕过浏览器直接通过一些 HTTP 工具直接向后端请求一些违法数据。 |
| 1 | +**数据的校验的重要性就不用说了,即使在前端对数据进行校验的情况下,我们还是要对传入后端的数据再进行一遍校验,避免用户绕过浏览器直接通过一些 HTTP 工具直接向后端请求一些违法数据。** |
2 | 2 |
|
3 |
| -最近工作中很多地方需要对参数做一些校验,刚开始的时候除了Controller层接受的对象我是直接通过一些 Spring 提供好的注解来实现校验比如`@Valid`、`@NotNull` 等等,在一些需要对参数做校验的其他地方我都是通过手动编程if else判断的方式来实现。后面重构代码发现有更好的方式来满足我的需求,然后花了半天时间对这部分内容做了一个简单的总结,希望可以对不了解这部分知识的朋友有帮助。 |
| 3 | +本文结合自己在项目中的实际使用经验,可以说**文章介绍的内容很实用,不了解的朋友可以学习一下,后面可以立马实践到项目上去。** |
4 | 4 |
|
5 | 5 | 下面我会通过实例程序演示如何在 Java 程序中尤其是 Spring 程序中优雅地的进行参数验证。
|
6 | 6 |
|
7 |
| -- [基础知识和依赖](#基础知识和依赖) |
8 |
| - - [相关依赖](#相关依赖) |
9 |
| - - [实体类](#实体类) |
10 |
| -- [验证Controller的输入](#验证controller的输入) |
11 |
| - - [验证请求体(RequestBody)](#验证请求体requestbody) |
12 |
| - - [验证请求参数(Path Variables 和 Request Parameters)](#验证请求参数path-variables-和-request-parameters) |
13 |
| -- [验证 Service 中的方法](#验证-service-中的方法) |
14 |
| -- [Validator 编程方式手动进行参数验证](#validator-编程方式手动进行参数验证) |
15 |
| -- [自定义 Validator](#自定以-validator) |
16 |
| -- [使用验证组](#使用验证组) |
17 |
| -- [TODO](#todo) |
18 |
| -- [参考](#参考) |
19 |
| - |
20 |
| -## 基础知识和依赖 |
| 7 | +## 基础设施搭建 |
21 | 8 |
|
22 | 9 | ### 相关依赖
|
23 | 10 |
|
@@ -357,9 +344,13 @@ public class PersonServiceTest {
|
357 | 344 | Validator validate
|
358 | 345 | ```
|
359 | 346 |
|
360 |
| -## 自定以 Validator |
| 347 | +## 自定以 Validator(实用) |
361 | 348 |
|
362 |
| -如果自带的校验注解无法满足你的需求的话,你还可以自定义实现注解。比如我们的Person类多了一个 region 字段,region 字段只能是`China`、`China-Taiwan`、`China-HongKong`这三个中的一个。 |
| 349 | +如果自带的校验注解无法满足你的需求的话,你还可以自定义实现注解。 |
| 350 | + |
| 351 | +### 案例一:校验特定字段的值是否在可选范围 |
| 352 | + |
| 353 | +比如我们现在多了这样一个需求:Person类多了一个 region 字段,region 字段只能是`China`、`China-Taiwan`、`China-HongKong`这三个中的一个。 |
363 | 354 |
|
364 | 355 | 第一步你需要创建一个注解:
|
365 | 356 |
|
@@ -406,9 +397,63 @@ public class RegionValidator implements ConstraintValidator<Region, String> {
|
406 | 397 | private String region;
|
407 | 398 | ```
|
408 | 399 |
|
| 400 | +### 案例二:校验电话号码 |
| 401 | + |
| 402 | +校验我们的电话号码是否合法,这个可以通过正则表达式来做,相关的正则表达式都可以在网上搜到,你甚至可以搜索到针对特定运营商电话号码段的正则表达式。 |
| 403 | + |
| 404 | +`PhoneNumber.java` |
| 405 | + |
| 406 | +```java |
| 407 | +import javax.validation.Constraint; |
| 408 | +import java.lang.annotation.Documented; |
| 409 | +import java.lang.annotation.Retention; |
| 410 | +import java.lang.annotation.Target; |
| 411 | + |
| 412 | +import static java.lang.annotation.ElementType.FIELD; |
| 413 | +import static java.lang.annotation.ElementType.PARAMETER; |
| 414 | +import static java.lang.annotation.RetentionPolicy.RUNTIME; |
| 415 | + |
| 416 | +@Documented |
| 417 | +@Constraint(validatedBy = PhoneNumberValidator.class) |
| 418 | +@Target({FIELD, PARAMETER}) |
| 419 | +@Retention(RUNTIME) |
| 420 | +public @interface PhoneNumber { |
| 421 | + String message() default "Invalid phone number"; |
| 422 | + Class[] groups() default {}; |
| 423 | + Class[] payload() default {}; |
| 424 | +} |
| 425 | +``` |
| 426 | + |
| 427 | +`PhoneNumberValidator.java` |
| 428 | + |
| 429 | +```java |
| 430 | +import javax.validation.ConstraintValidator; |
| 431 | +import javax.validation.ConstraintValidatorContext; |
| 432 | + |
| 433 | +public class PhoneNumberValidator implements ConstraintValidator<PhoneNumber,String> { |
| 434 | + |
| 435 | + @Override |
| 436 | + public boolean isValid(String phoneField, ConstraintValidatorContext context) { |
| 437 | + if (phoneField == null) { |
| 438 | + // can be null |
| 439 | + return true; |
| 440 | + } |
| 441 | + return phoneField.matches("^1(3[0-9]|4[57]|5[0-35-9]|8[0-9]|70)\\d{8}$") && phoneField.length() > 8 && phoneField.length() < 14; |
| 442 | + } |
| 443 | +} |
| 444 | +``` |
| 445 | + |
| 446 | +搞定,我们现在就可以使用这个注解了。 |
| 447 | + |
| 448 | +```java |
| 449 | +@PhoneNumber(message = "phoneNumber 格式不正确") |
| 450 | +@NotNull(message = "phoneNumber 不能为空") |
| 451 | +private String phoneNumber; |
| 452 | +``` |
| 453 | + |
409 | 454 | ## 使用验证组
|
410 | 455 |
|
411 |
| -很多时候我们需要使用到验证组,这样说可能不太清楚,说简单点就是对对象操作的不同方法有不同的验证规则,示例如下。 |
| 456 | +某些场景下我们需要使用到验证组,这样说可能不太清楚,说简单点就是对对象操作的不同方法有不同的验证规则,示例如下(这个就我目前经历的项目来说使用的比较少,因为本身这个在代码层面理解起来是比较麻烦的,然后写起来也比较麻烦)。 |
412 | 457 |
|
413 | 458 | 先创建两个接口:
|
414 | 459 |
|
@@ -475,6 +520,8 @@ public class PersonService {
|
475 | 520 |
|
476 | 521 | 代码地址:https://github.com/Snailclimb/springboot-guide/tree/master/source-code/advanced/bean-validation-demo
|
477 | 522 |
|
| 523 | + |
| 524 | + |
478 | 525 | ## TODO
|
479 | 526 |
|
480 | 527 | - [ ] JPA 数据库级别参数约束验证
|
|
0 commit comments