Skip to content

FAQ

This document collects the most common questions and fixes for the Lovrabet Java OpenSDK.


Contents

  • Authentication and authorization
  • Parameters and data
  • Performance
  • Networking
  • Data consistency
  • Development and debugging

Authentication and authorization

Q1: I get "Token invalid" or "signature verification failed"

Possible causes:

  1. The AccessKey is incorrect or expired
  2. The system clock is more than 10 minutes off from the server time
  3. A proxy or middleware is modifying the request in transit

How to fix:

Java
// 1. 验证 AccessKey 是否正确
System.out.println("AccessKey 前 10 位: " + accessKey.substring(0, 10));

// 2. 检查系统时间
System.out.println("当前时间戳: " + System.currentTimeMillis());
System.out.println("当前时间: " + new Date());

// 3. 确认请求参数正确
System.out.println("AppCode: " + request.getAppCode());
System.out.println("ModelCode: " + request.getModelCode());

If your clock is off:

Bash
# Linux/Mac 同步系统时间
sudo ntpdate -u time.apple.com

# 或使用 NTP 服务
sudo systemctl start ntpd

Q2: I get "AccessKey not found or expired"

How to fix:

  1. Log in to the Lovrabet platform

  2. Go to app management and check:

    • Whether the OpenAPI feature is enabled
    • Whether an AccessKey has been generated
    • Whether the AccessKey is still valid
  3. If the AccessKey is expired or lost, regenerate it:

    • Go to app settings
    • Find the OpenAPI configuration
    • Click "Regenerate AccessKey"
    • Copy the new AccessKey and update your configuration

Note: once you regenerate an AccessKey, the old one stops working immediately — update every application that uses it.


Q3: I get "app code not found"

How to fix:

  1. Check that appCode is correct:
Java
// appCode 格式通常为: app-xxxxxxxx
String appCode = "app-c2dd52a2";  // 确保格式正确

// 检查是否有多余的空格或换行符
appCode = appCode.trim();
  1. Confirm the app code on the Lovrabet platform:

    • Go to app management
    • Open the app details
    • Copy the correct app code

Q4: How do I manage AccessKeys for multiple apps?

Recommended approach:

Option 1: environment variables + config file

YAML
# application.yml
lovrabet:
  app1:
    access-key: ${APP1_ACCESS_KEY}
    app-code: app-xxx1
  app2:
    access-key: ${APP2_ACCESS_KEY}
    app-code: app-xxx2

Option 2: a secrets management service

Java
@Configuration
public class LovrabetMultiAppConfig {

    @Bean("app1Client")
    public LovrabetSDKClient app1Client(SecretManager secretManager) {
        String accessKey = secretManager.getSecret("lovrabet-app1-key");
        return new LovrabetSDKClient(accessKey, baseUrl);
    }

    @Bean("app2Client")
    public LovrabetSDKClient app2Client(SecretManager secretManager) {
        String accessKey = secretManager.getSecret("lovrabet-app2-key");
        return new LovrabetSDKClient(accessKey, baseUrl);
    }
}

Parameters and data

Q5: Creating a record fails with "required field missing"

How to fix:

  1. Log in to the Lovrabet platform and open the dataset's field definitions
  2. Check which fields are required
  3. Provide values for every required field:
Java
Map<String, Object> paramMap = new HashMap<>();

// ✅ 正确:提供必填字段的值
paramMap.put("TEXT_1", "客户名称");
paramMap.put("NUMBER_3", 100);

// ❌ 错误:不要传递 null 值
// paramMap.put("TEXT_2", null);

// 对于非必填的空值字段,直接不放入 paramMap

Q6: I'm not sure which field names to use — how do I find a dataset's field definitions?

Method 1: check the Lovrabet platform

  1. Go to app management
  2. Select the dataset
  3. Check the field list for field codes (such as TEXT_1, NUMBER_3)

