Skip to content

Java SDK

atkonbase-sdk-java —— ATKONBASE 官方 Java SDK(JDK 17,Java 业务后端;独立制品,无需引入服务端模块依赖)。本页讲用法;端点契约见接口参考,认证形态的概念背景见集成拓扑

安装

包通过 Maven 坐标引入(如所在环境的制品仓库未托管该坐标,请向 ATKONBASE 获取制品仓库地址):

xml
<dependency>
    <groupId>com.yhcm.atkonbase</groupId>
    <artifactId>atkonbase-sdk-java</artifactId>
    <version>0.5.0-SNAPSHOT</version>
</dependency>

最小示例(APP_ONLY)

最常见的服务端到服务端调用——只用 Client 身份。withClientCredentials 一行构造,baseUrl 只传一次:

java
import com.yhcm.atkonbase.sdk.client.AtkonbaseClient;
import com.yhcm.atkonbase.sdk.generated.api.V1DocumentApi;

AtkonbaseClient client = AtkonbaseClient.withClientCredentials(
    "https://api.atkonbase.example.com", "${clientId}", "${clientSecret}");

V1DocumentApi v1 = client.api(V1DocumentApi.class);
MyType data = v1.someV1Endpoint(/* ... */).getData();

client.api(...)内化响应解包:业务 code != 0 或 HTTP 非 2xx 直接抛 AtkonbaseApiException(携带真实 HTTP 状态码),成功时返回 generated 统一返回体 ResponseDTO,集成方通过它的 getData() 取业务数据——无需任何手动解包。

高级构造

需要自定义超时 / OkHttpClient / 默认头 / 关闭 401 自动刷新时,改用全量 ClientOptions 构造(与 withClientCredentials 等价,只是把三步装配显式展开):

java
import com.yhcm.atkonbase.sdk.client.AtkonbaseClient;
import com.yhcm.atkonbase.sdk.client.ClientCredentialsTokenProvider;
import com.yhcm.atkonbase.sdk.client.RefreshableTokenProvider;
import com.yhcm.atkonbase.sdk.client.V1Auth;

RefreshableTokenProvider clientToken = ClientCredentialsTokenProvider.builder()
    .baseUrl("https://api.atkonbase.example.com")
    .clientId("${clientId}")
    .clientSecret("${clientSecret}")
    .build();

AtkonbaseClient client = new AtkonbaseClient(
    AtkonbaseClient.ClientOptions.builder()
        .baseUrl("https://api.atkonbase.example.com")
        .auth(V1Auth.builder().clientToken(clientToken).build())
        .timeoutMs(60_000L)        // 默认 30s
        .autoRefreshOn401(true)    // 默认开
        .build());

V1Auth 是 client 级身份配置,只承载 clientToken(app 自身长期固定身份)。代表某个终端用户 / 外部身份的「代授权」是 per-call 的,下沉到调用层表达(见下)——不挂在 V1Auth 上。

三种认证形态

身份分两层:clientTokenclient 级长期固定身份,由 client 承载;代授权(代表谁)是 per-call 的,由调用层 actAsToken / actAsSource 表达,各返回一个只暴露 api()ScopedView

形态调用注入的请求头
APP_ONLYclient.api(Xxx.class)Authorization: Bearer <client>
强通道(代表已登录用户)client.actAsToken(userToken).api(Xxx.class)上 + X-Atk-User-Token: <user>
弱通道(代表外部身份)client.actAsSource(source, sourceId).api(Xxx.class)上 + X-Atk-Act-As-Source + X-Atk-Act-As-Source-Id
java
// APP_ONLY:纯 client 身份
MyType data = client.api(V1DocumentApi.class)
    .someEndpoint(/* ... */)
    .getData();

// 强通道:代表一个已签发用户会话 token 的用户
MyType userData = client.actAsToken(userSessionToken)
    .api(V1DocumentApi.class)
    .someEndpoint(/* ... */)
    .getData();

