### Request Creation Example Source: https://github.com/dromara/forest/blob/master/_autodocs/05-configuration.md Examples of executing GET and POST requests. ```java String result = config.get("http://api.example.com/data").execute(String.class); String postResult = config.post("http://api.example.com/users") .json(newUser) .execute(String.class); ``` -------------------------------- ### Singleton Access Example Source: https://github.com/dromara/forest/blob/master/_autodocs/05-configuration.md Example of how to get the default and a named configuration instance. ```java ForestConfiguration defaultConfig = ForestConfiguration.configuration(); ForestConfiguration apiConfig = ForestConfiguration.configuration("api-service"); ``` -------------------------------- ### Content Type Examples Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Provides examples of setting different content types for POST requests. ```java // JSON Forest.post(url) .contentType("application/json") .json(object) .execute(); // Form-encoded Forest.post(url) .contentType("application/x-www-form-urlencoded") .addBody("field1", "value1") .execute(); // XML Forest.post(url) .contentType("application/xml") .body(xmlString) .execute(); // Multipart/form-data Forest.post(url) .contentType("multipart/form-data") .addFile("file", file) .addBody("field", "value") .execute(); // Plain text Forest.post(url) .contentType("text/plain") .body(textContent) .execute(); // Binary Forest.post(url) .contentType("application/octet-stream") .body(byteArray) .execute(); ``` -------------------------------- ### GET Request Example Source: https://github.com/dromara/forest/blob/master/_autodocs/01-core-api.md Example of creating and executing a GET request. ```java String content = Forest.get("http://example.com") .execute(String.class); ``` -------------------------------- ### GET with Query Parameters Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Send a GET request with query parameters. ```java String result = Forest.get("http://api.example.com/users") .query("page", 1) .query("limit", 10) .execute(String.class); ``` -------------------------------- ### GET Request with URL Template Example Source: https://github.com/dromara/forest/blob/master/_autodocs/01-core-api.md Example of creating and executing a GET request with a URL template and arguments. ```java String data = Forest.get("http://api.example.com/users/{0}/posts/{1}", 123, 456).execute(String.class); ``` -------------------------------- ### Named Configuration Example Source: https://github.com/dromara/forest/blob/master/_autodocs/01-core-api.md Example of how to get a named configuration instance. ```java ForestConfiguration apiConfig = Forest.config("api-service"); ``` -------------------------------- ### @Get Example Source: https://github.com/dromara/forest/blob/master/_autodocs/03-annotations.md Example usage of the @Get annotation. ```java @Get("http://api.example.com/users/{id}") User getUser(@PathVariable("id") String id); ``` -------------------------------- ### Timeout Configuration Examples Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Illustrates how to configure global and per-request timeouts, including connect and read timeouts. ```java // Global timeout Forest.config().setTimeout(30000); // Per-request timeout Forest.get(url) .timeout(30, TimeUnit.SECONDS) .execute(); // Connect timeout Forest.get(url) .connectTimeout(10, TimeUnit.SECONDS) .execute(); // Read timeout Forest.get(url) .readTimeout(30, TimeUnit.SECONDS) .execute(); // Both Forest.get(url) .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .execute(); ``` -------------------------------- ### Backend Selection Example Source: https://github.com/dromara/forest/blob/master/_autodocs/01-core-api.md Example of how to get a specified HTTP backend implementation. ```java HttpBackend backend = Forest.backend("okhttp"); ``` -------------------------------- ### Global Configuration Example Source: https://github.com/dromara/forest/blob/master/_autodocs/01-core-api.md Example of how to get and modify global configuration. ```java ForestConfiguration config = Forest.config(); config.setMaxConnections(100); ``` -------------------------------- ### Backend Configuration - setBackend Example Source: https://github.com/dromara/forest/blob/master/_autodocs/05-configuration.md Example of setting an OkHttp backend. ```java ForestConfiguration config = Forest.config(); config.setBackend("okhttp", new OkHttpBackend()); ``` -------------------------------- ### Basic Usage Example Source: https://github.com/dromara/forest/blob/master/_autodocs/04-response-api.md A basic example demonstrating how to make a GET request, execute it asynchronously, and retrieve the content if the status code is 200. ```java ForestResponse response = Forest.get("http://api.example.com/users/1") .asyncExecute(String.class) .get(); if (response.getStatusCode() == 200) { String content = response.getContent(); System.out.println(content); } response.close(); ``` -------------------------------- ### Basic SSE Stream Source: https://github.com/dromara/forest/blob/master/_autodocs/10-advanced-features.md Example demonstrating how to set up and start a basic SSE stream with callbacks for open, message, error, and close events. ```java ForestSSE sse = Forest.get("http://api.example.com/events") .asyncExecute() .sse(); sse.onOpen(response -> { System.out.println("SSE connection opened"); }) .onMessage(message -> { System.out.println("Message: " + message); }) .onError(error -> { System.err.println("SSE error: " + error.getMessage()); }) .onClose(response -> { System.out.println("SSE connection closed"); }) .start(); ``` -------------------------------- ### Client Interface Creation Example Source: https://github.com/dromara/forest/blob/master/_autodocs/05-configuration.md Example of creating and using a client interface instance. ```java @ForestClient(baseUrl = "http://api.example.com") public interface UserApi { @Get("/users/{id}") User getUser(@PathVariable("id") String id); } ForestConfiguration config = Forest.config(); UserApi api = config.createInstance(UserApi.class); User user = api.getUser("123"); ``` -------------------------------- ### Simple GET Request Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Execute a simple GET request to retrieve data as a String. ```java String result = Forest.get("http://api.example.com/data") .execute(String.class); ``` -------------------------------- ### Complete Configuration Example Source: https://github.com/dromara/forest/blob/master/_autodocs/05-configuration.md A comprehensive example demonstrating various configuration settings including connection pooling, timeouts, character encoding, async configuration, retry policies, auto-redirection, global variables, interceptors, logging, and JSON converters. ```java ForestConfiguration config = Forest.config(); // Connection pooling config.setMaxConnections(200); config.setMaxRouteConnections(50); // Timeouts config.setConnectTimeout(5000); config.setReadTimeout(10000); // Character encoding config.setCharset("UTF-8"); // Async configuration config.setMaxAsyncThreadSize(50); config.setMaxAsyncQueueSize(1000); config.setAsyncMode(ForestAsyncMode.PLATFORM); // Retry policy config.setMaxRetryCount(3); config.setMaxRetryInterval(5000); // Auto-redirection config.setAutoRedirection(true); // Global variables config.setVariable("baseUrl", "http://api.example.com"); config.setVariable("apiKey", "sk-12345678"); // Interceptors config.addInterceptor(new LoggingInterceptor()); config.addInterceptor(new AuthenticationInterceptor()); // Logging config.setLogHandler(new DefaultLogHandler()); // JSON converter (Fastjson2 is auto-selected if available) // config.setJsonConverter(new Fastjson2Converter()); ``` -------------------------------- ### Interceptor Example Source: https://github.com/dromara/forest/blob/master/_autodocs/05-configuration.md Example of adding logging and authentication interceptors. ```java config.addInterceptor(new LoggingInterceptor()); config.addInterceptor(new AuthenticationInterceptor()); ``` -------------------------------- ### GET with Path Variables Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Define a Forest client interface with path variables for GET requests. ```java @ForestClient public interface UserApi { @Get("/users/{id}") User getUser(@PathVariable("id") String id); } User user = api.getUser("123"); ``` -------------------------------- ### Client Instance Creation Example Source: https://github.com/dromara/forest/blob/master/_autodocs/01-core-api.md Example of creating a dynamic proxy instance of an interface decorated with @ForestClient. ```java public interface MyApiClient { @Get("http://api.example.com/users") List getUsers(); } MyApiClient client = Forest.client(MyApiClient.class); List users = client.getUsers(); ``` -------------------------------- ### Client Interface Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Defines an HTTP client interface using annotations and provides an example of its usage. ```java @ForestClient(baseUrl = "http://api.example.com") public interface ApiClient { @Get("/users") List listUsers(); @Get("/users/{id}") User getUser(@PathVariable("id") String id); @Post("/users") User createUser(@JSONBody User user); @Put("/users/{id}") User updateUser( @PathVariable("id") String id, @JSONBody User user ); @Delete("/users/{id}") void deleteUser(@PathVariable("id") String id); } // Usage ApiClient client = Forest.client(ApiClient.class); List users = client.listUsers(); ``` -------------------------------- ### Variable Example Source: https://github.com/dromara/forest/blob/master/_autodocs/05-configuration.md Example of setting global variables for base URL and API key. ```java config.setVariable("baseUrl", "http://api.example.com"); config.setVariable("apiKey", "sk-12345678"); ``` -------------------------------- ### getContent Example Source: https://github.com/dromara/forest/blob/master/_autodocs/04-response-api.md Illustrates how to get the response body as a String. ```java String content = response.getContent(); System.out.println(content); ``` -------------------------------- ### SSL/TLS Exceptions Example Source: https://github.com/dromara/forest/blob/master/_autodocs/08-error-handling.md Example demonstrating how to catch SSL/TLS related exceptions. ```java try { String result = Forest.get("https://api.example.com/secure") .execute(String.class); } catch (Exception e) { if (e.getMessage().contains("SSL") || e.getMessage().contains("certificate")) { System.err.println("SSL/TLS error: " + e.getMessage()); } } ``` -------------------------------- ### Complete Interceptor Chain Example Source: https://github.com/dromara/forest/blob/master/_autodocs/07-interceptors-and-filters.md Example demonstrating how to set up a complete interceptor chain with multiple interceptors. ```java public class InterceptorChainExample { public static void setupInterceptorChain(ForestConfiguration config) { // Layer 1: Logging (outermost) config.addInterceptor(new LoggingInterceptor()); // Layer 2: Request modification (add headers, tracking IDs) config.addInterceptor(new RequestModificationInterceptor()); // Layer 3: Authentication (add auth headers) config.addInterceptor(new AuthenticationInterceptor("api-key-123")); // Layer 4: Request validation (innermost) config.addInterceptor(new RequestValidationInterceptor()); } } // Usage: ForestConfiguration config = Forest.config(); InterceptorChainExample.setupInterceptorChain(config); @ForestClient(baseUrl = "http://api.example.com") public interface ApiClient { @Get("/data") String getData(); } ApiClient client = Forest.client(ApiClient.class); // All interceptors in chain will process this request String result = client.getData(); ``` -------------------------------- ### @Post Example Source: https://github.com/dromara/forest/blob/master/_autodocs/03-annotations.md Example usage of the @Post annotation. ```java @Post("http://api.example.com/users") User createUser(@JSONBody User user); ``` -------------------------------- ### @ForestClient Example Source: https://github.com/dromara/forest/blob/master/_autodocs/03-annotations.md Example usage of the @ForestClient annotation. ```java @ForestClient(baseUrl = "http://api.example.com") public interface UserApi { @Get("/users/{id}") User getUserById(@PathVariable("id") String id); @Post("/users") User createUser(@JSONBody User user); } ``` -------------------------------- ### ConnectException / SocketException Example Source: https://github.com/dromara/forest/blob/master/_autodocs/08-error-handling.md Example for catching ConnectException or SocketException, which are thrown for connection failures. ```java try { String result = Forest.get("http://invalid-host.example.com/data") .connectTimeout(5, TimeUnit.SECONDS) .execute(String.class); } catch (Exception e) { if (e instanceof ConnectException) { System.err.println("Cannot connect to server"); } } ``` -------------------------------- ### getResult Example Source: https://github.com/dromara/forest/blob/master/_autodocs/04-response-api.md Shows how to get the response body deserialized into a specific object type. ```java User user = response.getResult(); System.out.println(user.getName()); ``` -------------------------------- ### Progress Monitoring Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Demonstrates how to monitor the progress of a file upload request. ```java File file = new File("large-file.zip"); Forest.post("http://api.example.com/upload") .addFile("file", file) .onProgress(progress -> { System.out.printf("Progress: %.2f%%\n", progress.getRate() * 100); }) .execute(String.class); ``` -------------------------------- ### Connection Pool Configuration - setMaxConnections Example Source: https://github.com/dromara/forest/blob/master/_autodocs/05-configuration.md Example of setting the maximum connections. ```java config.setMaxConnections(200); ``` -------------------------------- ### Batch File Upload (List) Source: https://github.com/dromara/forest/blob/master/README.md Example of uploading a list of files wrapped in a List, where `_index` represents the loop counter (starting from zero). ```java /** * 上传List包装的文件列表,其中 {_index} 代表每次迭代List的循环计数(从零开始计) */ @Post("/upload") ForestRequest uploadByteArrayList(@DataFile(value = "file", fileName = "test-img-{_index}.jpg") List byteArrayList); ``` -------------------------------- ### Spring Boot Configuration Source: https://github.com/dromara/forest/blob/master/forest-examples/example-chatgpt/README.md Configuration for the forest starter, including connection timeouts, custom variables like API key, model, max tokens, and temperature. ```yaml forest: connect-timeout: 60000 # HTTP请求连接超时时间 read-timeout: 60000 # HTTP请求读取超时时间 variables: # 自定义变量: apiKey: YOUR_API_KEY # 你的 OpenAI 的 API KEY model: text-davinci-003 # ChartGPT 的模型 maxTokens: 50 # 最大 Token 数 temperature: 0.5 # 该值越大每次返回的结果越随机,即相似度越小 ``` -------------------------------- ### getStatusCode Example Source: https://github.com/dromara/forest/blob/master/_autodocs/04-response-api.md Demonstrates how to get the HTTP status code and conditionally process the response content. ```java ForestResponse response = Forest.get("http://api.example.com/data") .asyncExecute(String.class) .get(); if (response.getStatusCode() == 200) { String content = response.getContent(); } ``` -------------------------------- ### Custom Authenticator Example Source: https://github.com/dromara/forest/blob/master/_autodocs/10-advanced-features.md Demonstrates how to create a custom authenticator by extending ForestAuthenticator and implementing the authenticate method. Includes a usage example. ```java public class SignatureAuthenticator extends ForestAuthenticator { private String secretKey; public SignatureAuthenticator(String secretKey) { this.secretKey = secretKey; } @Override public boolean authenticate(ForestRequest request) { long timestamp = System.currentTimeMillis(); String nonce = UUID.randomUUID().toString(); String signature = calculateSignature( request.getUrl(), timestamp, nonce, secretKey ); request.addHeader("X-Timestamp", String.valueOf(timestamp)); request.addHeader("X-Nonce", nonce); request.addHeader("X-Signature", signature); return true; } private String calculateSignature(String url, long timestamp, String nonce, String key) { // Implementation of signature calculation return Base64.getEncoder().encodeToString( HMACSHA256( url + timestamp + nonce, key ) ); } private byte[] HMACSHA256(String data, String key) { // HMAC-SHA256 implementation return new byte[]{}; } } // Usage Forest.get("http://api.example.com/secure") .authenticator(new SignatureAuthenticator("secret-key")) .execute(String.class); ``` -------------------------------- ### Async Request Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Execute a request asynchronously and get the result later. ```java ForestFuture future = Forest.get("http://api.example.com/data") .asyncExecute(String.class); // Do other work... String result = (String) future.get(); ``` -------------------------------- ### Example: File Upload Source: https://github.com/dromara/forest/blob/master/_autodocs/02-request-api.md Example of uploading a file using addFile. ```java File uploadFile = new File("document.pdf"); Map result = Forest.post("http://api.example.com/upload") .addFile("file", uploadFile) .execute(Map.class); ``` -------------------------------- ### Custom Headers Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Add custom headers to your requests. ```java String result = Forest.get("http://api.example.com/secure") .header("Authorization", "Bearer token123") .header("X-API-Key", "api-key-123") .execute(String.class); ``` -------------------------------- ### HTTP Basic Auth Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Configure HTTP Basic Authentication for your requests. ```java String result = Forest.get("http://api.example.com/admin") .basicAuth("username", "password") .execute(String.class); ``` -------------------------------- ### Real-time Chat Example Source: https://github.com/dromara/forest/blob/master/_autodocs/10-advanced-features.md A complete example of a real-time chat application using SSE to connect, receive messages, and handle user join/leave events. ```java public class ChatSSEExample { private ForestSSE sse; public void connectToChat(String roomId) { sse = Forest.get("http://api.example.com/chat/" + roomId + "/events") .asyncExecute() .sse(Message.class); sse.onOpen(response -> { System.out.println("Connected to chat: " + roomId); }) .onData(message -> { if (message.sender.equals("system")) { System.out.println(">> System: " + message.content); } else { System.out.println(message.sender + ": " + message.content); } }) .onEvent("user-joined", msg -> { System.out.println(">>> " + msg + " joined the chat"); }) .onEvent("user-left", msg -> { System.out.println("<<< " + msg + " left the chat"); }) .onError(error -> { System.err.println("Chat error: " + error.getMessage()); }) .onClose(response -> { System.out.println("Disconnected from chat"); }) .start(); } public void disconnect() { if (sse != null) { sse.close(); } } } // Message class class Message { public String sender; public String content; public long timestamp; } ``` -------------------------------- ### @Request Example Source: https://github.com/dromara/forest/blob/master/_autodocs/03-annotations.md Example usage of the @Request annotation for a POST request. ```java @Request( url = "http://api.example.com/data", type = "POST", contentType = "application/json", dataType = "json" ) Map postData(@JSONBody Map data); ``` -------------------------------- ### POST with Form Data Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Send a POST request with form data. ```java String result = Forest.post("http://api.example.com/login") .addBody("username", "admin") .addBody("password", "password123") .execute(String.class); ``` -------------------------------- ### Registering Interceptors Per-Method Source: https://github.com/dromara/forest/blob/master/_autodocs/07-interceptors-and-filters.md Example of registering interceptors per-method using the @Get annotation. ```java @ForestClient public interface ApiClient { @Get( url = "/secure", interceptor = {AuthenticationInterceptor.class} ) String getSecureData(); } ``` -------------------------------- ### Create an Interface for API Calls Source: https://github.com/dromara/forest/blob/master/README.md Define an interface for your API calls, using annotations to specify request details. This example shows a GET request to the Amap API. ```java package com.yoursite.client; import com.dtflys.forest.annotation.Request; import com.dtflys.forest.annotation.DataParam; public interface AmapClient { /** * 聪明的你一定看出来了@Get注解代表该方法专做GET请求 * 在url中的{0}代表引用第一个参数,{1}引用第二个参数 */ @Get("http://ditu.amap.com/service/regeo?longitude={0}&latitude={1}") Map getLocation(String longitude, String latitude); } ``` -------------------------------- ### Generic Request Creation Example Source: https://github.com/dromara/forest/blob/master/_autodocs/01-core-api.md Example of creating an untyped ForestRequest object and executing it. ```java String response = Forest.request() .url("http://api.example.com/data") .execute(String.class); ``` -------------------------------- ### Handling JSON Response Example Source: https://github.com/dromara/forest/blob/master/_autodocs/04-response-api.md An example showing how to make a request and deserialize the JSON response directly into a User object. ```java ForestResponse response = Forest.get("http://api.example.com/users/1") .asyncExecute(User.class) .get(); User user = response.getResult(); System.out.println("Name: " + user.getName()); System.out.println("Email: " + user.getEmail()); ``` -------------------------------- ### Example: Simple Body Source: https://github.com/dromara/forest/blob/master/_autodocs/02-request-api.md Example of setting a simple string body for a POST request. ```java Forest.post("http://api.example.com/message") .body("Hello, World!") .execute(String.class); ``` -------------------------------- ### getHeaders Example Source: https://github.com/dromara/forest/blob/master/_autodocs/04-response-api.md Demonstrates how to access all response headers and iterate through them. ```java ForestHeaderMap headers = response.getHeaders(); headers.forEach((name, header) -> { System.out.println(name + ": " + header.getValue()); }); ``` -------------------------------- ### getHeaderValue Example Source: https://github.com/dromara/forest/blob/master/_autodocs/04-response-api.md Illustrates a simpler way to get just the value of a specific header by its name. ```java String contentType = response.getHeaderValue("Content-Type"); ``` -------------------------------- ### Example: JSON Body Source: https://github.com/dromara/forest/blob/master/_autodocs/02-request-api.md Example of setting a JSON body for a POST request. ```java User user = new User("John", "john@example.com"); Forest.post("http://api.example.com/users") .json(user) .execute(String.class); ``` -------------------------------- ### Typed Request Creation Example Source: https://github.com/dromara/forest/blob/master/_autodocs/01-core-api.md Example of creating a typed ForestRequest object and executing it. ```java ForestRequest request = Forest.request(User.class); User user = request.url("http://api.example.com/users/1").execute(); ``` -------------------------------- ### Example of Redirection Handling Source: https://github.com/dromara/forest/blob/master/_autodocs/04-response-api.md Demonstrates how to handle redirection by checking if the response is a redirect and then executing the redirection request. ```java if (response.isRedirection()) { ForestRequest nextRequest = response.redirectionRequest(); String nextContent = nextRequest.execute(String.class); } ``` -------------------------------- ### Example: Content Type Source: https://github.com/dromara/forest/blob/master/_autodocs/02-request-api.md Example of setting a custom content type for a POST request. ```java Forest.post("http://api.example.com/data") .contentType("application/json") .body("{\"key\": \"value\"}") .execute(String.class); ``` -------------------------------- ### Custom Retryer Example Source: https://github.com/dromara/forest/blob/master/_autodocs/10-advanced-features.md Provides an example of implementing a custom retryer by implementing the Retryer interface, including logic for determining if a retry is possible and calculating the wait time. ```java public class ExponentialBackoffRetryer implements Retryer { @Override public boolean canRetry(ForestRequest request, ForestResponse response) { return response.getStatusCode() >= 500; } @Override public long getRetryWaitTime(ForestRequest request, int retryCount) { // Exponential backoff: 1s, 2s, 4s, 8s, etc. return 1000L * (long) Math.pow(2, retryCount - 1); } } // Configure globally ForestConfiguration config = Forest.config(); config.setRetryer(ExponentialBackoffRetryer.class); ``` -------------------------------- ### getCookies Example Source: https://github.com/dromara/forest/blob/master/_autodocs/04-response-api.md Demonstrates how to access all response cookies and iterate through them. ```java ForestCookies cookies = response.getCookies(); cookies.forEach(cookie -> { System.out.println(cookie.getName() + "=" + cookie.getValue()); }); ``` -------------------------------- ### ForestRetryException Example Source: https://github.com/dromara/forest/blob/master/_autodocs/08-error-handling.md Example showing how to catch ForestRetryException, which is thrown when a request fails and retry is triggered. ```java try { String result = Forest.get("http://api.example.com/data") .maxRetryCount(3) .retryWhen((req, res) -> res.getStatusCode() >= 500) .execute(String.class); } catch (ForestRetryException e) { System.err.println("Request failed after retries: " + e.getMessage()); System.err.println("Retry count: " + e.getRetryCount()); } ``` -------------------------------- ### File Upload Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Upload a file using a POST request. ```java Map response = Forest.post("http://api.example.com/upload") .addFile("file", new File("document.pdf")) .execute(Map.class); ``` -------------------------------- ### Maven Dependency Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Add the Forest Spring Boot Starter dependency to your Maven project. ```xml com.dtflys.forest forest-spring-boot-starter 1.7.x ``` -------------------------------- ### Authentication Interceptor Example Source: https://github.com/dromara/forest/blob/master/_autodocs/07-interceptors-and-filters.md An example of an AuthenticationInterceptor that adds API keys, timestamps, and signatures to requests. ```java public class AuthenticationInterceptor implements Interceptor { private final String apiKey; public AuthenticationInterceptor(String apiKey) { this.apiKey = apiKey; } @Override public boolean beforeExecute(ForestRequest request) { // Add authentication header request.addHeader("X-API-Key", apiKey); // Add timestamp header request.addHeader("X-Timestamp", String.valueOf(System.currentTimeMillis())); // Calculate and add signature String signature = calculateSignature(request); request.addHeader("X-Signature", signature); return true; } @Override public void afterExecute(ForestRequest request, ForestResponse response) { // Check for authentication errors if (response.getStatusCode() == 401) { System.err.println("Authentication failed"); } } @Override public void onError(ForestException exception, ForestRequest request, ForestResponse response) {} @Override public void onSuccess(ForestRequest request, ForestResponse response) {} @Override public void afterFinally(ForestRequest request, ForestResponse response) {} private String calculateSignature(ForestRequest request) { // Implement signature calculation (e.g., HMAC-SHA256) return "calculated-signature"; } } ``` -------------------------------- ### SocketTimeoutException Example Source: https://github.com/dromara/forest/blob/master/_autodocs/08-error-handling.md Example for catching SocketTimeoutException, which occurs when a socket read operation times out. ```java try { String result = Forest.get("http://slow-api.example.com/data") .readTimeout(5, TimeUnit.SECONDS) .execute(String.class); } catch (SocketTimeoutException e) { System.err.println("Server response timeout"); } ``` -------------------------------- ### Spring Boot Configuration for DeepSeek Source: https://github.com/dromara/forest/blob/master/forest-examples/example-deepseek/README.md Configuration properties for the forest starter to connect to DeepSeek, including timeouts, base URL, API key, and model selection. ```yaml forest: connect-timeout: 10000 # HTTP请求连接超时时间 read-timeout: 3600000 # HTTP请求读取超时时间 variables: # 自定义变量: baseUrl: https://api.deepseek.com apiKey: YOUR_API_KEY # 你的 DeepSeek 的 API KEY model: deepseek-reasoner # DeepSeek 模型: deepseek-chat 或 deepseek-reasoner ``` -------------------------------- ### getHeader Example Source: https://github.com/dromara/forest/blob/master/_autodocs/04-response-api.md Shows how to retrieve a specific header by its name and access its value. ```java ForestHeader contentType = response.getHeader("Content-Type"); if (contentType != null) { System.out.println(contentType.getValue()); } ``` -------------------------------- ### ForestRuntimeException Example Source: https://github.com/dromara/forest/blob/master/_autodocs/08-error-handling.md Example demonstrating how to catch ForestRuntimeException, which is thrown for general runtime errors during request processing. ```java try { @ForestClient interface InvalidClient { @Get("{invalid-url-template}") // Missing parameter String getData(); } InvalidClient client = Forest.client(InvalidClient.class); client.getData(); } catch (ForestRuntimeException e) { System.err.println("Configuration error: " + e.getMessage()); } ``` -------------------------------- ### Example of Exception Handling Source: https://github.com/dromara/forest/blob/master/_autodocs/04-response-api.md Shows how to check for and print the stack trace of an exception if one occurred during the request. ```java if (response.getException() != null) { response.getException().printStackTrace(); } ``` -------------------------------- ### Batch Request Processing Example Source: https://github.com/dromara/forest/blob/master/_autodocs/10-advanced-features.md Shows how to process a batch of requests asynchronously and wait for all of them to complete using ForestFuture and Forest.await. ```java public class BatchRequestProcessor { public static List processBatch(List ids) { List futures = new ArrayList<>(); // Create async requests for all IDs for (String id : ids) { ForestFuture future = Forest.get("http://api.example.com/items/" + id) .asyncExecute(String.class); futures.add(future); } // Wait for all to complete List responses = Forest.await(futures); // Extract results List results = new ArrayList<>(); for (ForestResponse response : responses) { if (!response.isError()) { results.add(response.getContent()); } } return results; } } // Usage List ids = Arrays.asList("1", "2", "3", "4", "5"); List results = BatchRequestProcessor.processBatch(ids); ``` -------------------------------- ### Example: Form Data Source: https://github.com/dromara/forest/blob/master/_autodocs/02-request-api.md Example of adding form data fields for a POST request. ```java Forest.post("http://api.example.com/login") .addBody("username", "admin") .addBody("password", "secret123") .execute(String.class); ``` -------------------------------- ### File Download Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Define a Forest client interface for downloading files with specified directory and filename. ```java @ForestClient public interface FileApi { @Get("/files/{id}") @DownloadFile(dir = "/tmp", fileName = "{fileName}") File downloadFile( @PathVariable("id") String fileId, @DataVariable("fileName") String name ); } File downloadedFile = api.downloadFile("123", "document.pdf"); ``` -------------------------------- ### getTimeAsMillisecond Example Source: https://github.com/dromara/forest/blob/master/_autodocs/04-response-api.md Shows how to retrieve the total request and response time in milliseconds. ```java long duration = response.getTimeAsMillisecond(); System.out.println("Request took: " + duration + "ms"); ``` -------------------------------- ### Custom Filter Example Source: https://github.com/dromara/forest/blob/master/_autodocs/07-interceptors-and-filters.md An example of a custom filter that masks sensitive data in strings. ```java public class SensitiveDataFilter implements Filter { @Override public Object doFilter(Object obj) { if (obj instanceof String) { String str = (String) obj; // Mask sensitive patterns (credit cards, SSNs, etc.) str = str.replaceAll("\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}", "****-****-****-****"); str = str.replaceAll("\\d{3}-\\d{2}-\\d{4}", "***-**-****"); return str; } return obj; } } ``` -------------------------------- ### Batch File Upload (Map) Source: https://github.com/dromara/forest/blob/master/README.md Example of uploading a list of files wrapped in a Map, where `_key` represents the key in each map iteration. ```java /** * 上传Map包装的文件列表,其中 {_key} 代表Map中每一次迭代中的键值 */ @Post("/upload") ForestRequest uploadByteArrayMap(@DataFile(value = "file", fileName = "{_key}") Map byteArrayMap); ``` -------------------------------- ### Multiple Async Requests Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Execute multiple requests asynchronously and wait for all of them to complete. ```java ForestFuture f1 = Forest.get("http://api1.example.com").asyncExecute(String.class); ForestFuture f2 = Forest.get("http://api2.example.com").asyncExecute(String.class); ForestFuture f3 = Forest.get("http://api3.example.com").asyncExecute(String.class); List responses = Forest.await(f1, f2, f3); ``` -------------------------------- ### ForestAsyncAbortException Example Source: https://github.com/dromara/forest/blob/master/_autodocs/08-error-handling.md Example demonstrating how to catch ForestAsyncAbortException, which is thrown when an asynchronous request is aborted or cancelled. ```java ForestFuture future = Forest.get("http://api.example.com/data") .asyncExecute(String.class); future.cancel(); try { future.get(); // Will throw ForestAsyncAbortException } catch (ForestAsyncAbortException e) { System.out.println("Async request was cancelled"); } ``` -------------------------------- ### getResultOpt Example Source: https://github.com/dromara/forest/blob/master/_autodocs/04-response-api.md Illustrates using an Optional wrapper for the deserialized result, handling cases where the result might be absent. ```java response.getResultOpt().ifPresent(user -> { System.out.println(user.getName()); }); ``` -------------------------------- ### getByteArray Example Source: https://github.com/dromara/forest/blob/master/_autodocs/04-response-api.md Demonstrates retrieving the response body as a byte array and writing it to a file. ```java byte[] data = response.getByteArray(); Files.write(Paths.get("output.bin"), data); ``` -------------------------------- ### Global Configuration Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Access and modify global Forest configuration, including setting variables and adding interceptors. ```java ForestConfiguration config = Forest.config(); config.setMaxConnections(200); config.setConnectTimeout(10000); config.setReadTimeout(30000); config.setCharset("UTF-8"); config.setVariable("baseUrl", "http://api.example.com"); config.setVariable("apiKey", "sk-12345"); config.addInterceptor(new LoggingInterceptor()); config.addInterceptor(new AuthenticationInterceptor()); ``` -------------------------------- ### POST with JSON Body Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Send a POST request with a JSON request body. ```java User newUser = new User("John", "john@example.com"); User result = Forest.post("http://api.example.com/users") .json(newUser) .execute(User.class); ``` -------------------------------- ### Example: Character Encoding Source: https://github.com/dromara/forest/blob/master/_autodocs/02-request-api.md Example of setting character encoding for a POST request with Chinese content. ```java Forest.post("http://api.example.com/data") .charset("UTF-8") .body("Chinese content: 你好") .execute(String.class); ``` -------------------------------- ### Example of Deserialization Source: https://github.com/dromara/forest/blob/master/_autodocs/04-response-api.md Demonstrates deserializing a JSON response into a List of User objects using a TypeReference. ```java List users = response.getAs(new TypeReference>(){}.getType()); ``` -------------------------------- ### Creating Custom Interceptors Source: https://github.com/dromara/forest/blob/master/_autodocs/07-interceptors-and-filters.md An example of a custom LoggingInterceptor that logs request and response details. ```java public class LoggingInterceptor implements Interceptor { private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class); @Override public boolean beforeExecute(ForestRequest request) { logger.info(">>> REQUEST: {} {}", request.getType(), request.getUrl()); logger.info(" Headers: {}", request.getHeaders()); logger.info(" Body: {}", request.getBody()); return true; // Return false to cancel request } @Override public void afterExecute(ForestRequest request, ForestResponse response) { logger.info("<<< RESPONSE: {} {}", response.getStatusCode(), response.getReasonPhrase()); logger.info(" Headers: {}", response.getHeaders()); logger.info(" Time: {}ms", response.getTimeAsMillisecond()); } @Override public void onSuccess(ForestRequest request, ForestResponse response) { logger.info("SUCCESS: Response content length: {}", response.getContentLength()); } @Override public void onError(ForestException exception, ForestRequest request, ForestResponse response) { logger.error("ERROR: {}", exception.getMessage(), exception); } @Override public void afterFinally(ForestRequest request, ForestResponse response) { logger.debug("Request/Response lifecycle completed"); } } ``` -------------------------------- ### Registering Interceptors Globally Source: https://github.com/dromara/forest/blob/master/_autodocs/07-interceptors-and-filters.md Example of registering interceptors globally using ForestConfiguration. ```java ForestConfiguration config = Forest.config(); config.addInterceptor(new LoggingInterceptor()); config.addInterceptor(new AuthenticationInterceptor()); ``` -------------------------------- ### Named Event Handling Source: https://github.com/dromara/forest/blob/master/_autodocs/10-advanced-features.md Example showing how to handle specific named events from an SSE stream using onEvent callbacks. ```java ForestSSE sse = Forest.get("http://api.example.com/events") .asyncExecute() .sse(); sse.onEvent("user-login", message -> { System.out.println("User login: " + message); }) .onEvent("user-logout", message -> { System.out.println("User logout: " + message); }) .onEvent("notification", message -> { System.out.println("Notification: " + message); }) .start(); ``` -------------------------------- ### Response Deserialization Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Shows various ways to deserialize HTTP responses into different Java types. ```java // To specific type User user = Forest.get("http://api.example.com/users/1") .execute(User.class); // To generic type List users = Forest.get("http://api.example.com/users") .execute(new TypeReference>(){}.getType()); // To Map Map data = Forest.get("http://api.example.com/data") .execute(Map.class); // To String String json = Forest.get("http://api.example.com/data") .execute(String.class); ``` -------------------------------- ### Use Custom Annotation Source: https://github.com/dromara/forest/blob/master/_autodocs/07-interceptors-and-filters.md Example of using a custom RateLimit annotation on an interface method. ```java @ForestClient(baseUrl = "http://api.example.com") public interface ApiClient { @Get("/public") String getPublicData(); @Get("/premium") @RateLimit(maxPerSecond = 5, action = "WAIT") String getPremiumData(); @Post("/critical") @RateLimit(maxPerSecond = 1, action = "REJECT") String postCriticalData(@JSONBody Map data); } ``` -------------------------------- ### Define Lifecycle Handler Source: https://github.com/dromara/forest/blob/master/_autodocs/07-interceptors-and-filters.md Example of defining a lifecycle handler for rate limiting. ```java public class RateLimitLifeCycle implements MethodAnnotationLifeCycle { private static final RateLimiter limiter = RateLimiter.create(10.0); @Override public void onInvokeMethod(ForestRequest request, ForestMethod method, Object[] args) { // Called when method is invoked } @Override public boolean beforeExecute(ForestRequest request) { RateLimit annotation = getAttribute(request, "class-annotation", RateLimit.class); if (annotation != null) { double rate = annotation.maxPerSecond(); RateLimiter limiter = RateLimiter.create(rate); if (annotation.action().equals("WAIT")) { limiter.acquire(); return true; } else { if (!limiter.tryAcquire()) { throw new ForestRuntimeException("Rate limit exceeded"); } return true; } } return true; } @Override public void onMethodInitialized(ForestMethod method, RateLimit annotation) { // Called when method is first initialized } @Override public void afterExecute(ForestRequest request, ForestResponse response) {} @Override public void onError(ForestException exception, ForestRequest request, ForestResponse response) {} @Override public void onSuccess(ForestRequest request, ForestResponse response) {} @Override public void afterFinally(ForestRequest request, ForestResponse response) {} } ``` -------------------------------- ### Annotation Scanning Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Use the @ForestScan annotation to specify the base packages for Forest client interfaces. ```java @SpringBootApplication @ForestScan(basePackages = "com.example.api.client") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` -------------------------------- ### Async with Callbacks Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Handle asynchronous request results using success and error callbacks. ```java Forest.get("http://api.example.com/data") .onSuccess(response -> { System.out.println("Success: " + response.getContent()); }) .onError((ex, req, res) -> { System.err.println("Error: " + ex.getMessage()); }) .asyncExecute(String.class); ``` -------------------------------- ### SSE Request Configuration Source: https://github.com/dromara/forest/blob/master/_autodocs/10-advanced-features.md Example of configuring SSE requests using Forest client interfaces. ```java @ForestClient public interface StreamingApi { @Get("http://api.example.com/events") ForestSSE subscribeToEvents(); @Get("http://api.example.com/notifications") ForestSSE subscribeToNotifications(); } ``` -------------------------------- ### Retry Policy Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Configure a retry policy for requests that fail under certain conditions. ```java String result = Forest.get("http://api.example.com/data") .maxRetryCount(3) .retryWhen((req, res) -> res.getStatusCode() >= 500) .execute(String.class); ``` -------------------------------- ### Registering Interceptors Per-Client Source: https://github.com/dromara/forest/blob/master/_autodocs/07-interceptors-and-filters.md Example of registering interceptors per-client using the @ForestClient annotation. ```java @ForestClient( baseUrl = "http://api.example.com", interceptor = {LoggingInterceptor.class, AuthenticationInterceptor.class} ) public interface ApiClient { @Get("/data") String getData(); } ``` -------------------------------- ### File Upload Source: https://github.com/dromara/forest/blob/master/README.md Example of uploading a file using the `@DataFile` annotation and handling upload progress with an `OnProgress` callback. ```java /** * 用@DataFile注解修饰要上传的参数对象 * OnProgress参数为监听上传进度的回调函数 */ @Post("/upload") Map upload(@DataFile("file") String filePath, OnProgress onProgress); ``` -------------------------------- ### Define Custom Annotation Source: https://github.com/dromara/forest/blob/master/_autodocs/07-interceptors-and-filters.md Example of defining a custom annotation with a lifecycle handler. ```java @Documented @MethodLifeCycle(RateLimitLifeCycle.class) @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface RateLimit { /** * Maximum requests per second */ int maxPerSecond() default 10; /** * Action on rate limit hit: WAIT or REJECT */ String action() default "WAIT"; } ``` -------------------------------- ### Connection Timeout Configuration Source: https://github.com/dromara/forest/blob/master/_autodocs/05-configuration.md Methods to set and get the connection timeout in milliseconds. ```java public void setConnectTimeout(int timeout) ``` ```java public Integer getConnectTimeout() ``` -------------------------------- ### Built-in Retry Handler Example Source: https://github.com/dromara/forest/blob/master/_autodocs/10-advanced-features.md Demonstrates how to configure built-in retry logic for requests, including setting the maximum retry count and defining a custom retry condition. ```java Forest.get("http://api.example.com/data") .maxRetryCount(3) .retryWhen((req, res) -> { int code = res.getStatusCode(); // Retry on 5xx errors and timeouts return code >= 500 || code == 408; }) .onRetry((req, res) -> { System.out.println("Retrying after status: " + res.getStatusCode()); }) .execute(String.class); ``` -------------------------------- ### Load Balancing with Custom Address Source Source: https://github.com/dromara/forest/blob/master/_autodocs/10-advanced-features.md Provides an example of implementing a custom load balancing mechanism by cycling through a list of server addresses. ```java public class LoadBalancedApi { private static final List SERVERS = Arrays.asList( "http://api1.example.com", "http://api2.example.com", "http://api3.example.com" ); private static int currentIndex = 0; public String getData() { String address = getNextServer(); return Forest.get(address + "/data") .execute(String.class); } private synchronized String getNextServer() { String server = SERVERS.get(currentIndex); currentIndex = (currentIndex + 1) % SERVERS.size(); return server; } } ``` -------------------------------- ### Sending Protobuf Data Source: https://github.com/dromara/forest/blob/master/README.md Example of sending Protobuf data in the request body using `@ProtobufBody`. Requires Google Protobuf dependency. ```java /** * ProtobufProto.MyMessage 为 Protobuf 生成的数据类 * 将 Protobuf 生成的数据对象转换为 Protobuf 格式的字节流 * 并放在请求的Body进行传输 * * 注: 需要引入 google protobuf 依赖 */ @Post(url = "/message", contentType = "application/octet-stream") String sendProtobufMessage(@ProtobufBody ProtobufProto.MyMessage message); ``` -------------------------------- ### Interceptor Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Implements a logging interceptor to log requests and responses, and shows how to add it to the Forest configuration. ```java public class LoggingInterceptor implements Interceptor { @Override public boolean beforeExecute(ForestRequest request) { System.out.println(">>" + request.getType() + " " + request.getUrl()); return true; } @Override public void afterExecute(ForestRequest request, ForestResponse response) { System.out.println("<<" + response.getStatusCode()); } @Override public void onError(ForestException exception, ForestRequest request, ForestResponse response) {} @Override public void onSuccess(ForestRequest request, ForestResponse response) {} @Override public void afterFinally(ForestRequest request, ForestResponse response) {} } Forest.config().addInterceptor(new LoggingInterceptor()); ``` -------------------------------- ### Async Mode Configuration Source: https://github.com/dromara/forest/blob/master/_autodocs/05-configuration.md Methods to set and get the asynchronous execution mode (PLATFORM or REACTIVE). ```java public void setAsyncMode(ForestAsyncMode mode) ``` ```java public ForestAsyncMode getAsyncMode() ``` -------------------------------- ### Example of Closing Response Source: https://github.com/dromara/forest/blob/master/_autodocs/04-response-api.md Demonstrates the proper way to close a response using a try-finally block to ensure resources are released. ```java ForestResponse response = ...; try { String content = response.getContent(); } finally { response.close(); } ``` -------------------------------- ### Spring Boot Configuration Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Configure Forest properties in your Spring Boot application's application.yml or application.properties file. ```yaml forest: max-connections: 200 max-route-connections: 50 connect-timeout: 10000 read-timeout: 30000 charset: UTF-8 auto-redirection: true ``` -------------------------------- ### Typed Named Events Source: https://github.com/dromara/forest/blob/master/_autodocs/10-advanced-features.md Example demonstrating how to handle named SSE events with specific data types, parsing the event data into custom objects. ```java class LoginEvent { public String userId; public long timestamp; } class NotificationEvent { public String title; public String message; } ForestSSE sse = Forest.get("http://api.example.com/events") .asyncExecute() .sse(); sse.onEvent("login", event -> { LoginEvent login = JsonConverter.parse(event, LoginEvent.class); System.out.println("User logged in: " + login.userId); }, LoginEvent.class) .onEvent("notification", event -> { NotificationEvent notif = JsonConverter.parse(event, NotificationEvent.class); System.out.println(notif.title + ": " + notif.message); }, NotificationEvent.class) .start(); ``` -------------------------------- ### Connection Failure Handling Source: https://github.com/dromara/forest/blob/master/_autodocs/08-error-handling.md Provides an example of handling connection failures with retries and exponential backoff. ```java public static String fetchDataWithRetry(int maxRetries) { int attempts = 0; while (attempts < maxRetries) { try { return Forest.get("http://api.example.com/data") .execute(String.class); } catch (Exception e) { attempts++; if (attempts >= maxRetries) { System.err.println("Failed after " + maxRetries + " attempts"); throw e; } System.out.println("Attempt " + attempts + " failed, retrying..."); try { Thread.sleep(1000 * attempts); // Exponential backoff } catch (InterruptedException ie) { Thread.currentThread().interrupt(); break; } } } return null; } ``` -------------------------------- ### Error Handling Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Implement error handling for requests, including timeouts and general Forest exceptions. ```java try { String result = Forest.get("http://api.example.com/data") .timeout(5, TimeUnit.SECONDS) .execute(String.class); } catch (SocketTimeoutException e) { System.err.println("Request timeout"); } catch (ForestException e) { System.err.println("Forest error: " + e.getMessage()); } ``` -------------------------------- ### Async Queue Size Configuration Source: https://github.com/dromara/forest/blob/master/_autodocs/05-configuration.md Methods to set and get the maximum size of the asynchronous task queue. ```java public void setMaxAsyncQueueSize(int size) ``` ```java public Integer getMaxAsyncQueueSize() ``` -------------------------------- ### @Get Annotation Source: https://github.com/dromara/forest/blob/master/_autodocs/03-annotations.md Annotation for GET requests. ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @MethodLifeCycle(RequestLifeCycle.class) public @interface Get ``` -------------------------------- ### Conditional Requests Source: https://github.com/dromara/forest/blob/master/_autodocs/11-quick-reference.md Conditionally add parameters or modify requests based on certain conditions. ```java boolean includeDetails = true; String result = Forest.get("http://api.example.com/data") .cond(includeDetails, req -> { req.query("details", "true"); }) .execute(String.class); ``` -------------------------------- ### Using Filters Source: https://github.com/dromara/forest/blob/master/_autodocs/07-interceptors-and-filters.md Demonstrates how to register filters globally or use them in annotations. ```java // Register filter globally ForestConfiguration config = Forest.config(); config.addFilter(new SensitiveDataFilter()); // Use in annotations @JSONBody(filter = SensitiveDataFilter.class) void sendData(@JSONBody String data); ``` -------------------------------- ### Async Thread Size Configuration Source: https://github.com/dromara/forest/blob/master/_autodocs/05-configuration.md Methods to set and get the maximum size of the asynchronous thread pool. ```java public void setMaxAsyncThreadSize(int size) ``` ```java public Integer getMaxAsyncThreadSize() ```