Method 2: use the browser developer tools

  1. Open the dataset on the Lovrabet platform
  2. Open the browser developer tools (F12)
  3. Switch to the Network tab
  4. Create or edit a record
  5. Inspect the request payload to learn the field names and data format

Field naming conventions:

  • TEXT_1, TEXT_2 - text fields
  • NUMBER_1, NUMBER_2 - number fields
  • SELECT_1, SELECT_2 - select fields
  • DATETIME_1, DATETIME_2 - date-time fields
  • BOOLEAN_1, BOOLEAN_2 - boolean fields

Q7: How do I handle date-time fields?

Option 1: use a timestamp (recommended)

Java
// 当前时间
paramMap.put("DATETIME_1", System.currentTimeMillis());

// 指定日期
Calendar calendar = Calendar.getInstance();
calendar.set(2025, Calendar.JANUARY, 12, 10, 30, 0);
paramMap.put("DATETIME_1", calendar.getTimeInMillis());

// 从 Date 对象
Date date = new Date();
paramMap.put("DATETIME_1", date.getTime());

Option 2: use a string format

Java
// 格式: yyyy-MM-dd HH:mm:ss
paramMap.put("DATETIME_1", "2025-01-12 10:30:00");

Reading date-time values:

Java
// API 返回的是时间戳(毫秒)
Number timestampMs = (Number) data.get("DATETIME_1");
if (timestampMs != null) {
    Date date = new Date(timestampMs.longValue());
    System.out.println("创建时间: " + date);
}

Q8: Do updates need to include every field?

No — pass only the fields you want to update:

Java
// ✅ 推荐:只传递要更新的字段
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("TEXT_1", "新的客户名称");  // 只更新客户名称

LovrabetRequest request = new LovrabetRequest();
request.setId(513L);
request.setParamMap(paramMap);

sdkClient.update(request);

Note: the SDK adds the ID to paramMap automatically; you don't need to include it yourself.


Q9: How do I work with select (dropdown) fields?

Single-select fields:

Java
// 选择字段的值可能是字符串或数字,取决于数据集定义
paramMap.put("SELECT_4", "china-north");  // 字符串类型
paramMap.put("SELECT_7", 463);            // 数字类型

Multi-select fields:

Java
// 多选字段使用 List
List<String> regions = Arrays.asList("north", "south", "east");
paramMap.put("MULTI_SELECT_1", regions);

Finding the available options for a select field:

Check the option list in the dataset's field definition on the Lovrabet platform.


Q10: A paginated query returns nothing even though the dataset has data

Possible causes:

  1. The page number is beyond the available data
  2. Query conditions filtered out all the records
  3. Data permission restrictions

Troubleshooting steps:

Java
// 1. 先查询第一页
paramMap.put("currentPage", 1);
paramMap.put("pageSize", 10);

LovrabetResult<?> result = sdkClient.getList(request);

if (result.isSuccess()) {
    List<?> dataList = (List<?>) result.getData();
    System.out.println("第一页数据量: " + dataList.size());

    if (dataList.isEmpty()) {
        // 2. 检查查询条件
        System.out.println("查询参数: " + paramMap);

        // 3. 尝试不带任何查询条件
        Map<String, Object> simpleParams = new HashMap<>();
        simpleParams.put("currentPage", 1);
        simpleParams.put("pageSize", 10);
        request.setParamMap(simpleParams);

        LovrabetResult<?> result2 = sdkClient.getList(request);
        // ...
    }
}

Performance

Q11: Queries are slow — how can I speed them up?

Optimization strategies:

1. Fetch less data per query

Java
// ❌ 不推荐:pageSize 过大
paramMap.put("pageSize", 1000);

// ✅ 推荐:使用合理的 pageSize
paramMap.put("pageSize", 50);  // 20-100 之间

2. Use a local cache

Java
// 对于不常变化的数据,使用缓存
private final Cache<String, Map<String, Object>> cache =
    Caffeine.newBuilder()
        .maximumSize(1000)
        .expireAfterWrite(5, TimeUnit.MINUTES)
        .build();

