• 自定义注解实战


    自定义注解实战

    Java注解又称Java标注,是Java语言5.0版本开始支持加入源代码的特殊语法元数据
    Java注解为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便的使用这些数据。
    Java语言中的类、方法、变量、参数和包等都可以被标注。和Javadoc不同,Java标注可以通过反射获取注解内容。在编译器生成类文件时,注解可以被嵌入到字节码中。Java虚拟机可以保留注解内容,在运行时可以获取到注解内容。

    Java注解概述

    jdk1.5版本内置了三种标准的注解:

    @Override,表示当前的方法定义将覆盖超类中的方法。
    @Deprecated,表示注解的代码是不赞成使用的代码(即将被弃用的代码)
    @SuppressWarnings,告诉编译器忽略指定的警告,不用在编译完成后出现警告信息

    同时Java还提供了4种注解用于新注解的创建:

    @Target:用于说明注解修饰的范围。

    可以在以下范围内选择一个。

    ElementType.METHOD:方法声明
    ElementType.TYPE:类、接口(包括注解类型)或enum声明
    ElementType.CONSTRUCTOR:构造器的声明
    ElementType.FIELD:域声明(包括enum实例)
    ElementType.LOCAL_VARIABLE:局部变量声明
    ElementType.PACKAGE:包声明
    ElementType.PARAMETER:参数声明

    @Retention:表示需要在什么级别保存该注解信息

    RetentionPolicy.RUNTIME:运行期间保留注解,可以通过反射机制读取注解信息
    RetentionPolicy.SOURCE:注解将被编译器丢弃
    RetentionPolicy.CLASS:注解在class文件中可用,但会被VM丢弃

    @Document:表示将注解包含在Javadoc中
    @Inherited:允许子类继承父类中的注解,默认不能被子类继承

    如何自定义注解

    自定义注解很简单,只需要将上面元注解使用好即可。
    以我们这次项目中的自定义注解为例:

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

    分析一下这个注解。
    @Target(ElementType.PARAMETER) 表示该注解是使用范围是参数
    @Retention(RetentionPolicy.RUNTIME) 表示运行期间保留注解,并且可以通过反射机制读取注解信息

    这两个注解加在一起表示,@CurrentUser 这个注解是用来标注参数的,它在运行时还能获取到注解信息。


    ## 自定义注解实战 如果只是单纯地写一个注解,这个注解就没有任何实际价值。我们需要通过处理这个注解来达到我们想要的结果, 项目需求是希望通过@CurrentUser注解获取当前登录用户的userId。 我们会怎么做呢?下面是我们处理的逻辑图: ![自定义注解原理图](https://img2018.cnblogs.com/blog/1704418/201909/1704418-20190917175503071-557018069.png)

    按照步骤拆分自定义注解的使用:

    第一步,自定义注解。
    第二步,继承HandlerMethodArgumentResolver,实现数据绑定。

    spring调用HandlerMethodArgumentResolver实现Controller的参数装配。HandlerMethodArgumentResolver实现类中会调用DataBinder,Converter等。常用的该接口实现类有:
    ServletModelAttributeMethodProcessor: 实体类的组装用它实现。
    RequestParamMethodArgumentResolver: 基本数据类型如String用它实现。

    RequestParamMethodArgumentResolver接口定义了实现类必须实现supportsParameterresolveArgument这两个方法。
    第一个方法表示这个方法的参数是否支持这个解析器,第二个方法将方法参数解析为来自给定请求的参数值。

    自定义解析器都需要实现这个接口,下面是我们在项目中的实现类:

    public class UserModelResolver<T> implements HandlerMethodArgumentResolver {
    
      public static final String REQUEST_USERID = "x-erp-auth-id";
    
    
      @Override
      public boolean supportsParameter(MethodParameter parameter) {
        //如果有CurrentUser注解则支持
        return parameter.hasParameterAnnotation(CurrentUser.class);
      }
    
      @Override
      public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
          NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
    
        Integer userId = 0;
        //取出鉴权网关存入的登录用户Id,内部服务调显示赋值userId
        String headerData = webRequest.getHeader(REQUEST_USERID);
        if (!Strings.isNullOrEmpty(headerData)) {
          try {
            userId = Integer.parseInt((String) headerData);
          } catch (NumberFormatException nfe) {
            userId = 0;
          }
        }
        return userId;
      }
    }
    
    第三步,在方法中使用,代码如下
      @GetMapping("/listDevices")
        public BaseReturnVO listShopDevice(@CurrentUser Integer userId, @Valid @NotNull(message = "shopPublicId为空") Integer shopPublicId){
            ...
        }
    
    

    是不是很简单实用?


    ### The End
  • 相关阅读:
    北京大学计算机系2009应试硕士生上机考试(DF)
    我的考研2010(一)
    这张容易看懂...
    关于招商银行信用卡的若干事宜
    20 years
    C/C++中关于qsort的使用
    有道破题~~
    POJ 4010 2011
    有道难题练习赛 Sibonacci
    北京大学计算机系2009应试硕士生上机考试(AC)
  • 原文地址:https://www.cnblogs.com/catlkb/p/11535844.html
Copyright © 2020-2023  润新知