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:
- The AccessKey is incorrect or expired
- The system clock is more than 10 minutes off from the server time
- A proxy or middleware is modifying the request in transit
How to fix:
// 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:
# Linux/Mac 同步系统时间
sudo ntpdate -u time.apple.com
# 或使用 NTP 服务
sudo systemctl start ntpdQ2: I get "AccessKey not found or expired"
How to fix:
Log in to the Lovrabet platform
Go to app management and check:
- Whether the OpenAPI feature is enabled
- Whether an AccessKey has been generated
- Whether the AccessKey is still valid
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:
- Check that
appCodeis correct:
// appCode 格式通常为: app-xxxxxxxx
String appCode = "app-c2dd52a2"; // 确保格式正确
// 检查是否有多余的空格或换行符
appCode = appCode.trim();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
# application.yml
lovrabet:
app1:
access-key: ${APP1_ACCESS_KEY}
app-code: app-xxx1
app2:
access-key: ${APP2_ACCESS_KEY}
app-code: app-xxx2Option 2: a secrets management service
@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:
- Log in to the Lovrabet platform and open the dataset's field definitions
- Check which fields are required
- Provide values for every required field:
Map<String, Object> paramMap = new HashMap<>();
// ✅ 正确:提供必填字段的值
paramMap.put("TEXT_1", "客户名称");
paramMap.put("NUMBER_3", 100);
// ❌ 错误:不要传递 null 值
// paramMap.put("TEXT_2", null);
// 对于非必填的空值字段,直接不放入 paramMapQ6: I'm not sure which field names to use — how do I find a dataset's field definitions?
Method 1: check the Lovrabet platform
- Go to app management
- Select the dataset
- Check the field list for field codes (such as
TEXT_1,NUMBER_3)
Method 2: use the browser developer tools
- Open the dataset on the Lovrabet platform
- Open the browser developer tools (F12)
- Switch to the Network tab
- Create or edit a record
- Inspect the request payload to learn the field names and data format
Field naming conventions:
TEXT_1,TEXT_2- text fieldsNUMBER_1,NUMBER_2- number fieldsSELECT_1,SELECT_2- select fieldsDATETIME_1,DATETIME_2- date-time fieldsBOOLEAN_1,BOOLEAN_2- boolean fields
Q7: How do I handle date-time fields?
Option 1: use a timestamp (recommended)
// 当前时间
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
// 格式: yyyy-MM-dd HH:mm:ss
paramMap.put("DATETIME_1", "2025-01-12 10:30:00");Reading date-time values:
// 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:
// ✅ 推荐:只传递要更新的字段
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:
// 选择字段的值可能是字符串或数字,取决于数据集定义
paramMap.put("SELECT_4", "china-north"); // 字符串类型
paramMap.put("SELECT_7", 463); // 数字类型Multi-select fields:
// 多选字段使用 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:
- The page number is beyond the available data
- Query conditions filtered out all the records
- Data permission restrictions
Troubleshooting steps:
// 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
// ❌ 不推荐:pageSize 过大
paramMap.put("pageSize", 1000);
// ✅ 推荐:使用合理的 pageSize
paramMap.put("pageSize", 50); // 20-100 之间2. Use a local cache
// 对于不常变化的数据,使用缓存
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
// 使用线程池并发查询多个数据
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
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
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:
- Loading too much data at once
- Not releasing resources promptly
How to fix:
1. Stream large datasets
// ❌ 不推荐:一次性加载所有数据
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
// 定期清理缓存
@Scheduled(fixedRate = 3600000) // 每小时清理一次
public void cleanupCache() {
cache.cleanUp();
logger.info("缓存清理完成");
}Networking
Q14: I get "Connection timeout" or "Read timeout"
Possible causes:
- Unstable network
- Slow server responses
- Oversized requests
How to fix:
1. Check connectivity
# 测试网络连接
ping runtime.lovrabet.com
# 测试 HTTPS 连接
curl -I https://runtime.lovrabet.com/openapi2. Add retries
// 使用重试工具(参考最佳实践文档)
LovrabetResult<?> result = RetryHelper.executeWithRetry(
() -> sdkClient.getOne(request),
3, // 最多重试 3 次
1000L // 初始延迟 1 秒
);3. Request less data per call
// 如果查询数据量过大导致超时
paramMap.put("pageSize", 20); // 减小 pageSizeQ15: I can't reach the Lovrabet API from the corporate network
Possible cause: firewall or proxy restrictions
How to fix:
1. Configure a proxy
// 设置系统代理
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):
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:
- Database replication lag
- A stale local cache
How to fix:
1. Wait briefly, then query
// 更新数据
sdkClient.update(updateRequest);
// 短暂等待(通常 100-200ms 足够)
Thread.sleep(100);
// 查询数据
LovrabetResult<?> result = sdkClient.getOne(queryRequest);2. Use the data you already have
// 更新后直接使用本地数据,不重新查询
Map<String, Object> localData = updateRequest.getParamMap();
// 使用 localData 而不是重新查询3. Invalidate the local cache
// 更新后清除缓存
sdkClient.update(request);
cache.invalidate(id); // 清除该 ID 的缓存Q18: How do I avoid conflicts when updating the same record concurrently?
Option 1: optimistic locking (recommended)
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
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
# application.yml 或 logback.xml
logging:
level:
com.lovrabet.runtime.opensdk: DEBUGMethod 2: use a packet-capture tool
- Windows: Fiddler
- Mac: Charles Proxy
- Cross-platform: Wireshark
Configure the proxy:
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.
# application-dev.yml
lovrabet:
app-code: app-dev-xxx
model-code: test-dataset-xxxOption 2: mock the SDK client
@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:
// 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:
<dependency>
<groupId>com.lovrabet.runtime</groupId>
<artifactId>lovrabet-runtime-opensdk</artifactId>
<version>1.1.0-SNAPSHOT</version> <!-- 更新版本号 -->
</dependency>Then run:
mvn clean installGradle projects:
implementation 'com.lovrabet.runtime:lovrabet-runtime-opensdk:1.1.0-SNAPSHOT'Then run:
./gradlew clean buildUpgrade notes:
- Read the official documentation to see what changed
- Validate in a test environment before upgrading production
- Watch out for breaking changes
Getting help
If your question isn't answered here, get help through:
Technical support
- 📧 Email: service@lovrabet.com
- 🌐 Website: https://lovrabet.com
- 📚 Docs: https://open.lovrabet.com
When reporting an issue, please include:
- SDK version: your
lovrabet-runtime-opensdkversion - JDK version: your Java version
- Error message: the full stack trace (mask any sensitive data)
- Reproduction steps: how to trigger the issue
- Code snippet: the relevant code (sanitized)
Sample email:
主题: [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:
- 📖 Quick start — build your first CRUD program in 5 minutes
- 📚 Core concepts — understand how the SDK works
- 📋 API reference — the complete API documentation
- 💡 Examples — 5 real-world implementations
- 🚀 Best practices — production optimization tips
- ❓ FAQ ← you are here — answers to common questions
Last updated: 2025-10-12