public Map<String, Object> getData(String id) {
    return cache.get(id, key -> fetchFromApi(key));
}

3. Query concurrently

Java
// 使用线程池并发查询多个数据
ExecutorService executor = Executors.newFixedThreadPool(10);
List<Future<Map<String, Object>>> futures = new ArrayList<>();

for (String id : idList) {
    Future<Map<String, Object>> future = executor.submit(() -> {
        return queryData(id);
    });
    futures.add(future);
}

// 收集结果
for (Future<Map<String, Object>> future : futures) {
    Map<String, Object> data = future.get();
    // 处理数据
}

executor.shutdown();

Q12: Bulk creation is slow — how can I make it faster?

Optimization options:

1. Create concurrently with a thread pool

Java
ExecutorService executor = Executors.newFixedThreadPool(10);  // 控制并发数

List<CompletableFuture<Void>> futures = dataList.stream()
    .map(data -> CompletableFuture.runAsync(() -> {
        try {
            LovrabetRequest request = buildRequest(data);
            sdkClient.create(request);
        } catch (Exception e) {
            logger.error("创建失败", e);
        }
    }, executor))
    .collect(Collectors.toList());

// 等待所有任务完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
executor.shutdown();

2. Batch processing + retries

Java
public void batchCreateWithRetry(List<Map<String, Object>> dataList) {
    int batchSize = 100;
    for (int i = 0; i < dataList.size(); i += batchSize) {
        int end = Math.min(i + batchSize, dataList.size());
        List<Map<String, Object>> batch = dataList.subList(i, end);

        // 批量创建
        batchCreate(batch);

        // 短暂休息,避免过载
        Thread.sleep(100);
    }
}

Q13: Memory usage is too high

Possible causes:

  1. Loading too much data at once
  2. Not releasing resources promptly

How to fix:

1. Stream large datasets

Java
// ❌ 不推荐:一次性加载所有数据
List<Map<String, Object>> allData = getAllData();  // 可能有 10 万条

// ✅ 推荐:分页流式处理
public void processAllData(Consumer<Map<String, Object>> processor) {
    int currentPage = 1;
    int pageSize = 100;
    boolean hasMore = true;

    while (hasMore) {
        List<Map<String, Object>> pageData = getPageData(currentPage, pageSize);

        if (pageData.isEmpty()) {
            hasMore = false;
        } else {
            // 处理当前页数据
            pageData.forEach(processor);

            // 释放引用,帮助 GC
            pageData.clear();

            if (pageData.size() < pageSize) {
                hasMore = false;
            } else {
                currentPage++;
            }
        }
    }
}

2. Clean up caches regularly

Java
// 定期清理缓存
@Scheduled(fixedRate = 3600000)  // 每小时清理一次
public void cleanupCache() {
    cache.cleanUp();
    logger.info("缓存清理完成");
}

Networking

Q14: I get "Connection timeout" or "Read timeout"

Possible causes:

  1. Unstable network
  2. Slow server responses
  3. Oversized requests

How to fix:

1. Check connectivity

Bash
# 测试网络连接
ping runtime.lovrabet.com

# 测试 HTTPS 连接
curl -I https://runtime.lovrabet.com/openapi

2. Add retries

Java
// 使用重试工具(参考最佳实践文档)
LovrabetResult<?> result = RetryHelper.executeWithRetry(
    () -> sdkClient.getOne(request),
    3,      // 最多重试 3 次
    1000L   // 初始延迟 1 秒
);

3. Request less data per call

Java
// 如果查询数据量过大导致超时
paramMap.put("pageSize", 20);  // 减小 pageSize

Q15: I can't reach the Lovrabet API from the corporate network

Possible cause: firewall or proxy restrictions

How to fix:

1. Configure a proxy

