註解原理與自定義註解
1、引入依賴:
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
2、定義註解@JachinLength
利用該註解驗證某字符串屬性長度必須爲指定長度
package com.jachin.zhujie;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = LengthValidatorClass.class) // 指定驗證類
public @interface JachinLength {
int length() default 11; // 允許字符串長度
String message() default "kkkkk"; // 自定義的錯誤提示信息
// 下面這兩個必須有
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
下面做幾點說明:
1、註解的定義有點像定義接口 interface
,但唯一不同的是前面需要加一個 @
符號
2、註解的成員變量只能使用基本類型、 String
或者 enum
枚舉,比如 int
可以,但 Integer
這種包裝類型就不行。
3、像上面 @Target
、 @Retention
這種加在註解定義上面的註解,稱爲 “元註解”,元註解就是專門用於給註解添加註解的註解
4、 @Target(xxx)
用來說明該自定義註解可以用在什麼位置,比如:
ElementType.FIELD
:說明自定義的註解可以用於類的變量ElementType.METHOD
:說明自定義的註解可以用於類的方法ElementType.TYPE
:說明自定義的註解可以用於類本身、接口或enum
類型
5、 @Retention(xxx)
用來說明你自定義註解的生命週期,比如:
@Retention(RetentionPolicy.RUNTIME)
:表示註解可以一直保留到運行時,因此可以通過反射獲取註解信息@Retention(RetentionPolicy.CLASS)
:表示註解被編譯器編譯進class
文件,但運行時會忽略@Retention(RetentionPolicy.SOURCE)
:表示註解僅在源文件中有效,編譯時就會被忽略
所以聲明週期從長到短分別爲:RUNTIME > CLASS > SOURCE
6、@Constraint:指定驗證屬性的類。
-
message()指明瞭驗證失敗後返回的消息,此方法爲@Constraint要求
-
groups()和payload()也爲@Constraint要求,可默認爲空,詳細用途可以查看@Constraint文檔
3、實現驗證類LengthValidatorClass
package com.jachin.zhujie;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* @description:
* @Author: JachinDo
* @Date: 2020/03/09 11:55
*/
public class LengthValidatorClass implements ConstraintValidator<JachinLength, String> { // 第一個參數是註解類,第二個註解是作用的對象類型
private JachinLength length;
// 將註解提取出來,底層利用反射生成註解的代理類
@Override
public void initialize(JachinLength constraint) {
this.length = constraint;
}
// 驗證邏輯
@Override
public boolean isValid(String obj, ConstraintValidatorContext context) {
return obj.length() != length.length() ? false : true;
}
}
4、實體類與使用controller處驗證字段
實體類:
package com.jachin.zhujie;
import lombok.Data;
/**
* @description:
* @Author: JachinDo
* @Date: 2020/03/09 12:06
*/
@Data
public class Person {
// 之前定義時默認長度爲11
@JachinLength(message = "長度錯誤!")
private String phone;
}
controller:
package com.jachin.zhujie;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
/**
* @description:
* @Author: JachinDo
* @Date: 2020/03/09 13:02
*/
@RestController
@RequestMapping("/anno")
public class TestZhujie {
@PostMapping("/phone")
public String print(@Valid Person person,
BindingResult bindingResult) throws Exception {
if (bindingResult.hasErrors()) {
System.out.println("錯誤 " + person);
throw new Exception(bindingResult.getFieldError().getDefaultMessage());
}
return person.toString();
}
}
結果:
當輸入phone長度不爲11時: