美文网首页
Java注解之实战

Java注解之实战

作者: Good龙辉 | 来源:发表于2020-12-07 00:47 被阅读0次

一、什么是注解

  • Java 注解是在 JDK5 时引入的新特性,注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个阶段方便的使用这些数据。

二、JDK常用注解、元注解

常用注解如下

  • @Override: 表示注解修饰的方法必须满足重写的规则
  • @Deprecated: 表示成员过时,编译器可以在程序运行的时候获取到该注解
  • @SupressWarnings: 表示忽略编译器的警告
    常见的元注解:
  • @Target 可声明在哪些目标元素之前
 ElementType.PARAMETER               声明在参数上
 ElementType.METHOD                  声明在方法上
 ElementType.FIELD                   声明在字段上
 ElementType.TYPE                    声明在类,接口,枚举
 ElementType.CONSTRUCTOR             声明在构造函数
 ElementType.LOCAL_VARIABLE          局部变量
 ElementType.ANNOTATION_TYPE         注释类型声明
 ElementType.PACKAGE                 包声明
  • @Retention 注解类的生命周期,及作用在哪个阶段
RetentionPolicy.RUNTIME   程序运行时期起作用
RetentionPolicy.SOURCE    在原文件中有效,被编译器丢弃
RetentionPolicy.CLASS     程序编译时期起作用
  • @Documented 生成文档的时候,会被写入到文档中

三、如何使用注解

那么注解是怎么在某个阶段被方便的使用呢,比如我们自定义一个注解,程序是如何使用的呢?其实注解不能自己起作用,需要程序员自身去针对注解写专门的逻辑,比如:日志切面针对日志注解进行扫描处理;登录注解使用拦截器去判断是否包含再处理登录逻辑。

四、注解实战

接下来介绍下注解在实际中的使用,本次介绍的demo是一个利用注解来实现动态参数校验功能。
1、首先新建一个验证注解,用于切入点进行参数校验。

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ValidParam {
}

2、其次编写实现此注解的扫描,对含有此注解的方法参数进行校验。这里我们用到了SpringMVC中的参数解析器,RequestBody注解的操作类继承了AbstractMessageConverterMethodArgumentResolver,因此我们也使用此类实现RequestBody相同参数解析功能。

@Slf4j
public class ValidMethodArgumentResolver extends AbstractMessageConverterMethodArgumentResolver {
    private static Validator validator;

    static {    
        validator = Validation.buildDefaultValidatorFactory().getValidator();
    }

    public ValidMethodArgumentResolver(List<HttpMessageConverter<?>> converters, List<Object> requestResponseBodyAdvice){
        super(converters, requestResponseBodyAdvice);
    }


    public ValidMethodArgumentResolver(List<HttpMessageConverter<?>> converters) {
        super(converters);
    }

    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return methodParameter.hasParameterAnnotation(ValidParam.class);
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        final Object object = readWithMessageConverters(nativeWebRequest, methodParameter, methodParameter.getParameterType());
        validateParam(object);
        return object;
    }

    /**
     * 参数校验
     * @param object
     */
    private void validateParam(Object object) {
        Set<ConstraintViolation<Object>> constraintViolations;
        if(object instanceof List){
            List list = (List)object;
            list.forEach(p -> validateParam(p));
        }else {
            constraintViolations = validator.validate(object);
            if (!constraintViolations.isEmpty()) {
                ConstraintViolation<Object> constraint = (ConstraintViolation<Object>)constraintViolations.iterator().next();
                throw new ParamException(GloabEnums.PARAM_ERROR.getCode(), constraint.getMessage());
            }
        }
    }
}

使用之后我们需要将此类配置到参数解析器中,及实现WebMvcConfigurer类中,具体代码如下:

 @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> list) {
        List<HttpMessageConverter<?>> converters = new ArrayList<>();
        converters.add(new MappingJackson2HttpMessageConverter());
        list.add(new ValidMethodArgumentResolver(converters));
    }

首先是实现HandlerMethodArgumentResolver方法的supportsParameter方法,用于判断是否包含自定义验证注解,其次包含则调用resolveArgument方法对参数进行处理验证;这里我们使用了validator验证工具包进行校验。
3、接下来我们对入参实体进行校验验证,这里我们使用了NotB

@Data
public class UserDto {
    @NotBlank(message = "名字不能为空")
    private String name;
    @NotBlank(message = "电话号码为空")
    @Pattern(regexp = "^1(?:3\\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\\d|9\\d)\\d{8}$", message = "电话号码有误")
    private String phone;
    private int age;
}
@Slf4j
@RestController
@RequestMapping("valid")
public class ValidController {

    @PostMapping("user")
    public R insertAddress(@ValidParam UserDto dto){
        log.info("参数验证成功,执行正常逻辑:{}", dto);
        return R.ok();
    }
}

调用该接口:


image.png

有人会问,当我们使用增、删、改需要使用同一个类,如用如上参数注解校验,则会引起新增的方法判断了修改方法的校验,我们不同的方法是需要对此类不同的字段进行校验,这不是要写多个类才能进行校验吗?
既然有不同的需求,我们就有不同的方案来进行处理,这里我们引入group组这个概念,将字段划分组进行区分校验。

public interface QueryGroup {}

public @interface ValidParam {
    Class value() default QueryGroup.class;
}

@NotBlank(message = "名字不能为空", groups = QueryGroup.class)
    private String name;

@PostMapping("user")
    public R insertAddress(@ValidParam(value = QueryGroup.class) UserDto dto){
        log.info("参数验证成功,执行正常逻辑:{}", dto);
        return R.ok();
    }

/**
     * 参数校验
     * @param object
     */
    private void validateParam(Object object, Class<?>... groups) {
        Set<ConstraintViolation<Object>> constraintViolations;
        if(object instanceof List){
            List list = (List)object;
            list.forEach(p -> validateParam(p, groups));
        }else {
            constraintViolations = validator.validate(object, groups);
            if (!constraintViolations.isEmpty()) {
                ConstraintViolation<Object> constraint = (ConstraintViolation<Object>)constraintViolations.iterator().next();
                throw new ParamException(GloabEnums.PARAM_ERROR.getCode(), constraint.getMessage());
            }
        }
    }

四、总结

1、注解就是对代码的解释,可以把它类同于标签
2、注解的定义只是interface前加了个@
3、注解不会自己起作用,需要程序开发人员去开发对应的功能

相关文章

  • java——注解(实战)

    项目说明: 项目取自一个公司的持久层架构,用来代替Hibernate的解决方案,核心代码就是通过注解来实现的。 需...

  • Java——注解(Annotation)入门学习

    学习资料: Java编程思想 ——第20章 公共技术点之 Java 注解 Annotation 注解(Annota...

  • Spring注解原理探索(三)

    之 Java如何识别注解 关键词:Java 反射java.lang.reflect 包,实现反射功能的工具类。注解...

  • Spring注解原理探索(一)

    之 Java元注解释义 Question 注解在Java中如何起作用? Spring是如何识别注解? 如何自定义注...

  • 读书笔记

    《系统之美》 《重构》 《Redis 实战》 《Effective Java》 《Spring Boot实战》 《...

  • Java注解之实战

    一、什么是注解 Java 注解是在 JDK5 时引入的新特性,注解(也被称为元数据)为我们在代码中添加信息提供了一...

  • Android & Java 注解和自定义注解处理器

    写在前面:本文是实际工作中学习成果,记为笔记 目录 背景 什么是注解 注解实战:动态注解 注解实战:静态注解 注解...

  • java注解详解(注解项目实战)

    定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类...

  • Java注解详解「注解项目实战」

    定义: 注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与...

  • 干货系列之java注解

    干货系列之java注解 前言 java反射和注解在java里面很重要,但是很多人对这方面的知识理解不是很好,我来说...

网友评论

      本文标题:Java注解之实战

      本文链接:https://www.haomeiwen.com/subject/fpuawktx.html