Forest Forest
首页
  • 当前版本

    • v1.6.x
  • 历史版本

    • v1.5.36
    • v1.5.35
    • v1.5.33
    • v1.5.30 ~ v1.5.32
    • v1.5.0 ~ v1.5.28
  • 插件

    • ForestX
  • 问答

    • 常见问题
    • 更新记录
案例
  • 加入群聊
  • 赞助我们
  • 参与贡献
  • 贡献者们
  • 项目介绍
  • 开发团队
  • 关于作者
  • MaxKey - 业界领先的身份管理和认证产品 (opens new window)
  • Snowy - 国内首个国密前后端分离快速开发平台 (opens new window)
  • Eoapi - 一个开源、可拓展的 API 工具平台 (opens new window)
  • Fast Request - IDEA版Postman,为简化API调试而生 (opens new window)
  • Bean Searcher - 专注高级查询的只读 ORM (opens new window)
  • zyplayer-doc - 可私有化部署的文档与知识库管理平台 (opens new window)
  • frSimple - 中后台脚手架/小程序商城 (opens new window)
  • Gitee (opens new window)
  • Github (opens new window)
  • GitCode (opens new window)
首页
  • 当前版本

    • v1.6.x
  • 历史版本

    • v1.5.36
    • v1.5.35
    • v1.5.33
    • v1.5.30 ~ v1.5.32
    • v1.5.0 ~ v1.5.28
  • 插件

    • ForestX
  • 问答

    • 常见问题
    • 更新记录