Java
// 设置系统代理
System.setProperty("https.proxyHost", "proxy.company.com");
System.setProperty("https.proxyPort", "8080");

// 如果代理需要认证
System.setProperty("https.proxyUser", "username");
System.setProperty("https.proxyPassword", "password");

2. Contact your network administrator

Ask them to allowlist:

  • runtime.lovrabet.com
  • Port: 443 (HTTPS)

Q16: I occasionally see "SocketException: Connection reset"

Cause: network jitter or a reset connection

How to fix:

Add automatic retries (see Best practices - Error handling):

Java
LovrabetResult<?> result = RetryHelper.executeWithRetry(
    () -> sdkClient.getList(request),
    3,      // 最多重试 3 次
    2000L   // 初始延迟 2 秒
);

Data consistency

Q17: After an update, reads don't return the latest values

Possible causes:

  1. Database replication lag
  2. A stale local cache

How to fix:

1. Wait briefly, then query

Java
// 更新数据
sdkClient.update(updateRequest);

// 短暂等待(通常 100-200ms 足够)
Thread.sleep(100);

// 查询数据
LovrabetResult<?> result = sdkClient.getOne(queryRequest);

2. Use the data you already have

Java
// 更新后直接使用本地数据,不重新查询
Map<String, Object> localData = updateRequest.getParamMap();
// 使用 localData 而不是重新查询

3. Invalidate the local cache

Java
// 更新后清除缓存
sdkClient.update(request);
cache.invalidate(id);  // 清除该 ID 的缓存

Q18: How do I avoid conflicts when updating the same record concurrently?

Option 1: optimistic locking (recommended)

Java
public boolean updateWithVersion(Long id, Map<String, Object> newData) {
    // 1. 查询当前数据和版本号
    Map<String, Object> current = getData(id);
    Integer currentVersion = (Integer) current.get("version");

    // 2. 更新时携带版本号
    newData.put("version", currentVersion + 1);

    LovrabetRequest request = new LovrabetRequest();
    request.setId(id);
    request.setParamMap(newData);

    LovrabetResult<String> result = sdkClient.update(request);

    // 3. 检查更新结果
    if (!result.isSuccess()) {
        // 版本冲突,可能需要重试
        logger.warn("版本冲突,当前版本: {}", currentVersion);
        return false;
    }

    return true;
}

Option 2: distributed lock

