# Java调用示例

### **前提条件**

1. [您需要一个有效的 API Key 和 API Secret](/getting-started/buy-energy-via-api-on-catfee/api-overview.md#apply-api-info)。
2. 确保您的环境已安装 Java 8 及以上版本，并导入以下依赖：
   * `java.net.http.HttpClient`
   * `java.security.MessageDigest`
   * `javax.crypto.Mac`
   * `javax.crypto.spec.SecretKeySpec`

### **示例代码**

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class CatFeeAPIExample {

    private static final String API_KEY = "your_api_key"; // 请替换为您的API Key
    private static final String API_SECRET = "your_api_secret"; // 请替换为您的API Secret
    private static final String BASE_URL = "https://api.catfee.io";

    public static void main(String[] args) throws Exception {
        // 请求方法
        String method = "POST"; // 可以根据需要修改为 "GET", "PUT", "DELETE" 等

        // 示例：创建订单
        String path = "/v1/order";
        Map<String, String> queryParams = new HashMap<>();
        queryParams.put("quantity", "65000");
        queryParams.put("receiver", "TRON_ADDRESS");
        queryParams.put("duration", "1h");

        // 生成请求头
        String timestamp = generateTimestamp();
        String requestPath = buildRequestPath(path, queryParams);
        String signature = generateSignature(timestamp, method, requestPath);

        // 创建HTTP请求
        String url = BASE_URL + requestPath;
        HttpRequest request = createRequest(url, method, timestamp, signature);

        // 发送请求并获取响应
        HttpClient client = HttpClient.newHttpClient();
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

        // 打印响应
        System.out.println("Response Code: " + response.statusCode());
        System.out.println("Response Body: " + response.body());

        // 处理可能的错误信息
        if (response.statusCode() != 200) {
            System.out.println("Error: " + response.body());
        }
    }

    // 生成当前 UTC 时间戳（ISO 8601格式）
    public static String generateTimestamp() {
        return Instant.now().toString();
    }

    // 构建请求路径，包括查询参数
    public static String buildRequestPath(String path, Map<String, String> queryParams) {
        if (queryParams == null || queryParams.isEmpty()) {
            return path;
        }
        String queryString = queryParams.entrySet().stream()
                .map(entry -> entry.getKey() + "=" + entry.getValue())
                .collect(Collectors.joining("&", "?", ""));
        return path + queryString;
    }

    // 生成签名
    public static String generateSignature(String timestamp, String method, String requestPath) throws Exception {
        String signString = timestamp + method + requestPath;
        return hmacSHA256(signString, API_SECRET);
    }

    // 使用 HMAC-SHA256 算法生成签名
    public static String hmacSHA256(String data, String secret) throws Exception {
        Mac sha256Hmac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        sha256Hmac.init(secretKey);
        byte[] hash = sha256Hmac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(hash);
    }

    // 创建 HTTP 请求，支持 GET, POST, PUT, DELETE
    public static HttpRequest createRequest(String url, String method, String timestamp, String signature) {
        HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header("Content-Type", "application/json")
                .header("CF-ACCESS-KEY", API_KEY)
                .header("CF-ACCESS-SIGN", signature)
                .header("CF-ACCESS-TIMESTAMP", timestamp);

        switch (method.toUpperCase()) {
            case "POST":
                requestBuilder.POST(HttpRequest.BodyPublishers.noBody());
                break;
            case "PUT":
                requestBuilder.PUT(HttpRequest.BodyPublishers.noBody());
                break;
            case "DELETE":
                requestBuilder.DELETE();
                break;
            case "GET":
                requestBuilder.GET();
                break;
            default:
                throw new UnsupportedOperationException("Unsupported HTTP method: " + method);
        }

        return requestBuilder.build();
    }
}
```

### **代码解析**

1. **`method` 变量**：\
   在 `main` 函数中，使用 `String method = "POST";` 来定义请求方法。这可以根据需要修改为 `"GET"`、`"PUT"` 或 `"DELETE"` 等。
2. **生成当前时间戳**：\
   `generateTimestamp()` 函数使用 `Instant.now().toString()` 获取当前 UTC 时间，并以 ISO 8601 格式返回时间戳。
3. **构建请求路径**：\
   `buildRequestPath()` 函数根据传入的查询参数（`queryParams`）构建完整的 URL 路径，并将查询参数拼接到请求路径后。该函数返回一个带有查询参数的完整路径。
4. **生成签名**：\
   `generateSignature()` 函数将 `timestamp`、`method` 和 `requestPath` 拼接成签名字符串，并通过 `hmacSHA256()` 方法进行加密，使用 API Secret 作为密钥，生成签名。
5. **HMAC-SHA256 加密**：\
   `hmacSHA256()` 函数实现了 HMAC-SHA256 签名算法，用于生成请求的签名。
6. **创建请求**：\
   `createRequest()` 函数根据不同的 HTTP 方法（`GET`、`POST`、`PUT`、`DELETE`）动态构建 HTTP 请求。如果是 `POST` 或 `PUT` 请求，使用 `HttpRequest.BodyPublishers.noBody()`，如果是 `DELETE` 或 `GET` 请求，则使用对应的 `DELETE()` 和 `GET()` 方法。
7. **发送请求并获取响应**：\
   使用 `HttpClient` 发送 HTTP 请求，并通过 `HttpResponse.BodyHandlers.ofString()` 获取响应内容。
8. **错误处理**：\
   示例代码中通过 `if (response.statusCode() != 200)` 判断响应状态码，如果响应失败，打印错误信息。

### **注意事项**

* **API Key 和 Secret**：\
  请确保将 `API_KEY` 和 `API_SECRET` 替换为您从 CatFee.IO 获取的实际值。
* **签名的作用**：\
  签名用于验证请求的合法性，确保请求未被篡改。签名是通过将 `timestamp`、`HTTP 方法`、`请求路径` 和 `查询字符串` 拼接在一起计算得到的。
* **查询参数的顺序**：\
  查询参数应按照原始顺序传递，不需要特别排序。
* **请求的 HTTP 方法**：\
  当前示例支持 `POST`、`PUT`、`GET` 和 `DELETE` 方法，查询参数仍然通过 URL 中传递。
* **响应处理**：\
  示例中直接打印响应内容。如果需要进一步处理响应数据，可以将其解析为 JSON 或其他格式。

### **总结**

此示例展示了如何在 Java 中使用 CatFee.IO Rest API 进行安全的 API 调用。通过使用 HMAC-SHA256 签名和正确的查询参数处理，确保请求的有效性和安全性。您可以根据需要调整代码，进行不同的操作，支持 `GET`、`POST`、`PUT` 和 `DELETE` 方法。

如有任何问题或需要进一步的帮助，欢迎联系 CatFee.IO 支持团队！


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.catfee.io/getting-started/buy-energy-via-api-on-catfee/java.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