案例
  • 加入群聊
  • 赞助我们
  • 参与贡献
  • 贡献者们
  • 项目介绍
  • 开发团队
  • 关于作者
  • MaxKey - 业界领先的身份管理和认证产品 (opens new window)
  • Snowy - 国内首个国密前后端分离快速开发平台 (opens new window)
  • Eoapi - 一个开源、可拓展的 API 工具平台 (opens new window)
  • Fast Request - IDEA版Postman,为简化API调试而生 (opens new window)
  • Bean Searcher - 专注高级查询的只读 ORM (opens new window)
  • zyplayer-doc - 可私有化部署的文档与知识库管理平台 (opens new window)
  • frSimple - 中后台脚手架/小程序商城 (opens new window)
  • Gitee (opens new window)
  • Github (opens new window)
  • GitCode (opens new window)
  • 序言

    • 🎁 新手介绍
    • 📖 文档
    • 🌰 使用案例
    • 🕵️‍ 关于作者
    • 👨‍🎓 贡献者列表
  • 入门

    • 🎬 安装配置说明
    • 🏹 Springboot环境安装
    • 📐 Springboot环境配置
    • 🎯 Springboot环境使用
    • 🏹 Springboot3环境安装
    • 📐 Springboot3环境配置
    • 🎯 Springboot3环境使用
    • 🏹 Spring环境安装
    • 📐 Spring环境配置
    • 🎯 Spring环境使用
    • 🏹 Solon环境安装
    • 📐 Solon环境配置
    • 🎯 Solon环境使用
    • 🏹 原生Java环境安装
    • 📐 原生Java环境配置
    • 🎯 原生Java环境使用
    • 🧬 编程式接口
  • 配置项

    • 👜 Springboot环境配置项
    • 👝 Spring环境配置项
    • 👜 Solon环境配置项
    • 🎒 原生Java环境配置项
    • 📚 配置优先级/作用域
  • 声明式接口

    • 🧱 构建接口
    • 🍀 请求方法
    • 🚚 请求地址
    • 🎈 URL 参数
    • 🍭 请求头
    • 👔 请求体
    • 🍮 后端框架
    • 🧁 接口注解
    • 📬 接收数据
    • 🍛 数据转换
    • 🍓 成功/失败条件
    • 🍌 重试机制
    • 🥂 重定向
    • 🍔 Gzip解压
    • 🎂 日志管理
    • ⚽ 回调函数
    • 🍟 异步请求
    • 🛡️ HTTPS
    • 🍪 使用Cookie
    • 🛸 使用代理
    • 🍉 上传下载
    • 🚑 异常处理
  • 编程式接口

    • 请求API

      • 🚀 请求对象
      • 🚢 请求属性
      • ✨ 执行请求
      • 🎊 后端框架
      • 🎪 请求类型
      • 🔮 请求地址
      • 🧀 URL 参数
      • 🚅 请求头
      • 🚋 请求体
      • ⚓ 回调函数
      • 🚁 异步请求
      • 🥯 Cookie
      • 🍜 成功/失败条件
      • 🌶️ 重试机制
      • ⛵ 重定向
      • 🛰️ 请求代理
    • 响应API

      • 🌠 响应对象
      • ✒️ 读取数据
      • 🦋 响应状态码
      • 🏥 响应错误处理
      • 🎧 响应头
      • 🥞 Cookie
  • 模板表达式

    • 🍬 Hello World
    • 🍹 配置属性引用
    • 🍖 变量引用
    • 🥃 动态变量绑定
    • 🥗 参数序号引用
    • 🍍 引用对象属性
    • 🥝 调用对象方法
  • 高级特性

    • 🥪 拦截器
    • 🍏 自定义注解
    • 🍇 组合注解
      • 🥑 自定义转换器
    • v1.5.33文档
    • 高级特性
    公子骏
    2022-07-01
    目录

    🍇 组合注解

    Forest 除了能用生命周期来自定义注解外,也允许您把已有的 Forest 注解组合成一个新的注解

    # 组合一个注解

    /**
     * 用Forest组合注解实现一个自定义的请求头注解
     * 此注解加上了 @Headers 注解,并为注解的参数赋了值
     * 那么以后使用此注解的接口和方法,会自动添加上 @Headers 注解以及它的参数值
     */
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD, ElementType.TYPE})
    // 被组合的注解
    @Headers({
            "Accept: text/plain",
            "Content-Type: application/json",
            // 在组合注解中可以在模板字符串中引用变量
            // 它会从全局变量或方法的参数中获取变量值
            "Token: ${token}"
    })
    public @interface MyHeaders {
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    使用组合注解的方法

    // 该方法使用了自定义的组合注解 @MyHeaders
    // 所以该方法发送的请求会自动添加以下请求头:
    // Accept: text/plain
    // Content-Type: application/json
    // Token: xxx (从形参 token 中传入的值)
    @Get("/data")
    @MyHeaders
    String getData(@Var("token") String token);
    
    1
    2
    3
    4
    5
    6
    7
    8

    注意

    组合注解目前无法在字符串模板中引用自身的注解属性

    如需要定义和解析注解的属性,请使用《自定义注解》

    # 组合多个注解

    Forest 还可以组合2个及2个以上的 Forest 注解

    /**
     * Forest 可以同时组合多个注解
     * 如方法使用该自定义的 @MySite 注解
     * 那么就等同使用这里被组合的 @Headers 注解和 @Address 注解
     * 以及它们的参数值
     */
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD, ElementType.TYPE})
    // 组合第一个注解
    @Headers({
            "Accept: text/plain",
            "Content-Type: application/json"
    })
    // 组合第二个注解
    // 可以从全局变量或方法参数中获取变量值
    @Address(host = "${my-site.host}", port = "${my-site.port}")
    public @interface MySite {
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    注意

    定义组合注解的时候要注解不要组合自身,以及组合过自身的其它注解,以免引起循环引用

    # 属性重写

    注解的组合关系,类似于 Java 类的继承关系,继承关系中有多态(比如方式和属性的重写), Forest 的组合注解也有类似的能力

    从v1.5.33版本开始,Forest 提供了@OverrideAttribute注解,将被该注解标识的注解属性定义可重写的注解属性,它将覆盖被组合注解中的同名属性值

    要重写组合注解的属性,要满足以下三个条件:

    1. 注解定义时,要加上@@RequestAttributes注解,以标识该注解的属性可以被解析

    2. 属性名要和被组合的注解中的属性名一致

    3. 属性定义上要加上@OverrideAttribute注解

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD, ElementType.TYPE})
    // 加上 @RequestAttributes 注解才能解析注解中定义的属性
    @RequestAttributes
    // 被组合的 @Address 注解
    @Address
    public @interface MySite {
        
        // 重写 @Address 注解的 host 属性
        @OverrideAttribute
        String host();
        
        // 重写 @Address 注解的 port 属性
        @OverrideAttribute
        int port();
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    此时,使用@MySite,并为其 host 属性和 port 属性赋值时,将会自动覆盖被组合的@Address注解的 host 属性和 port 属性

    // 等价于 @Address(host = "localhost", port = 8080)
    @MySite(host = "localhost", port = 8080)
    public interface MyClient {
        ...
    }
    
    1
    2
    3
    4
    5
    帮助我们改善此文档 (opens new window)
    上次更新: 2024/12/26, 12:59:11
    🍏 自定义注解
    🥑 自定义转换器

    ← 🍏 自定义注解 🥑 自定义转换器→

    Theme by Vdoing | Copyright © 2016-2025 公子骏 | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式