现象:
自定义注解使用
方法:
1:元注解
java.lang.annotation 下定义了元注解
- @Documented 文档相关 标注了此注解则会包含在javadoc文档中
- @Retention 指定注解生命周期
- @Target 指定注解作用范围
- @Inherited 指定子类可以继承父类的注解
- @Native 指定字段是常量
- @Repeatable 指定在一个地方可以重复使用同一个注解
2:元注解 @Retention 生命周期
- SOURCE: 只保留在源文件
- CLASS: 保留到class文件
- RUNTIME: 运行时也存在
3:元注解 @Target 作用范围
- TYPE——接口、类、枚举、注解
- FIELD——字段、枚举的常量
- METHOD——方法
- PARAMETER——方法参数
- CONSTRUCTOR ——构造函数
- LOCAL_VARIABLE——局部变量
- ANNOTATION_TYPE——注解
- PACKAGE——包,用于记录java文件的package信息
4:新建java类选择注解@Annitation
5:示例建立MyAnnitation注解
6:使用:
二:实例使用:
需求:自定义注解校验请求参数只能是指定值
比如 请求接口 type 参数 只能是"1"、“2”、“3”
方法:
1:引入validation校验jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
2:建立自定义注解
自定义注解范围 :字段、枚举的常量、方法参数
使用@Constraint 指定校验逻辑的类
@Target({ElementType.PARAMETER,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = EnumRangeValidator.class)
public @interface CheckEnum {
// 校验能输入的值
String[] rang();
// 错误提示
String message() default "输入的内容不在规定范围";
// 名称固定参数:校验分组信息
Class<?>[] groups() default {};
// 名称固定参数:加载的负载
Class<? extends Payload>[] payload() default {};
}
3:建立校验逻辑的类EnumRangeValidator
public class EnumRangeValidator implements ConstraintValidator<CheckEnum,String> {
private String[] range;
@Override
public void initialize(CheckEnum constraintAnnotation) {
// 初始化将注解中的枚举内容放数组range
range=constraintAnnotation.rang();
}
@Override
public boolean isValid(String request, ConstraintValidatorContext constraintValidatorContext) {
// 判断输入的值在不在 注解设置的范围
if(StringUtils.isNotBlank(request)){
if(range!=null && range.length>0){
return Arrays.asList(range).contains(request);
}
}
return false;
}
}
4:全局异常监听控制返回
这里简单返回String 实际开发中应该定义全局返回对象
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler<T> {
@ResponseBody
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler({MethodArgumentNotValidException.class})
private String argumentsNotValid(MethodArgumentNotValidException e) {
try {
var fieldError = e.getBindingResult().getFieldError();
var defaultMessage = fieldError.getDefaultMessage();
log.error("参数校验不通过 ", e);
return defaultMessage;
} catch (NullPointerException exception) {
log.error("fieldError 为空", e);
return "参数异常";
}
}
@ResponseBody
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(ConstraintViolationException.class)
private String multiArgumentNotValid(ConstraintViolationException e) {
var constraintViolations = e.getConstraintViolations();
var reduce =
constraintViolations.stream()
.map(ConstraintViolation::getMessage)
.reduce((x, y) -> x + " " + y)
.orElse("");
log.error("参数校验不通过 ", e);
return reduce;
}
}
5:请求入参对象EnumValidRequest
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EnumValidRequest {
/**
* @NotBlank 不能为空校验
*/
@NotBlank(message = "id不能为空!")
private String id;
private String name;
/**
* 设置类型 值只能是1、2、3
* 使用自定义枚举校验 类型只能传值1、2、3
*/
@CheckEnum(rang = {"1","2","3"})
private String type;
}
6:请求接口test/check/enum
使用定义的EnumValidRequest 作为参数
@Slf4j
@RestController
@RequestMapping("/test")
@Validated
public class RequestController {
@PostMapping("/check/enum")
public String getA(@Valid @RequestBody EnumValidRequest request){
log.debug("a请求执行:{}",request);
return "A";
}
}
7:启动项目 访问接口test/check/enum
- 输入的type不在范围时返回:
- 不传id时返回:
- 正常参数访问返回: