• Java自定义注解


    Java自定义注解

    Java自定义注解一般使用场景为:自定义注解+拦截器或者AOP配合使用,可以用来设计自己的框架,也可以用于开发中的权限校验

    一、什么是注解(Annotation)

    Java注解是什么,以下是引用自维基百科的内容

    Java注解又称Java标注,是JDK5.0版本开始支持加入源代码的特殊语法元数据。ava语言中的类、方法、变量、参数和包等都可以被标注。和Javadoc不同,Java标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java虚拟机可以保留标注内容,在运行时可以获取到标注内容。 当然它也支持自定义Java标注。

    二、注解体系图

    元注解:java.lang.annotation中提供了元注解,可以使用这些注解来定义自己的注解。主要使用的是Target和Retention注解

    可以通过java.lang.reflect.AnnotationElement接口来获取,注解的获取都是通过反射来处理的。如下反射相关的类都实现了AnnotationElement接口

    反射处理:

    AnnotationElement接口方法:

    因此,只要我们通过反射拿到Class, Method, Field类,就能够通过getAnnotation(Class)拿到我们想要的注解并取值。

    三、常用元注解

    Target:描述了注解修饰的对象范围,取值在java.lang.annotation.ElementType定义,常用包括:

    • METHOD:用于描述方法

    • PACKAGE:用于描述包

    • PARAMETER:用于描述方法变量

    • TYPE:用于描述类、接口或enum类型

    Retention:表述注解保留时间的长短,取值在java.lang.annotation.RetentionPolicy中,取值:

    • SOURCE:在源文件中有效,编译过程中会被忽略
    • CLASS:随源文件一起编译在class文件中,运行时忽略
    • RUNTIME:在运行时有效

    只有定义为RetentionPolicy.RUNTIME时,我们才能通过注解反射获取注解

    四、注解属性定义

    注解属性 ( 接口方法 ) 返回值类型要求 :

    • 基本数据类型 : byte , short , int , long , float , double , char , boolean ;

    • 字符串类型 : String ;

    • 枚举类型 : enum ;

    • 注解类型 ;

    • 以上类型的数组形式 ;

    可以使用default来进行赋默认值

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface AdminLoginToken {
        @AliasFor("admin")
        boolean value() default true;
    
        @AliasFor("value")
        boolean admin() default true;
    }
    

    四、示例-反射获取注解

    定义一个注解:

    @Target(ElementType.FIELD)//只能定义在字段上
    @Retention(RetentionPolicy.RUNTIME)//在运行时有效
    public @interface MyAnnotation {
        //字段描述
        String description();
        //字段长度
        int length();
    }
    

    注解的使用:

    @Data
    public class User {
        @MyAnnotation(length = 12,description = "用户名的长度只能为12位")
        private String userName;
    }
    

    通过反射获取到注解:

    public void test1(){
        User user = new User();
        user.setUserName("张三");
    
        //获取类模板
        Class<User> userClass = User.class;
    
        //获取所有字段
        Field[] declaredFields = userClass.getDeclaredFields();
        for (Field field : declaredFields) {
            //判断该字段是否存在MyAnnotation注解
            if(field.isAnnotationPresent(MyAnnotation.class)){
                MyAnnotation myAnnotation = field.getAnnotation(MyAnnotation.class);
                System.out.println("字段:["+field.getName()+"],描述:["+myAnnotation.description()+"],长度:["+myAnnotation.length()+"]");
                }
            }
        }
    

    运行结果

    应用场景一:基于Spring的自定义注解+拦截器 实现登录权限校验

    我们在实际开发中,可以使用这种方式来进行是否需要进行登录校验;如果方法中加上了@LoginRequired注解表示方法需要登录校验,如果没加则不需要。

    定义一个@LoginRequired注解

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public@interface LoginRequired {
        
    }
    
    

    定义两个简单接口,其中一个添加@LoginRequired注解表示需要登录校验

    @RestController
    public class UserController {
    
        @GetMapping("/login1")
        public TransDTO login1(){
            return new TransDTO<>().withMessage("访问login1成功").withCode(HttpStatus.OK.value());
        }
        
        @LoginRequired
        @GetMapping("/login2")
        public TransDTO login2(){
            return new TransDTO<>().withMessage("访问login2成功").withCode(HttpStatus.OK.value());
        }
    }
    
    

    自定义拦截器

    @Configuration
    public class MyInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("访问了过滤器!");
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            LoginRequired annotation = handlerMethod.getMethod().getAnnotation(LoginRequired.class);
            if(annotation != null){
                //全局异常处理会进行处理
                throw new BusinessException("访问失败,您没有权限访问!");
            }
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
        }
    }
    

    配置拦截路径

    @Configuration
    public class InterceptorTrainConfigurer implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
        }
    }
    

    全局异常处理

    @RestControllerAdvice
    public class MyExceptionAdvice {
        @ExceptionHandler(Exception.class)
        @ResponseStatus(HttpStatus.OK)
        public TransDTO handleException(HttpServletRequest request,Exception e){
            e.printStackTrace();
            return new TransDTO().withCode(500).withSuccess(false).withMessage(e.getMessage());
        }
    }
    

    基本交互对象

    @Data
    public class TransDTO<T> {
    
        private Boolean success = true;
        private T data;
        private String message;
        private int code;
    
        public TransDTO() {
        }
    
        public int getCode() {
            return this.code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public TransDTO<T> withCode(int code) {
            this.code = code;
            return this;
        }
    
        public Boolean getSuccess() {
            return this.success;
        }
    
        public void setSuccess(Boolean success) {
            this.success = success;
        }
    
        public T getData() {
            return this.data;
        }
    
        public void setData(T data) {
            this.data = data;
        }
    
        public String getMessage() {
            return this.message;
        }
    
        public void setMessage(String message) {
            this.message = message;
        }
    
        public TransDTO<T> withSuccess(Boolean success) {
            this.success = success;
            return this;
        }
    
        public TransDTO<T> withMessage(String message) {
            this.message = message;
            return this;
        }
    
        public TransDTO<T> withData(T data) {
            this.data = data;
            return this;
        }
    }
    

    访问结果


    我们还能使用自定义注解+AOP进行权限的控制,为了保证博客长度,可以访问自定义注解+AOP实现权限控制

  • 相关阅读:
    我的利器
    老树新芽——矩估计遇到神经网络
    QuantLib 金融计算——数学工具之随机数发生器
    《Implementing QuantLib》译后记
    c# 大批量用户访问数据库报错
    阿里云redis映射到阿里云服务器
    C# 输出字符串到文本文件中
    SQL Server 怎么在分页获取数据的同时获取到总记录数
    C# 当前 .NET SDK 不支持将 .NET Core 2.1 设置为目标。请将 .NET Core 2.0 或更低版本设置为目标,或使用支持 .NET Core 2.1 的 .NET SDK 版本。
    c# 项目之间循环引用vs弹窗提醒
  • 原文地址:https://www.cnblogs.com/codeli/p/14944639.html
Copyright © 2020-2023  润新知