Java
public void updateWithLock(Long id, Map<String, Object> newData) {
    String lockKey = "lovrabet:lock:" + id;

    // 获取分布式锁
    RLock lock = redissonClient.getLock(lockKey);

    try {
        // 尝试获取锁,最多等待 10 秒,锁超时时间 30 秒
        if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
            try {
                // 执行更新操作
                sdkClient.update(buildRequest(id, newData));
            } finally {
                lock.unlock();
            }
        } else {
            logger.warn("获取锁超时: {}", id);
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}

Development and debugging

Q19: How do I inspect the HTTP requests the SDK sends?

Method 1: enable logging

YAML
# application.yml 或 logback.xml
logging:
  level:
    com.lovrabet.runtime.opensdk: DEBUG

Method 2: use a packet-capture tool

  • Windows: Fiddler
  • Mac: Charles Proxy
  • Cross-platform: Wireshark

Configure the proxy:

Java
System.setProperty("https.proxyHost", "localhost");
System.setProperty("https.proxyPort", "8888");  // Charles 默认端口

Q20: How do I test the SDK in local development?

Option 1: use a test dataset

Create a dedicated test dataset on the Lovrabet platform so you don't pollute production data.

YAML
# application-dev.yml
lovrabet:
  app-code: app-dev-xxx
  model-code: test-dataset-xxx

Option 2: mock the SDK client

Java
@TestConfiguration
public class TestConfig {

    @Bean
    @Primary  // 覆盖正常的 Bean
    public LovrabetSDKClient mockSdkClient() {
        LovrabetSDKClient mockClient = Mockito.mock(LovrabetSDKClient.class);

        // 设置 Mock 行为
        LovrabetResult<String> mockResult = new LovrabetResult<>();
        mockResult.setSuccess(true);
        mockResult.setData("mock-id-12345");

        Mockito.when(mockClient.create(Mockito.any()))
            .thenReturn(mockResult);

        return mockClient;
    }
}

Q21: How do I debug "the record was created but I can't query it"?

Troubleshooting steps:

Java
// 1. 创建数据并记录返回的 ID
LovrabetResult<String> createResult = sdkClient.create(request);
if (createResult.isSuccess()) {
    String newId = createResult.getData();
    logger.info("创建成功,新 ID: {}", newId);

    // 2. 立即查询确认
    Thread.sleep(200);  // 等待 200ms

    LovrabetRequest queryRequest = new LovrabetRequest();
    queryRequest.setAppCode(appCode);
    queryRequest.setModelCode(modelCode);
    queryRequest.setId(Long.parseLong(newId));

    LovrabetResult<?> queryResult = sdkClient.getOne(queryRequest);

    if (queryResult.isSuccess()) {
        Map<String, Object> data = (Map<String, Object>) queryResult.getData();
        logger.info("查询成功: {}", data);
    } else {
        logger.error("查询失败: {}", queryResult.getResultMsg());
        // 3. 检查 appCode 和 modelCode 是否一致
        logger.error("创建时 appCode: {}, modelCode: {}",
            request.getAppCode(), request.getModelCode());
        logger.error("查询时 appCode: {}, modelCode: {}",
            queryRequest.getAppCode(), queryRequest.getModelCode());
    }
}

Q22: How do I upgrade the SDK version?

Maven projects:

XML
<dependency>
    <groupId>com.lovrabet.runtime</groupId>
    <artifactId>lovrabet-runtime-opensdk</artifactId>
    <version>1.1.0-SNAPSHOT</version>  <!-- 更新版本号 -->
</dependency>

Then run:

Bash
mvn clean install

Gradle projects:

Plain
implementation 'com.lovrabet.runtime:lovrabet-runtime-opensdk:1.1.0-SNAPSHOT'

Then run:

Bash
./gradlew clean build

Upgrade notes:

  1. Read the official documentation to see what changed
  2. Validate in a test environment before upgrading production
  3. Watch out for breaking changes

Getting help

If your question isn't answered here, get help through:

Technical support

When reporting an issue, please include:

  1. SDK version: your lovrabet-runtime-opensdk version
  2. JDK version: your Java version
  3. Error message: the full stack trace (mask any sensitive data)
  4. Reproduction steps: how to trigger the issue
  5. Code snippet: the relevant code (sanitized)

Sample email:

Plain
主题: [OpenSDK] 创建数据时提示必填字段缺失

您好,

我在使用 Lovrabet Java OpenSDK 时遇到问题:

1. SDK 版本: lovrabet-runtime-opensdk 1.0.0-SNAPSHOT
2. JDK 版本: Java 11
3. 错误信息:
   resultCode: PARAM_ERROR
   resultMsg: 必填字段 TEXT_1 缺失

4. 代码片段:
   Map<String, Object> paramMap = new HashMap<>();
   paramMap.put("TEXT_1", "测试数据");
   // ...

5. 已尝试的解决方法:
   - 确认字段名正确
   - 确认值不为 null

请问这个问题如何解决?

谢谢!

Next steps

Now that you've read the FAQ, here's the full learning path for reference:

  1. 📖 Quick start — build your first CRUD program in 5 minutes
  2. 📚 Core concepts — understand how the SDK works
  3. 📋 API reference — the complete API documentation
  4. 💡 Examples — 5 real-world implementations
  5. 🚀 Best practices — production optimization tips
  6. FAQ ← you are here — answers to common questions

Last updated: 2025-10-12

基于飞书知识库同步生成,内容以飞书源文档为准