Forest Forest
💒 首页
  • v1.5.30
  • v1.5.28
  • 🎄 ForestX
🌰 案例
💖 支持
🛫 更新记录
🧢 开发团队
⚒️ 参与贡献
  • MaxKey - 业界领先的身份管理和认证产品 (opens new window)
  • Snowy - 国内首个国密前后端分离快速开发平台 (opens new window)
  • Eoapi - 一个开源、可拓展的 API 工具平台 (opens new window)
  • Gitee (opens new window)
  • Github (opens new window)
💒 首页
  • v1.5.30
  • v1.5.28
  • 🎄 ForestX
🌰 案例
💖 支持
🛫 更新记录
🧢 开发团队
⚒️ 参与贡献
  • MaxKey - 业界领先的身份管理和认证产品 (opens new window)
  • Snowy - 国内首个国密前后端分离快速开发平台 (opens new window)
  • Eoapi - 一个开源、可拓展的 API 工具平台 (opens new window)
  • Gitee (opens new window)
  • Github (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
    • 🍹 配置属性引用
    • 🍖 变量引用
    • 🥃 动态变量绑定
      • 静态变量绑定
      • 动态变量绑定
      • @BindingVar注解
    • 🥗 参数序号引用
    • 🍍 引用对象属性
    • 🥝 调用对象方法
  • 高级特性

    • 🥪 拦截器
    • 🍏 自定义注解
    • 🍇 组合注解
    • 🥑 自定义转换器
  • v1.5.30文档
  • 模板表达式
公子骏
2022-07-01
目录

🥃 动态变量绑定

在大部分情况下,变量引用 + 配置文件的方式都可以满足要求,比如:不同环境下配置不同的变量。但如果我想在每次引用变量的时候,都根据某种条件动态获取变量值就办不到了

因此,Forest 在 1.5.3 版本开始,提供了一种动态绑定变量名的技术

# 静态变量绑定

在了解什么是 动态变量绑定 之前,先来了解一下什么是 静态变量绑定

ForestConfiguration对象提供了setVariableValue方法可以动态设置静态绑定的全局变量值

但该方法设置的值为静态的值,即设置完之后该变量就不会该改变了,所有再次调用 setVariableValue 方法覆盖原来的变量值,所以称为变量的 静态绑定。

setVariableValue(String name, Object value) 设置全局变量所对应的值

  • 参数name: 变量名
  • 参数name: 变量值
// 获取 Forest 全局配置对象
ForestConfiguration configuration = Forest.config();
// 设置全局变量: name -> Peter
configuration.setVariableValue("name", "Peter");
// 设置全局变量: baseUrl -> http://abc.com
configuration.setVariableValue("baseUrl", "http://abc.com");
1
2
3
4
5
6

此时就能引用到刚才设置的全局变量名了

@Get("${baseUrl}/data?n={name}")
String getData();

// 调用该方法所产生的URL为
// http://abc.com/data?n=Peter
1
2
3
4
5

# 动态变量绑定

动态变量绑定的概念是相对静态变量绑定而来的,静态绑定的变量是一个固定值,即一旦设置完之后,就不会再做改变,每次引用到同一个变量名的值都是相同的,除非将变量名重新设值,覆盖掉原来的值。

而动态绑定的变量尤其说是变量,其实更接近于函数或者方法,即每次引用一个变量名的时候都会重新计算其变量值,相当于调用一次方法,而它的返回值即为变量名所对应的值。

上面介绍过的ForestConfiguration对象的setVariableValue方法的兄弟方法(重载方法)可以动态设置动态绑定的全局变量值

setVariableValue(String name, ForestVariableValue value)

  • 参数name: 变量名
  • 参数value: 变量值,ForestVariableValue接口的实现类

欸,我们发现,这里的value是一个接口类的实例对象,这个接口本质上可以看成一个Lambda

// 获取 Forest 全局配置对象
ForestConfiguration configuration = Forest.config();
// 定义一个原子整数对象
AtomicInteger count = new AtomicInteger(0);
// 设置全局动态变量: num -> 从0开始记,每次引用加一的值
configuration.setVariableValue("num", (method) -> count.getAndIncrement());
1
2
3
4
5
6

此时就能引用到刚才设置的全局动态变量名了

@Get("/data?num={num}")
String getData();
1
2

然后,多次调用该方法,所产生的结果都是不同的 (每次都累加一)

myClient.getData(); // 第一次调用,URL: http://localhost/data?num=0
myClient.getData(); // 第二次调用,URL: http://localhost/data?num=1
myClient.getData(); // 第三次调用,URL: http://localhost/data?num=2
1
2
3

ForestVariableValue接口的 Lambda 带有一个参数 method, 它是 ForestMethod 类型的对象,即 Forest 接口方法对象

ForestConfiguration configuration = Forest.config();
// 设置全局动态变量: baseUrl -> 根据条件产生不同的IP地址
configuration.setVariableValue("num", (method) -> {
    // method: Forest 接口方法对象,即对请求所对应的方法的封装对象
    // method.getMethodName() 获得请求所对应的方法的方法名
    String methodName = method.getMethodName();
    if (methodName.equals("getData")) {
        // 若调用的是 getData 方法,则返回 192.168.0.2
        return "192.168.0.2";
    }
    // 默认返回 192.168.0.1
    return "192.168.0.1";
});
1
2
3
4
5
6
7
8
9
10
11
12
13

引用该 baseUrl 变量

@Get("{baseUrl}/data")
String getData();

@Get("{baseUrl}/user")
String getUser();
1
2
3
4
5

调用不同方法产生的结果

myClient.getData(); // 调用getData,URL: http://192.168.0.2/data
myClient.getUser(); // 调用getUser,URL: http://192.168.0.1/user
1
2

# @BindingVar注解

还有一种更方便的声名式动态绑定变量的办法,就是在 Spring 环境下利用 @BindingVar 注解修饰某个在 Spring 上下文的 Bean 的方法

@Service("myService")
public class MyService {
    // 定义一个原子整数对象
    private AtomicInteger count = new AtomicInteger(0); 

    /**
     * 使用 @BindingVar 注解
     * 将变量名 num 和一段方法代码绑定
     * 方法的参数可以忽略不定义
     * 每次引用 num 变量,都会调用该方法重算出该值
     */
    @BindingVar("num")
    public int getNum() {
        // 返回原子整数的值,每次调用加一
        return count.getAndIncrement();
    }
    
    /**
     * 使用 @BindingVar 注解
     * 将变量名 baseUrl 和一段方法代码绑定
     * 该方法可以有一个 ForestMethod 类型的参数
     */
    @BindingVar("baseUrl")
    public String getBaseUrl(ForestMethod method) {
        // method: Forest 接口方法对象,即对请求所对应的方法的封装对象
        // method.getMethodName() 获得请求所对应的方法的方法名
        String methodName = method.getMethodName();
        if (methodName.equals("getData")) {
            // 若调用的是 getData 方法,则返回 192.168.0.2
            return "192.168.0.2";
        }
        // 默认返回 192.168.0.1
        return "192.168.0.1";
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

此时就能引用到刚才设置的全局动态变量名了

@Get("{baseUrl}/data?num={num}")
String getData();

@Get("{baseUrl}/user?num={num}")
String getUser();
1
2
3
4
5

然后,多次调用该方法,所产生的结果都是不同的 (每次都累加一)

myClient.getData(); // 第一次调用,URL: http://192.168.0.2/data?num=0
myClient.getData(); // 第二次调用,URL: http://192.168.0.2/data?num=1
myClient.getData(); // 第三次调用,URL: http://192.168.0.2/data?num=2

myClient.getUser(); // 调用另一个方法,URL: http://192.168.0.1/data?num=3
1
2
3
4
5
帮助我们改善此文档 (opens new window)
上次更新: 2023/03/13, 15:28:40
🍖 变量引用
🥗 参数序号引用

← 🍖 变量引用 🥗 参数序号引用→

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