Skip to content

Commit d20b180

Browse files
committed
电话号码验证
1 parent 4da879b commit d20b180

File tree

8 files changed

+116
-23
lines changed

8 files changed

+116
-23
lines changed

docs/advanced/spring-bean-validation.md

+66-19
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,10 @@
1-
数据的校验的重要性就不用说了,即使在前端对数据进行校验的情况下,我们还是要对传入后端的数据再进行一遍校验,避免用户绕过浏览器直接通过一些 HTTP 工具直接向后端请求一些违法数据。
1+
**数据的校验的重要性就不用说了,即使在前端对数据进行校验的情况下,我们还是要对传入后端的数据再进行一遍校验,避免用户绕过浏览器直接通过一些 HTTP 工具直接向后端请求一些违法数据。**
22

3-
最近工作中很多地方需要对参数做一些校验,刚开始的时候除了Controller层接受的对象我是直接通过一些 Spring 提供好的注解来实现校验比如`@Valid``@NotNull` 等等,在一些需要对参数做校验的其他地方我都是通过手动编程if else判断的方式来实现。后面重构代码发现有更好的方式来满足我的需求,然后花了半天时间对这部分内容做了一个简单的总结,希望可以对不了解这部分知识的朋友有帮助。
3+
本文结合自己在项目中的实际使用经验,可以说**文章介绍的内容很实用,不了解的朋友可以学习一下,后面可以立马实践到项目上去。**
44

55
下面我会通过实例程序演示如何在 Java 程序中尤其是 Spring 程序中优雅地的进行参数验证。
66

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+
## 基础设施搭建
218

229
### 相关依赖
2310

@@ -357,9 +344,13 @@ public class PersonServiceTest {
357344
Validator validate
358345
```
359346

360-
## 自定以 Validator
347+
## 自定以 Validator(实用)
361348

362-
如果自带的校验注解无法满足你的需求的话,你还可以自定义实现注解。比如我们的Person类多了一个 region 字段,region 字段只能是`China``China-Taiwan``China-HongKong`这三个中的一个。
349+
如果自带的校验注解无法满足你的需求的话,你还可以自定义实现注解。
350+
351+
### 案例一:校验特定字段的值是否在可选范围
352+
353+
比如我们现在多了这样一个需求:Person类多了一个 region 字段,region 字段只能是`China``China-Taiwan``China-HongKong`这三个中的一个。
363354

364355
第一步你需要创建一个注解:
365356

@@ -406,9 +397,63 @@ public class RegionValidator implements ConstraintValidator<Region, String> {
406397
private String region;
407398
```
408399

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+
409454
## 使用验证组
410455

411-
很多时候我们需要使用到验证组,这样说可能不太清楚,说简单点就是对对象操作的不同方法有不同的验证规则,示例如下。
456+
某些场景下我们需要使用到验证组,这样说可能不太清楚,说简单点就是对对象操作的不同方法有不同的验证规则,示例如下(这个就我目前经历的项目来说使用的比较少,因为本身这个在代码层面理解起来是比较麻烦的,然后写起来也比较麻烦)
412457

413458
先创建两个接口:
414459

@@ -475,6 +520,8 @@ public class PersonService {
475520

476521
代码地址:https://github.com/Snailclimb/springboot-guide/tree/master/source-code/advanced/bean-validation-demo
477522

523+
524+
478525
## TODO
479526

480527
- [ ] JPA 数据库级别参数约束验证

source-code/advanced/bean-validation-demo/src/main/java/com/example/beanvalidationdemo/entity/Person.java

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import com.example.beanvalidationdemo.constants.Constants;
44
import com.example.beanvalidationdemo.service.AddPersonGroup;
55
import com.example.beanvalidationdemo.service.DeletePersonGroup;
6+
import com.example.beanvalidationdemo.validation.PhoneNumber;
7+
import com.example.beanvalidationdemo.validation.Region;
68
import lombok.AllArgsConstructor;
79
import lombok.Data;
810
import lombok.NoArgsConstructor;
@@ -33,6 +35,10 @@ public class Person {
3335
@NotNull(message = "email 不能为空")
3436
private String email;
3537

38+
@PhoneNumber(message = "phoneNumber 格式不正确")
39+
@NotNull(message = "phoneNumber 不能为空")
40+
private String phoneNumber;
41+
3642
@Region
3743
private String region;
3844

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.example.beanvalidationdemo.validation;
2+
3+
import javax.validation.Constraint;
4+
import java.lang.annotation.Documented;
5+
import java.lang.annotation.Retention;
6+
import java.lang.annotation.Target;
7+
8+
import static java.lang.annotation.ElementType.FIELD;
9+
import static java.lang.annotation.ElementType.PARAMETER;
10+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
11+
12+
@Documented
13+
@Constraint(validatedBy = PhoneNumberValidator.class)
14+
@Target({FIELD, PARAMETER})
15+
@Retention(RUNTIME)
16+
public @interface PhoneNumber {
17+
String message() default "Invalid phone number";
18+
Class[] groups() default {};
19+
Class[] payload() default {};
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.example.beanvalidationdemo.validation;
2+
3+
import javax.validation.ConstraintValidator;
4+
import javax.validation.ConstraintValidatorContext;
5+
6+
public class PhoneNumberValidator implements ConstraintValidator<PhoneNumber,String> {
7+
8+
@Override
9+
public boolean isValid(String phoneField, ConstraintValidatorContext context) {
10+
if (phoneField == null) {
11+
// can be null
12+
return true;
13+
}
14+
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;
15+
}
16+
}
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.example.beanvalidationdemo.entity;
1+
package com.example.beanvalidationdemo.validation;
22

33
import javax.validation.Constraint;
44
import javax.validation.Payload;
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.example.beanvalidationdemo.entity;
1+
package com.example.beanvalidationdemo.validation;
22

33
import javax.validation.ConstraintValidator;
44
import javax.validation.ConstraintValidatorContext;

source-code/advanced/bean-validation-demo/src/test/java/com/example/beanvalidationdemo/PersonControllerTest.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ public void should_get_person() throws Exception {
4343
person.setClassId("82938390");
4444
person.setEmail("Snailclimb@qq.com");
4545
person.setRegion("China");
46+
person.setPhoneNumber("13615833391");
47+
4648

4749
mockMvc.perform(post("/api/person")
4850
.contentType(MediaType.APPLICATION_JSON_UTF8)
@@ -61,15 +63,17 @@ public void should_check_person_value() throws Exception {
6163
person.setClassId("82938390");
6264
person.setEmail("SnailClimb");
6365
person.setRegion("BeiGuo");
66+
person.setPhoneNumber("1361583339");
6467

6568
mockMvc.perform(post("/api/person")
6669
.contentType(MediaType.APPLICATION_JSON_UTF8)
6770
.content(objectMapper.writeValueAsString(person)))
6871
.andExpect(MockMvcResultMatchers.jsonPath("sex").value("sex 值不在可选范围"))
6972
.andExpect(MockMvcResultMatchers.jsonPath("name").value("name 不能为空"))
7073
.andExpect(MockMvcResultMatchers.jsonPath("email").value("email 格式不正确"))
71-
.andExpect(MockMvcResultMatchers.jsonPath("region").value("Region 值不在可选范围内"));
72-
;
74+
.andExpect(MockMvcResultMatchers.jsonPath("region").value("Region 值不在可选范围内"))
75+
.andExpect(MockMvcResultMatchers.jsonPath("phoneNumber").value("phoneNumber 格式不正确"));
76+
7377
}
7478

7579
@Test

0 commit comments

Comments
 (0)