Java校驗(yàn)validate介紹和使用實(shí)例
Java校驗(yàn)validate
日常開(kāi)發(fā)中,我們時(shí)常需要提供可靠的 API 接口,此時(shí)對(duì)于請(qǐng)求的入?yún)⒕托枰r?yàn),以保證最終數(shù)據(jù)入庫(kù)的正確性,這就成了必不可少的活。例如說(shuō),用戶注冊(cè)時(shí),會(huì)校驗(yàn)手機(jī)格式的正確性、郵箱格式的正確性、密碼非弱密碼等。
但是如果使用 if-else 這種代碼去校驗(yàn), 那么需要校驗(yàn)的地方有很多情況下,代碼量就會(huì)變的十分臃腫,若是一個(gè)類(lèi)請(qǐng)求參數(shù)校驗(yàn)字段又多的化,相信各位小伙伴對(duì)不會(huì)開(kāi)心,這么干肯定不合適,代碼也不優(yōu)雅,那么如何解決這個(gè)問(wèn)題呢?
答案就是下面要介紹的 validation
validation介紹
validation 技術(shù)在Java中運(yùn)用最早在2009 年,Java 官方提出了 Bean Validation 規(guī)范,而后經(jīng)歷了JSR303、JSR349、JSR380 三次標(biāo)準(zhǔn)的更迭,發(fā)展到了 2.0 。
Bean Validation 和 我們以前學(xué)習(xí)過(guò)的 JPA 一樣,只提供規(guī)范,不提供具體的實(shí)現(xiàn)。因此實(shí)際使用過(guò)程,常用的是 hibernate 的校驗(yàn)組件:org.hibernate.hibernate-validator
常見(jiàn)的注解
通常情況下,在javax.validation.constraints 包下,定義了一系列的約束(constraint)注解,一共 22 個(gè)注解,快速略過(guò)即可。如下:
空和非空檢查
- @NotBlank:只能用于字符串不為 null ,并且字符串 .trim() 以后 length 要大于 0 。
- @NotEmpty:集合對(duì)象的元素不為 0 ,即集合不為空 。
- @NotNull:不能為 null 。
- @Null:必須為 null 。
數(shù)值檢查
- @DecimalMax(value):被注釋的元素必須是一個(gè)數(shù)字,其值必須小于等于指定的最大值。
- @DecimalMin(value):被注釋的元素必須是一個(gè)數(shù)字,其值必須大于等于指定的最小值。
- @Digits(integer, fraction):被注釋的元素必須是一個(gè)數(shù)字,其值必須在可接受的范圍內(nèi)。
- @Positive:判斷正數(shù)。
- @PositiveOrZero:判斷正數(shù)或 0 。
- @Max(value):該字段的值只能小于或等于該值。
- @Min(value):該字段的值只能大于或等于該值。
- @Negative:判斷負(fù)數(shù)。
- @NegativeOrZero:判斷負(fù)數(shù)或 0 。
Boolean 值檢查
- @AssertFalse:被注釋的元素必須為 true 。
- @AssertTrue:被注釋的元素必須為 false 。
長(zhǎng)度檢查
- @Size(max, min):檢查字段的 size 是否在 min 和 max 之間,可以是字符串、數(shù)組、集合、Map 等。
日期檢查
- @Future:被注釋的元素必須是一個(gè)將來(lái)的日期。
- @FutureOrPresent:判斷日期是否是將來(lái)或現(xiàn)在日期。
- @Past:檢查該字段的日期是在過(guò)去。
- @PastOrPresent:判斷日期是否是過(guò)去或現(xiàn)在日期。
其它檢查
- @Email:被注釋的元素必須是電子郵箱地址。
- @Pattern(value):被注釋的元素必須符合指定的正則表達(dá)式。
Hibernate Validator 附加的約束注解,在org.hibernate.validator.constraints 包下,定義了一系列的約束(constraint)注解。常見(jiàn)的如示。
- @Range(min=, max=):被注釋的元素必須在合適的范圍內(nèi)。
- @Length(min=, max=):被注釋的字符串的大小必須在指定的范圍內(nèi)。
- @URL(protocol=,host=,port=,regexp=,flags=):被注釋的字符串必須是一個(gè)有效的 URL 。
- @SafeHtml:判斷提交的 HTML 是否安全。例如說(shuō),不能包含 javascript 腳本等等。
其他的就不一一列舉了,有感興趣的小伙伴可以去源碼包看看。
@Valid和 @Validated
- @Valid 注解,是 Bean Validation 所定義,可以添加在普通方法、構(gòu)造方法、方法參數(shù)、方法返回、成員變量上,表示它們需要進(jìn)行約束校驗(yàn)。
- @Validated 注解,是 Spring Validation 鎖定義,可以添加在類(lèi)、方法參數(shù)、普通方法上,表示它們需要進(jìn)行約束校驗(yàn)。同時(shí),@Validated 有 value 屬性,支持分組校驗(yàn)。
對(duì)于初學(xué)者來(lái)說(shuō),很容易搞混 @Valid 和 @Validated 注解。
- ① 聲明式校驗(yàn):Spring Validation 僅對(duì) @Validated 注解,實(shí)現(xiàn)聲明式校驗(yàn)。
- ② 分組校驗(yàn):Bean Validation 提供的 @Valid注解,因?yàn)闆](méi)有分組校驗(yàn)的屬性,所以無(wú)法提供分組校驗(yàn)。此時(shí),我們只能使用 @Validated 注解。
- ③ 嵌套校驗(yàn):相比來(lái)說(shuō),@Valid注解的地方,多了【成員變量】。這就導(dǎo)致,如果有嵌套對(duì)象的時(shí)候,只能使用@Valid注解。
spring-boot-starter-web 依賴?yán)?,已?jīng)默認(rèn)引入 hibernate-validator 依賴,所以本示例使用的是 Hibernate Validator 作為 Bean Validation 的實(shí)現(xiàn)框架。
1、簡(jiǎn)單校驗(yàn)
編寫(xiě)實(shí)體類(lèi)(這里以常用的用戶注冊(cè)為場(chǎng)景)
@Data
public class SysUser {
private Long userId;
/**
* 賬號(hào)
*/
@NotBlank(message = "用戶名不能為空")
@Size(min = 6, message = "用戶名長(zhǎng)度不能小于6個(gè)字符")
private String username;
/**
* 密碼
*/
@NotEmpty(message = "密碼不能為空")
@Size(min = 8, message = "密碼長(zhǎng)度不能小于8個(gè)字符")
private String password;
/**
* 手機(jī)號(hào)
*/
@NotBlank(message = "手機(jī)號(hào)不能為空")
@Size(min = 11, max = 11, message = "手機(jī)號(hào)長(zhǎng)度不對(duì)")
private String mobile;
}編寫(xiě)前端控制器
@RestController
@RequestMapping("/user")
public class SysUserController {
@PostMapping("/add")
public R addUser(@RequestBody @Valid SysUser sysUser) {
System.out.println("走到這里說(shuō)明校驗(yàn)成功");
System.out.println(sysUser);
return R.ok(R.SUCCESS_MSG);
}
}編寫(xiě)前端響應(yīng)封裝實(shí)體
public class R extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
public static final String SUCCESS_MSG = "操作成功!";
public static final String FAIL_MSG = "操作失??!";
public R() {
this.put((String) "code", 0);
}
public static R error() {
return error(500, "未知異常,請(qǐng)聯(lián)系管理員");
}
public static R error(String msg) { return error(500, msg); } public static R error(int code, String msg) { R r = new R(); r.put((String) "code", code); r.put((String) "msg", msg); return r; } public static R ok(String msg) { R r = new R(); r.put((String) "msg", msg); return r; } public static R ok(Object object) { R r = new R(); r.put("result", object); return r; } public static R ok(int code, String msg) { R r = new R(); r.put((String) "code", code); r.put((String) "msg", msg); return r; } public static R ok(Map<String, Object> map) { R r = new R(); r.putAll(map); return r; } public static R ok() { return new R(); } public R put(String key, Object value) { super.put(key, value); return this; } 編寫(xiě)自定義異常(用于后續(xù)業(yè)務(wù)拋出異常錯(cuò)誤)
public class RRException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String msg;
private int code = 500;
public RRException(String msg) {
super(msg);
this.msg = msg;
}
public RRException(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
}
public RRException(String msg, int code) {
super(msg);
this.msg = msg;
this.code = code;
}
public RRException(String msg, int code, Throwable e) {
super(msg, e);
this.msg = msg;
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}當(dāng)訪問(wèn)/user/add這個(gè)post接口時(shí),如果參數(shù)不符合Model中定義的話,程序中就回拋出400異常狀態(tài)碼,并提示錯(cuò)誤信息,如下所示。
{
“timestamp”: “2021-05-20T01:08:28.831+0000”,
“status”: 400,
“error”: “Bad Request”,
“errors”: [
{
“codes”: [ “Size.sysUser.mobile”, “Size.mobile”, “Size.java.lang.String”, “Size” ],
“arguments”: [ { “codes”: [ “sysUser.mobile”, “mobile” ], “arguments”: null, “defaultMessage”: “mobile”, “code”: “mobile” },
11,
11
],
“defaultMessage”: “手機(jī)號(hào)長(zhǎng)度不對(duì)”,
“objectName”: “sysUser”,
“field”: “mobile”,
“rejectedValue”: “155833013”,
“bindingFailure”: false,
“code”: “Size”
}
],
“message”: “Validation failed for object=‘sysUser'. Error count: 1”,
“path”: “/user/add”
}自定義校驗(yàn)注解
雖然 JSR303 和 Hibernate Validtor 已經(jīng)提供了很多校驗(yàn)注解,但是當(dāng)面對(duì)復(fù)雜參數(shù)校驗(yàn)時(shí),還是不能滿足我們的要求,這時(shí)候我們就需要 自定義校驗(yàn)注解。
下面以“List數(shù)組中不能含有null元素”為實(shí)例自定義校驗(yàn)注解
1、注解定義如示。
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = ListNotHaveNullValidatorImpl.class)//此處指定了注解的實(shí)現(xiàn)類(lèi)
public @interface ListNotHaveNull {
/**
* 添加value屬性,可以作為校驗(yàn)時(shí)的條件,若不需要,可去掉此處定義
/
int value() default 0;
String message() default “List集合中不能含有null元素”;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
/*
* 定義List,為了讓Bean的一個(gè)屬性上可以添加多套規(guī)則
*/
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@interface List {
ListNotHaveNull[] value();
}
}編寫(xiě)自定義校驗(yàn)實(shí)現(xiàn)類(lèi)
@Service
public class ListNotHaveNullValidatorImpl implements ConstraintValidator<ListNotHaveNull, List> {
private int value;
@Override
public void initialize(ListNotHaveNull constraintAnnotation) {
//傳入value 值,可以在校驗(yàn)中使用
this.value = constraintAnnotation.value();
}
public boolean isValid(List list, ConstraintValidatorContext constraintValidatorContext) {
for (Object object : list) {
if (object == null) {
//如果List集合中含有Null元素,校驗(yàn)失敗
return false;
} else if (object instanceof String) {
String value = object.toString();
if (value.trim().length() == 0){
return false;
}
}
}
return true;
}
}model中添加注解:
@Data
public class SysRole {private Long roleId; @NotBlank(message = "角色名不能為空") private String name; @NotEmpty(message = "資源列表不能為空") @ListNotHaveNull(message = "List 中不能含有null元素") @Valid private List<String> paths;
編寫(xiě)前端控制器
@PostMapping(“/addRole”)
public R addRole(@RequestBody @Valid SysRole sysRole) {
System.out.println(“走到這里說(shuō)明校驗(yàn)成功”);
System.out.println(sysRole);
return R.ok(R.SUCCESS_MSG);
}使用方法同 “簡(jiǎn)單校驗(yàn)”,在在需要校驗(yàn)的Model上面加上@Valid即可。
通用的Validtor校驗(yàn)工具類(lèi)
public class ValidatorUtils {
private ValidatorUtils() { }private static Validator validator; static { validator = Validation.buildDefaultValidatorFactory().getValidator(); } /** * 校驗(yàn)對(duì)象 * * @param object 待校驗(yàn)對(duì)象 * @param groups 待校驗(yàn)的組 * @throws RRException 校驗(yàn)不通過(guò),則報(bào)RRException異常 */ public static void validateEntity(Object object, Class<?>... groups) throws RRException { Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups); if (!constraintViolations.isEmpty()) { Iterator<ConstraintViolation<Object>> iterator = constraintViolations.iterator(); StringBuilder msg = new StringBuilder(); while (iterator.hasNext()) { ConstraintViolation<Object> constraint = iterator.next(); msg.append(constraint.getMessage()).append(','); } throw new RRException(msg.toString().substring(0,msg.toString().lastIndexOf(','))); } } 使用方式,在接收到前端傳遞的參數(shù)后,使用ValidatorUtils.validateEntity(【參數(shù)名】);即可校驗(yàn),支持分組校驗(yàn),分組需要定義分組接口。
總結(jié)
到此這篇關(guān)于Java校驗(yàn)validate介紹和使用的文章就介紹到這了,更多相關(guān)Java校驗(yàn)validate內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
用Java實(shí)現(xiàn)簡(jiǎn)單ATM機(jī)功能
這篇文章主要為大家詳細(xì)介紹了用Java實(shí)現(xiàn)簡(jiǎn)單ATM機(jī)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
非maven項(xiàng)目快速轉(zhuǎn)換為maven項(xiàng)目的方法步驟
時(shí)候我們導(dǎo)入的項(xiàng)目并不是有maven來(lái)管理依賴的,而是要手動(dòng)添加jar包,比較麻煩,本文主要介紹了非maven項(xiàng)目快速轉(zhuǎn)換為maven項(xiàng)目的方法步驟,具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01
IDEA最新版2020.1的maven工程本地依賴倉(cāng)庫(kù)無(wú)法使用問(wèn)題(已解決)
這篇文章主要介紹了IDEA最新版2020.1的maven工程本地依賴倉(cāng)庫(kù)無(wú)法使用問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
70行Java代碼實(shí)現(xiàn)深度神經(jīng)網(wǎng)絡(luò)算法分享
這篇文章主要介紹了70行Java代碼實(shí)現(xiàn)深度神經(jīng)網(wǎng)絡(luò)算法分享,涉及神經(jīng)網(wǎng)絡(luò)的計(jì)算過(guò)程,神經(jīng)網(wǎng)絡(luò)的算法程序?qū)崿F(xiàn),多層神經(jīng)網(wǎng)絡(luò)完整程序?qū)崿F(xiàn)等相關(guān)內(nèi)容,具有一定參考價(jià)值,需要的朋友可以參考下。2017-11-11
MyBatis-Plus 中 的動(dòng)態(tài)SQL 片段(sqlSegment)詳解
MyBatis-Plus的sqlSegment通過(guò)Wrapper動(dòng)態(tài)生成SQL片段,支持XML中${ew.customSqlSegment}引用,結(jié)合Lambda表達(dá)式避免硬編碼,適用于動(dòng)態(tài)查詢、邏輯刪除等場(chǎng)景,提升代碼可維護(hù)性與靈活性,本文給大家介紹MyBatis-Plus中的動(dòng)態(tài)SQL片段(sqlSegment)講解,感興趣的朋友一起看看吧2025-06-06
Java8中List轉(zhuǎn)換String字符串幾種方式
這篇文章主要給大家介紹了關(guān)于Java8中List轉(zhuǎn)換String字符串的幾種方式,在實(shí)際開(kāi)發(fā)中經(jīng)常遇到List轉(zhuǎn)為String字符串的情況,文中給出了幾種方法的示例代碼,需要的朋友可以參考下2023-07-07
Spring?Security短信驗(yàn)證碼實(shí)現(xiàn)詳解
本文主要介紹了Spring?Security短信驗(yàn)證碼的實(shí)現(xiàn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-11-11
使用Java實(shí)現(xiàn)自動(dòng)調(diào)整Excel行高和列寬
在處理 Excel 文件時(shí),自動(dòng)調(diào)整行高和列寬是一項(xiàng)常見(jiàn)的需求,本文將介紹如何使用 Java 來(lái)自動(dòng)調(diào)整 Excel 文件中的行高和列寬,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2026-01-01

