Java利用自定義注解實(shí)現(xiàn)數(shù)據(jù)校驗(yàn)
JSR303介紹
在Java中提供了一系列的校驗(yàn)方式
這些校驗(yàn)方式在javax.validation.constraints包中
引入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>常用注解
@Null 驗(yàn)證對(duì)象是否為null
@NotNull 驗(yàn)證對(duì)象是否不為null, 無(wú)法查檢長(zhǎng)度為0的字符串
@NotBlank 檢查約束字符串是不是Null還有被Trim的長(zhǎng)度是否大于0,只對(duì)字符串,且會(huì)去掉前后空格.
@NotEmpty 檢查約束元素是否為NULL或者是EMPTY.
Booelan檢查
- @AssertTrue 驗(yàn)證 Boolean 對(duì)象是否為 true
- @AssertFalse 驗(yàn)證 Boolean 對(duì)象是否為 false
長(zhǎng)度檢查
- @Size(min=, max=) 驗(yàn)證對(duì)象(Array,Collection,Map,String)長(zhǎng)度是否在給定的范圍之內(nèi)
- @Length(min=, max=) Validates that the annotated string is between min and max included.
日期檢查
- @Past 驗(yàn)證 Date 和 Calendar 對(duì)象是否在當(dāng)前時(shí)間之前,驗(yàn)證成立的話被注釋的元素一定是一個(gè)過(guò)去的日期
- @Future 驗(yàn)證 Date 和 Calendar 對(duì)象是否在當(dāng)前時(shí)間之后 ,驗(yàn)證成立的話被注釋的元素一定是一個(gè)將來(lái)的日期
- @Pattern 驗(yàn)證 String 對(duì)象是否符合正則表達(dá)式的規(guī)則,被注釋的元素符合制定的正則表達(dá)式,regexp:正則表達(dá)式 flags: 指定 Pattern.Flag 的數(shù)組,表示正則表達(dá)式的相關(guān)選項(xiàng)。
數(shù)值檢查
建議使用在Stirng,Integer類型,不建議使用在int類型上,因?yàn)楸韱沃禐?ldquo;”時(shí)無(wú)法轉(zhuǎn)換為int,但可以轉(zhuǎn)換為Stirng為”“,Integer為null
- @Min 驗(yàn)證 Number 和 String 對(duì)象是否大等于指定的值
- @Max 驗(yàn)證 Number 和 String 對(duì)象是否小等于指定的值
- @DecimalMax 被標(biāo)注的值必須不大于約束中指定的最大值. 這個(gè)約束的參數(shù)是一個(gè)通過(guò)BigDecimal定義的最大值的字符串表示.小數(shù)存在精度
- @DecimalMin 被標(biāo)注的值必須不小于約束中指定的最小值. 這個(gè)約束的參數(shù)是一個(gè)通過(guò)BigDecimal定義的最小值的字符串表示.小數(shù)存在精度
- @Digits 驗(yàn)證 Number 和 String 的構(gòu)成是否合法
- @Digits(integer=,fraction=) 驗(yàn)證字符串是否是符合指定格式的數(shù)字,interger指定整數(shù)精度,fraction指定小數(shù)精度。
- @Range(min=, max=) 被指定的元素必須在合適的范圍內(nèi)
- @Range(min=10000,max=50000,message=”range.bean.wage”)
- @Valid 遞歸的對(duì)關(guān)聯(lián)對(duì)象進(jìn)行校驗(yàn), 如果關(guān)聯(lián)對(duì)象是個(gè)集合或者數(shù)組,那么對(duì)其中的元素進(jìn)行遞歸校驗(yàn),如果是一個(gè)map,則對(duì)其中的值部分進(jìn)行校驗(yàn).(是否進(jìn)行遞歸驗(yàn)證)
- @CreditCardNumber信用卡驗(yàn)證
- @Email 驗(yàn)證是否是郵件地址,如果為null,不進(jìn)行驗(yàn)證,算通過(guò)驗(yàn)證。
- @ScriptAssert(lang= ,script=, alias=)
- @URL(protocol=,host=, port=,regexp=, flags=)
開(kāi)啟校驗(yàn)
controller中加校驗(yàn)注解@Valid,開(kāi)啟校驗(yàn)
數(shù)據(jù)校驗(yàn)測(cè)試
步驟1:實(shí)體類字段上使用校驗(yàn)注解 @NotNull @NotEmpty @NotBlank @Pattern
步驟2:controller中加校驗(yàn)注解@Valid,開(kāi)啟校驗(yàn)
步驟3:給校驗(yàn)的Bean后,緊跟一個(gè)BindingResult,就可以獲取到校驗(yàn)的結(jié)果
public R save(@Valid @RequestBody User user, BindingResult result){}
實(shí)體中添加注解
@Data
public class Student {
@NotEmpty(message ="姓名不能為空")
private String name;
}
controller層中保存方法添加:@Valid
@PostMapping("/jsr")
public AjaxResult testJrs(@Valid @RequestBody User user, BindingResult result) {
String name = user.getName();
HashMap<String, Object> map = new HashMap<>();
map.put("name", name);
map.put("errors", result.getFieldErrors());
return AjaxResult.success("數(shù)據(jù)校驗(yàn)", map);
}數(shù)據(jù)校驗(yàn)測(cè)試:測(cè)試:http://localhost:8080/test/jsr
@Data
public class User {
@NotEmpty(message = "姓名不能為空")
@ApiModelProperty("姓名")
private String name;
@ApiModelProperty("學(xué)號(hào)")
private String id;
@ApiModelProperty("年齡")
private String age;
}
返回信息
{
"msg": "數(shù)據(jù)校驗(yàn)",
"code": 200,
"data": {
"name": "",
"errors": [
{
"codes": [
"NotEmpty.user.name",
"NotEmpty.name",
"NotEmpty.java.lang.String",
"NotEmpty"
],
"arguments": [
{
"codes": [
"user.name",
"name"
],
"defaultMessage": "name",
"code": "name"
}
],
"defaultMessage": "姓名不能為空",
"objectName": "user",
"field": "name",
"rejectedValue": "",
"bindingFailure": false,
"code": "NotEmpty"
}
]
}
}
自定義的封裝錯(cuò)誤信息
@PostMapping("/package")
public AjaxResult testPackage(@Valid @RequestBody User user, BindingResult result) {
String name = user.getName();
Map<String, String> map = new HashMap<>();
map.put("name", name);
if (result.hasErrors()) {
//1.獲取錯(cuò)誤的校驗(yàn)結(jié)果
result.getFieldErrors().forEach((item) -> {
//2.獲取發(fā)生錯(cuò)誤時(shí)的message
String message = item.getDefaultMessage();
//3.獲取發(fā)生錯(cuò)誤的字段
String field = item.getField();
map.put(field, message);
});
return AjaxResult.error("數(shù)據(jù)校驗(yàn)", map);
} else {
return AjaxResult.success(map);
}
}自定義的封裝錯(cuò)誤信息:測(cè)試:http://localhost:80/test/package
{
"name": "",
"id": "demoData",
"age": "demoData"
}
錯(cuò)誤信息
{
"msg": "數(shù)據(jù)校驗(yàn)",
"code": 500,
"data": {
"name": "姓名不能為空"
}
}統(tǒng)一異常處理
@Slf4j
@RestControllerAdvice(basePackages = "com.michale.jrs303.controllers")
public class FireflyMallExceptionControllerAdvice {
/**
* 處理數(shù)據(jù)校驗(yàn)問(wèn)題
* @param e
* @return
*/
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Result handleVaildException(MethodArgumentNotValidException e) {
log.error("數(shù)據(jù)校驗(yàn)出現(xiàn)問(wèn)題:{},異常類型:{}", e.getMessage(), e.getClass());
BindingResult bindingResult = e.getBindingResult();
Map<String, String> errorMap = new HashMap();
bindingResult.getFieldErrors().forEach((fieldError) -> {
errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
});
return Result.fail(errorMap, "數(shù)據(jù)校驗(yàn)出現(xiàn)問(wèn)題");
}
/**
* 處理其他異常
* @param throwable
* @return
*/
@ExceptionHandler(value = Throwable.class)
public Result handleException(Throwable throwable) {
return Result.fail();
}
}
@RequestMapping("/testException")
public Result testException(@Valid @RequestBody Student student) {
String name = student.getName();
Map<String, String> map = new HashMap<>();
map.put("name", name);
return Result.ok(map);
}測(cè)試統(tǒng)一異常處理:測(cè)試:http://localhost:8080/testException
{
"msg": "數(shù)據(jù)校驗(yàn)出現(xiàn)問(wèn)題",
"path": "/test/testException",
"code": 414,
"errors": {
"name": "姓名不能為空"
}
}錯(cuò)誤信息
{
"code": 500,
"msg": "數(shù)據(jù)校驗(yàn)出現(xiàn)問(wèn)題",
"data": {
"name": "姓名不能為空"
}
}分組校驗(yàn)
創(chuàng)建分組校驗(yàn)接口
/**
* @Author 天才小狐貍
* @Data 2022/8/11 2:03
* @Description 姓名校驗(yàn)分組
*/
public interface NameGroup {
}/**
* @Author 天才小狐貍
* @Data 2022/8/11 2:04
* @Description 年齡校驗(yàn)分組
*/
public interface AgeGroup {
}添加校驗(yàn)注解
@Data
public class Student {
@NotEmpty(message ="姓名不能為空",groups = NameGroup.class)
private String name;
@NotEmpty(message ="綽號(hào)不能為空",groups = NameGroup.class)
private String nickName;
@Min(value = 18,message = "年齡下限不能低于18歲" ,groups = AgeGroup.class)
private String age;
@Max(value = 60,message = "年齡上限不能超過(guò)60歲" ,groups = AgeGroup.class)
private String retireAge;
}開(kāi)啟分組校驗(yàn)
@Validated(NameGroup.class)指定校驗(yàn)分組
@RequestMapping("/testGroup")
public Result testGroup(@Validated(NameGroup.class) @RequestBody Student student) {
String name = student.getName();
String nickName = student.getNickName();
String age = student.getAge();
String retireAge = student.getRetireAge();
Map<String, String> map = new HashMap<>();
map.put("name", name);
map.put("nickname", nickName);
map.put("age", age);
map.put("retireAge", retireAge);
return Result.ok(map);
}測(cè)試分組校驗(yàn):http://localhost:8080/testGroup
{
"name":"",
"nickName":"",
"age":"17",
"retireAge":"66"
}錯(cuò)誤信息
{
"code": 500,
"msg": "數(shù)據(jù)校驗(yàn)出現(xiàn)問(wèn)題",
"data": {
"nickName": "綽號(hào)不能為空",
"name": "姓名不能為空"
}
}@Validated(AgeGroup.class)指定校驗(yàn)分組
@RequestMapping("/testGroup")
public Result testGroup(@Validated(AgeGroup.class) @RequestBody Student student) {
String name = student.getName();
String nickName = student.getNickName();
String age = student.getAge();
String retireAge = student.getRetireAge();
Map<String, String> map = new HashMap<>();
map.put("name", name);
map.put("nickname", nickName);
map.put("age", age);
map.put("retireAge", retireAge);
return Result.ok(map);
}測(cè)試分組校驗(yàn):http://localhost:8080/testGroup
{
"name":"",
"nickName":"",
"age":"17",
"retireAge":66
}錯(cuò)誤信息
{
"code": 500,
"msg": "數(shù)據(jù)校驗(yàn)出現(xiàn)問(wèn)題",
"data": {
"retireAge": "年齡上限不能超過(guò)60歲",
"age": "年齡下限不能低于18歲"
}
}自定義校驗(yàn)
編寫(xiě)自定義的校驗(yàn)注解
比如要?jiǎng)?chuàng)建一個(gè):@ListValue 注解,被標(biāo)注的字段值只能是:0或1
@Documented
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
// 使用該屬性去Validation.properties中取
String message() default "{com.atguigu.common.valid.ListValue.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
int[] value() default {};
}設(shè)置錯(cuò)誤信息:創(chuàng)建文件ValidationMessages.properties
com.firefly.common.valid.ListValue.message=必須提交指定的值 [0,1]
編寫(xiě)自定義的校驗(yàn)器
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.Set;
/**
* @author Michale @EMail:firefly@163.com
* @Date: 2022/1/8 19:23
* @Name ListValueConstraintValidator
* @Description:
*/
public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {
private Set<Integer> set = new HashSet<>();
@Override
public void initialize(ListValue constraintAnnotation) {
//獲取注解允許的值
int[] value = constraintAnnotation.value();
for (int i : value) {
set.add(i);
}
}
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
//判斷傳入的值是否在滿足允許的值
boolean b = set.contains(value);
return b;
}
}關(guān)聯(lián)校驗(yàn)器和校驗(yàn)注解
在@ListValue注解關(guān)聯(lián)校驗(yàn)器
@Constraint(validatedBy = { ListValueConstraintValidator.class})
一個(gè)校驗(yàn)注解可以匹配多個(gè)校驗(yàn)器
添加自定義的校驗(yàn)注解
@ListValue(value = {0,1},groups = {AgeGroup.class,MyJRS303Group.class})
private Integer gender;測(cè)試自定義校驗(yàn)器:http://localhost:8080/testGroup
{
"gender":"3"
}{
"code": 500,
"msg": "數(shù)據(jù)校驗(yàn)出現(xiàn)問(wèn)題",
"data": {
"gender": "必須提交指定的值 [0,1]"
}
}以上就是Java利用自定義注解實(shí)現(xiàn)數(shù)據(jù)校驗(yàn)的詳細(xì)內(nèi)容,更多關(guān)于Java數(shù)據(jù)校驗(yàn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java高級(jí)之HashMap中的entrySet()方法使用
這篇文章主要介紹了Java高級(jí)之HashMap中的entrySet()方法使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
Java+swing+Mysql實(shí)現(xiàn)商品銷(xiāo)售管理系統(tǒng)
基礎(chǔ)扎不扎實(shí)只有在實(shí)戰(zhàn)中才能顯現(xiàn),本篇文章手把手帶你用Java+swing+Mysql實(shí)現(xiàn)商品銷(xiāo)售管理系統(tǒng),大家可以在過(guò)程中查缺補(bǔ)漏,提升水平2022-01-01
java實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06
jdk中String類設(shè)計(jì)成final的原由
為什么jdk中把 String 類設(shè)計(jì)成final,主要是為了“ 效率 ”和“安全性”的緣故,若 String 允許被繼承, 由于它的高度被使用率, 可能會(huì)降低程序的性能,所以String被定義成final,需要了解的朋友可以參考下2013-01-01
Sprigmvc項(xiàng)目轉(zhuǎn)為springboot的方法
本篇文章主要介紹了Sprigmvc項(xiàng)目轉(zhuǎn)為springboot的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-02-02
java使用RestTemplate封裝post請(qǐng)求方式
這篇文章主要介紹了java使用RestTemplate封裝post請(qǐng)求方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10