// 弱通道:Client 主张代表外部身份(需 server 侧开启 actAsAllowed)
MyType extData = client.actAsSource("wechat", "openid-xxx")
    .api(V1DocumentApi.class)
    .someEndpoint(/* ... */)
    .getData();

要点:

  • 代授权是 per-call 的actAsToken / actAsSource 每次按需调用产出 ScopedView,同一个 client 可对不同终端用户安全并发复用——所有视图共享同一连接池与 clientToken 刷新单点。
  • 通道互斥在编译期成立ScopedView 只暴露 api(),类型层面无法再叠加另一通道(强、弱不可同时);actAsSource 双参签名保证 sourcesourceId 成对。约束前移到编译期,不再有运行期校验。

TokenProvider 与凭据刷新

java
@FunctionalInterface
public interface TokenProvider {
    String resolve();   // 同步签名,每次请求前由拦截器调一次
}

工厂:

工厂语义
TokenProvider.of(String)字面量 token
TokenProvider.of(Supplier<String>)动态 token(你控制缓存)
ClientCredentialsTokenProvider.builder()...build()可刷新 token(RefreshableTokenProvider,SDK 在 401 时主动 invalidate)

⚠️ resolve() 为同步签名,请在其中完成 token 获取(含必要的阻塞等待)。需要「动态 token + 异步刷新」时,在 Supplier#get()future.get(timeout) 阻塞拉取。

ClientCredentialsTokenProviderclientId + clientSecretPOST /v1/auth/token,带缓存 + 提前续期 + 并发去重(线程安全)。withClientCredentials 工厂内部即用它装配;需要调参时单独构造:

java
ClientCredentialsTokenProvider provider = ClientCredentialsTokenProvider.builder()
    .baseUrl("https://api.atkonbase.example.com")
    .clientId("${clientId}")
    .clientSecret("${clientSecret}")
    .refreshSkewMs(60_000L)   // 提前续期窗口,默认 60s
    .timeoutMs(10_000L)       // token 端点超时,默认 10s
    .build();

跨多个 AtkonbaseClient 共享缓存时,复用同一个 provider 实例——不要重复 build(),每次产出独立闭包状态。

401 自动刷新

autoRefreshOn401(true)(默认)且 clientTokenRefreshableTokenProvider 时,收到 401 时先 invalidate() 当前 token,再用新 token 自动重试一次(仅一次,避免无限重试)。否则退回「401 直接抛 AtkonbaseApiException」。

错误处理

java
class AtkonbaseApiException extends RuntimeException {
    int getCode();        // server 业务 code(0 成功,其它失败;常量见 ErrorCodes)
    int getHttpStatus();  // 真实 HTTP 状态码
    Object getData();
}
class AtkonbaseNetworkException extends RuntimeException {
    // 由 IOException 包装;getCause() 返回原异常
}
java
import com.yhcm.atkonbase.sdk.client.AtkonbaseApiException;
import com.yhcm.atkonbase.sdk.client.AtkonbaseNetworkException;
import com.yhcm.atkonbase.sdk.client.ErrorCodes;

try {
    MyType data = client.api(V1DocumentApi.class).someEndpoint(/* ... */).getData();
} catch (AtkonbaseApiException e) {
    if (e.getCode() == ErrorCodes.USER_TOKEN_INVALID) {
        // 强通道 user_token 失效,触发用户重新登录
    } else if (e.getCode() == ErrorCodes.PERMISSION_DENIED) {
        // 权限不足
    }
} catch (AtkonbaseNetworkException e) {
    // 网络 / 超时
}

错误码常量 ErrorCodes

com.yhcm.atkonbase.sdk.client.ErrorCodes 提供 V1 集成接口可能返回的业务错误码常量,覆盖全部 V1 接口。分段概览:

段位含义
101*认证(含 USER_TOKEN_INVALID / INVALID_DELEGATION_HEADERS / V1_ACL_USER_IDENTITY_REQUIRED 等)
102*权限 / ACL
105*IdP / SSO
106*API Client / Scope
112*业务身份(用户 / 角色 / 部门)
173* / 179*存储与文件上传 / 下载(预签名 / 分片会话 / 签名直读 / 配额 / MIME 校验)
174*站内分享 / 分享链接 / 公开分享消费
175*容器生命周期(归档 / 回收站 / 恢复 / 移动 等)
176*检索
177*Webhook
181*服务端摄入(/v1/ingest/*
182* / 183*元数据值 / 字段定义 / 内容类型 / 模型 Schema 导出
185*文档生命周期(发布 / 版本回退 / 回收站 等)
186* / 187*内容 ACL / 资源访问前置校验

完整含义与触发条件见错误码参考

public 分享通路

AtkonbasePublicClient 覆盖 /public/s/{tenantCode}/{token}/** 匿名分享端点,无 auth,与 V1 client 类型层面互不替换:

java
import com.yhcm.atkonbase.sdk.client.AtkonbasePublicClient;
import com.yhcm.atkonbase.sdk.client.AtkonbasePublicClient.PublicClientOptions;
import com.yhcm.atkonbase.sdk.client.AtkonbasePublicClient.BuildDownloadUrlOptions;
import com.yhcm.atkonbase.sdk.generatedpublic.model.PublicShareMetaDTO;
import com.yhcm.atkonbase.sdk.generatedpublic.model.ShareVerifyResultDTO;

AtkonbasePublicClient publicClient = new AtkonbasePublicClient(
    PublicClientOptions.builder().baseUrl("https://api.atkonbase.example.com").build()
);

// 1. 拉元信息
PublicShareMetaDTO meta = publicClient.getMeta(tenantCode, token);

// 2. 需要密码时,验证后拿一次性 ticket
String ticket = null;
if (Boolean.TRUE.equals(meta.getRequiresPassword())) {
    ShareVerifyResultDTO verify = publicClient.verifyPassword(tenantCode, token, userInputPassword);
    ticket = verify.getTicket();
}

// 3. 拼下载 URL —— 浏览器原生导航 / 服务端流式转发
String url = publicClient.buildDownloadUrl(
    tenantCode, token,
    BuildDownloadUrlOptions.builder().ticket(ticket).build()
);

⚠️ ticket 是 IP-bound:ticket 与验密码请求的公网 IP 绑定。verifyPassword 调用方与最终下载方必须是同一公网 IP,否则下载被拒。服务端代理场景下不要把 ticket 透传给前端浏览器——正确做法是集成方服务端自己用 ticket 走 buildDownloadUrl + OkHttp/HttpClient 流式转发。前端直连无此问题。

错误处理与 v1 一致:getMeta / verifyPassword 失败抛 AtkonbaseApiExceptionbuildDownloadUrl 仅拼字符串,不抛业务错。

BuildDownloadUrlOptions.disposition"inline" / "attachment")参数当前保留但不生效:下载一律以 attachment(触发下载)响应。如需浏览器内预览,请改用接口参考中的预览模式端点。

与 TypeScript SDK 的差异

主题JavaTypeScript
主入口client.api(V1DocumentApi.class)client.api(V1DocumentApi) + client.request<T>(path) 转义出口
代授权client.actAsToken(token) / actAsSource(source, id)ScopedView同左(形态镜像一致)
TokenProvider 异步性同步 String resolve()原生支持异步(() => Promise<string>
错误统一api() 内化解包:非 2xx 与 code != 0AtkonbaseApiException,成功读 dto.getData()中间件把非 2xx 与 code !== 0 转成 AtkonbaseApiError,成功读 dto.data
错误码常量ErrorCodes 覆盖 V1 子集errorCodes 覆盖 V1 子集

TypeScript 用法见 TypeScript SDK