diff --git a/examples/fit-example/07-http-client-proxy/plugin-http-client/pom.xml b/examples/fit-example/07-http-client-proxy/plugin-http-client/pom.xml
new file mode 100644
index 00000000..13995cff
--- /dev/null
+++ b/examples/fit-example/07-http-client-proxy/plugin-http-client/pom.xml
@@ -0,0 +1,75 @@
+
+
+ 4.0.0
+
+ org.fitframework.example
+ http-client
+ 1.0-SNAPSHOT
+
+
+ UTF-8
+ 17
+
+
+ 3.5.0-SNAPSHOT
+
+
+ 3.14.0
+
+
+
+
+ org.fitframework
+ fit-api
+ ${fit.version}
+
+
+ org.fitframework
+ fit-util
+ ${fit.version}
+
+
+ org.fitframework.service
+ fit-http-classic
+ ${fit.version}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven.compiler.version}
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+ -parameters
+
+
+
+
+ org.fitframework
+ fit-build-maven-plugin
+ ${fit.version}
+
+
+ build-plugin
+
+ build-plugin
+
+
+
+ package-plugin
+
+ package-plugin
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/client/TestInterface.java b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/client/TestInterface.java
new file mode 100644
index 00000000..dcb5b025
--- /dev/null
+++ b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/client/TestInterface.java
@@ -0,0 +1,77 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.example.client;
+
+import modelengine.fit.example.entity.Education;
+
+import java.util.List;
+
+/**
+ * This interface defines a set of methods for testing HTTP client proxy functionality.
+ * Each method corresponds to a specific HTTP request type and parameter binding scenario.
+ *
+ * @author 季聿阶
+ * @since 2025-06-01
+ */
+public interface TestInterface {
+ /**
+ * Tests request bean binding by sending an Education object in the request.
+ *
+ * @param education The Education object to be sent in the request.
+ * @return The modified Education object received in the response.
+ */
+ Education requestBean(Education education);
+
+ /**
+ * Tests path variable binding by extracting a path variable from the URL.
+ *
+ * @param variable The path variable extracted from the URL.
+ * @return A string containing the path variable value.
+ */
+ String pathVariable(String variable);
+
+ /**
+ * Tests header binding by extracting header values from the request.
+ *
+ * @param header The value of the "header" header.
+ * @param headers The list of values for the "headers" header.
+ * @return A string containing the header values.
+ */
+ String header(String header, List headers);
+
+ /**
+ * Tests cookie binding by extracting a cookie value from the request.
+ *
+ * @param cookieValue The value of the "cookie" cookie.
+ * @return A string containing the cookie value.
+ */
+ String cookie(String cookieValue);
+
+ /**
+ * Tests query parameter binding by extracting a query parameter from the request.
+ *
+ * @param query The value of the "query" query parameter.
+ * @return A string containing the query parameter value.
+ */
+ String query(String query);
+
+ /**
+ * Tests request body binding by extracting the request body content.
+ *
+ * @param requestBody The content of the request body.
+ * @return A string containing the request body content.
+ */
+ String requestBody(String requestBody);
+
+ /**
+ * Tests form data binding by extracting a form field value from the request.
+ *
+ * @param form The value of the "form" form field.
+ * @return A string containing the form field value.
+ */
+ String form(String form);
+}
\ No newline at end of file
diff --git a/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/client/TestRequestAddress.java b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/client/TestRequestAddress.java
new file mode 100644
index 00000000..93713457
--- /dev/null
+++ b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/client/TestRequestAddress.java
@@ -0,0 +1,69 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.example.client;
+
+import modelengine.fit.example.entity.Education;
+import modelengine.fit.http.annotation.GetMapping;
+import modelengine.fit.http.annotation.HttpProxy;
+import modelengine.fit.http.annotation.PatchMapping;
+import modelengine.fit.http.annotation.PathVariable;
+import modelengine.fit.http.annotation.PostMapping;
+import modelengine.fit.http.annotation.PutMapping;
+import modelengine.fit.http.annotation.RequestAddress;
+import modelengine.fit.http.annotation.RequestBean;
+import modelengine.fit.http.annotation.RequestBody;
+import modelengine.fit.http.annotation.RequestCookie;
+import modelengine.fit.http.annotation.RequestForm;
+import modelengine.fit.http.annotation.RequestHeader;
+import modelengine.fit.http.annotation.RequestMapping;
+import modelengine.fit.http.annotation.RequestQuery;
+
+import java.util.List;
+
+/**
+ * This interface defines a set of methods for testing HTTP client proxy functionality.
+ * It extends the TestInterface and provides specific annotations for configuring the HTTP request details.
+ * The interface is marked with @HttpProxy to indicate it's a proxy for HTTP requests.
+ * The @RequestAddress annotation specifies the base URL and port for the requests.
+ * The @RequestMapping annotation sets the base path for all methods in this interface.
+ *
+ * @author 季聿阶
+ * @since 2025-06-01
+ */
+@HttpProxy
+@RequestAddress(protocol = "http", host = "localhost", port = "8080")
+@RequestMapping(path = "/http-server")
+public interface TestRequestAddress extends TestInterface {
+ @Override
+ @PostMapping(path = "/request-bean")
+ Education requestBean(@RequestBean Education education);
+
+ @Override
+ @GetMapping(path = "/path-variable/{variable}")
+ String pathVariable(@PathVariable(name = "variable") String variable);
+
+ @Override
+ @GetMapping(path = "/header")
+ String header(@RequestHeader(name = "header") String header,
+ @RequestHeader(name = "headers") List headers);
+
+ @Override
+ @GetMapping(path = "/cookie")
+ String cookie(@RequestCookie(name = "cookie") String cookieValue);
+
+ @Override
+ @GetMapping(path = "/query")
+ String query(@RequestQuery(name = "query") String query);
+
+ @Override
+ @PatchMapping(path = "/request-body")
+ String requestBody(@RequestBody String requestBody);
+
+ @Override
+ @PutMapping(path = "/form")
+ String form(@RequestForm(name = "form") String form);
+}
\ No newline at end of file
diff --git a/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/client/TestRequestAddressClass.java b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/client/TestRequestAddressClass.java
new file mode 100644
index 00000000..00935134
--- /dev/null
+++ b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/client/TestRequestAddressClass.java
@@ -0,0 +1,70 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.example.client;
+
+import modelengine.fit.example.config.DefaultAddressLocator;
+import modelengine.fit.example.entity.Education;
+import modelengine.fit.http.annotation.GetMapping;
+import modelengine.fit.http.annotation.HttpProxy;
+import modelengine.fit.http.annotation.PatchMapping;
+import modelengine.fit.http.annotation.PathVariable;
+import modelengine.fit.http.annotation.PostMapping;
+import modelengine.fit.http.annotation.PutMapping;
+import modelengine.fit.http.annotation.RequestAddress;
+import modelengine.fit.http.annotation.RequestBean;
+import modelengine.fit.http.annotation.RequestBody;
+import modelengine.fit.http.annotation.RequestCookie;
+import modelengine.fit.http.annotation.RequestForm;
+import modelengine.fit.http.annotation.RequestHeader;
+import modelengine.fit.http.annotation.RequestMapping;
+import modelengine.fit.http.annotation.RequestQuery;
+
+import java.util.List;
+
+/**
+ * This interface defines a set of methods for testing HTTP client proxy functionality.
+ * It extends the TestInterface and provides specific annotations for configuring the HTTP request details.
+ * The interface is marked with @HttpProxy to indicate it's a proxy for HTTP requests.
+ * The @RequestAddress annotation specifies the address locator class for the requests.
+ * The @RequestMapping annotation sets the base path for all methods in this interface.
+ *
+ * @author 季聿阶
+ * @since 2025-06-01
+ */
+@HttpProxy
+@RequestAddress(address = DefaultAddressLocator.class)
+@RequestMapping(path = "/http-server")
+public interface TestRequestAddressClass extends TestInterface {
+ @Override
+ @PostMapping(path = "/request-bean")
+ Education requestBean(@RequestBean Education education);
+
+ @Override
+ @GetMapping(path = "/path-variable/{variable}")
+ String pathVariable(@PathVariable(name = "variable") String variable);
+
+ @Override
+ @GetMapping(path = "/header")
+ String header(@RequestHeader(name = "header") String header,
+ @RequestHeader(name = "headers") List headers);
+
+ @Override
+ @GetMapping(path = "/cookie")
+ String cookie(@RequestCookie(name = "cookie") String cookieValue);
+
+ @Override
+ @GetMapping(path = "/query")
+ String query(@RequestQuery(name = "query") String query);
+
+ @Override
+ @PatchMapping(path = "/request-body")
+ String requestBody(@RequestBody String requestBody);
+
+ @Override
+ @PutMapping(path = "/form")
+ String form(@RequestForm(name = "form") String form);
+}
diff --git a/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/client/TestRequestAddressInClassMapping.java b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/client/TestRequestAddressInClassMapping.java
new file mode 100644
index 00000000..b88b8b27
--- /dev/null
+++ b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/client/TestRequestAddressInClassMapping.java
@@ -0,0 +1,66 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.example.client;
+
+import modelengine.fit.example.entity.Education;
+import modelengine.fit.http.annotation.GetMapping;
+import modelengine.fit.http.annotation.HttpProxy;
+import modelengine.fit.http.annotation.PatchMapping;
+import modelengine.fit.http.annotation.PathVariable;
+import modelengine.fit.http.annotation.PostMapping;
+import modelengine.fit.http.annotation.PutMapping;
+import modelengine.fit.http.annotation.RequestBean;
+import modelengine.fit.http.annotation.RequestBody;
+import modelengine.fit.http.annotation.RequestCookie;
+import modelengine.fit.http.annotation.RequestForm;
+import modelengine.fit.http.annotation.RequestHeader;
+import modelengine.fit.http.annotation.RequestMapping;
+import modelengine.fit.http.annotation.RequestQuery;
+
+import java.util.List;
+
+/**
+ * This interface defines a set of methods for testing HTTP client proxy functionality.
+ * It extends the TestInterface and provides specific annotations for configuring the HTTP request details.
+ * The interface is marked with @HttpProxy to indicate it's a proxy for HTTP requests.
+ * The @RequestMapping annotation sets the base URL for all methods in this interface.
+ *
+ * @author 季聿阶
+ * @since 2025-06-01
+ */
+@HttpProxy
+@RequestMapping(path = "http://localhost:8080/http-server")
+public interface TestRequestAddressInClassMapping extends TestInterface {
+ @Override
+ @PostMapping(path = "/request-bean")
+ Education requestBean(@RequestBean Education education);
+
+ @Override
+ @GetMapping(path = "/path-variable/{variable}")
+ String pathVariable(@PathVariable(name = "variable") String variable);
+
+ @Override
+ @GetMapping(path = "/header")
+ String header(@RequestHeader(name = "header") String header,
+ @RequestHeader(name = "headers") List headers);
+
+ @Override
+ @GetMapping(path = "/cookie")
+ String cookie(@RequestCookie(name = "cookie") String cookieValue);
+
+ @Override
+ @GetMapping(path = "/query")
+ String query(@RequestQuery(name = "query") String query);
+
+ @Override
+ @PatchMapping(path = "/request-body")
+ String requestBody(@RequestBody String requestBody);
+
+ @Override
+ @PutMapping(path = "/form")
+ String form(@RequestForm(name = "form") String form);
+}
\ No newline at end of file
diff --git a/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/client/TestRequestAddressInMethodMapping.java b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/client/TestRequestAddressInMethodMapping.java
new file mode 100644
index 00000000..658b5074
--- /dev/null
+++ b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/client/TestRequestAddressInMethodMapping.java
@@ -0,0 +1,65 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.example.client;
+
+import modelengine.fit.example.entity.Education;
+import modelengine.fit.http.annotation.GetMapping;
+import modelengine.fit.http.annotation.HttpProxy;
+import modelengine.fit.http.annotation.PatchMapping;
+import modelengine.fit.http.annotation.PathVariable;
+import modelengine.fit.http.annotation.PostMapping;
+import modelengine.fit.http.annotation.PutMapping;
+import modelengine.fit.http.annotation.RequestBean;
+import modelengine.fit.http.annotation.RequestBody;
+import modelengine.fit.http.annotation.RequestCookie;
+import modelengine.fit.http.annotation.RequestForm;
+import modelengine.fit.http.annotation.RequestHeader;
+import modelengine.fit.http.annotation.RequestQuery;
+
+import java.util.List;
+
+/**
+ * This interface defines a set of methods for testing HTTP client proxy functionality.
+ * It extends the TestInterface and provides specific annotations for configuring the HTTP request details.
+ * The interface is marked with @HttpProxy to indicate it's a proxy for HTTP requests.
+ * Each method in this interface specifies the full URL for the HTTP request using the @GetMapping, @PostMapping, etc.
+ * annotations.
+ *
+ * @author 季聿阶
+ * @since 2025-06-01
+ */
+@HttpProxy
+public interface TestRequestAddressInMethodMapping extends TestInterface {
+ @Override
+ @PostMapping(path = "http://localhost:8080/http-server/request-bean")
+ Education requestBean(@RequestBean Education education);
+
+ @Override
+ @GetMapping(path = "http://localhost:8080/http-server/path-variable/{variable}")
+ String pathVariable(@PathVariable(name = "variable") String variable);
+
+ @Override
+ @GetMapping(path = "http://localhost:8080/http-server/header")
+ String header(@RequestHeader(name = "header") String header,
+ @RequestHeader(name = "headers") List headers);
+
+ @Override
+ @GetMapping(path = "http://localhost:8080/http-server/cookie")
+ String cookie(@RequestCookie(name = "cookie") String cookieValue);
+
+ @Override
+ @GetMapping(path = "http://localhost:8080/http-server/query")
+ String query(@RequestQuery(name = "query") String query);
+
+ @Override
+ @PatchMapping(path = "http://localhost:8080/http-server/request-body")
+ String requestBody(@RequestBody String requestBody);
+
+ @Override
+ @PutMapping(path = "http://localhost:8080/http-server/form")
+ String form(@RequestForm(name = "form") String form);
+}
\ No newline at end of file
diff --git a/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/config/DefaultAddressLocator.java b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/config/DefaultAddressLocator.java
new file mode 100644
index 00000000..c3636abc
--- /dev/null
+++ b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/config/DefaultAddressLocator.java
@@ -0,0 +1,31 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.example.config;
+
+import modelengine.fit.http.client.proxy.scanner.AddressLocator;
+import modelengine.fit.http.client.proxy.scanner.entity.Address;
+import modelengine.fitframework.annotation.Component;
+
+/**
+ * Provides a default implementation of the AddressLocator interface.
+ * This class is responsible for returning a default address configuration for HTTP requests.
+ * The default address includes the protocol (http), host (localhost), and port (8080).
+ *
+ * @author 季聿阶
+ * @since 2025-06-01
+ */
+@Component
+public class DefaultAddressLocator implements AddressLocator {
+ @Override
+ public Address address() {
+ Address address = new Address();
+ address.setProtocol("http");
+ address.setHost("localhost");
+ address.setPort(8080);
+ return address;
+ }
+}
\ No newline at end of file
diff --git a/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/controller/TestClientController.java b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/controller/TestClientController.java
new file mode 100644
index 00000000..11f4ea59
--- /dev/null
+++ b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/controller/TestClientController.java
@@ -0,0 +1,92 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.example.controller;
+
+import modelengine.fit.example.client.TestInterface;
+import modelengine.fit.example.client.TestRequestAddress;
+import modelengine.fit.example.client.TestRequestAddressClass;
+import modelengine.fit.example.client.TestRequestAddressInClassMapping;
+import modelengine.fit.example.client.TestRequestAddressInMethodMapping;
+import modelengine.fit.example.entity.Education;
+import modelengine.fit.http.annotation.GetMapping;
+import modelengine.fit.http.annotation.RequestMapping;
+import modelengine.fit.http.annotation.RequestQuery;
+import modelengine.fitframework.annotation.Component;
+
+import java.util.Arrays;
+
+/**
+ * Controller for handling HTTP client test operations.
+ * This class provides endpoints for testing various HTTP client proxy implementations.
+ *
+ * @author 季聿阶
+ * @since 2025-06-01
+ */
+@Component
+@RequestMapping(path = "/http-client")
+public class TestClientController {
+ private final TestRequestAddress t1;
+ private final TestRequestAddressClass t2;
+ private final TestRequestAddressInClassMapping t3;
+ private final TestRequestAddressInMethodMapping t4;
+
+ /**
+ * Constructs a TestClientController with the specified test interfaces.
+ *
+ * @param t1 The TestRequestAddress interface.
+ * @param t2 The TestRequestAddressClass interface.
+ * @param t3 The TestRequestAddressInClassMapping interface.
+ * @param t4 The TestRequestAddressInMethodMapping interface.
+ */
+ public TestClientController(TestRequestAddress t1, TestRequestAddressClass t2, TestRequestAddressInClassMapping t3,
+ TestRequestAddressInMethodMapping t4) {
+ this.t1 = t1;
+ this.t2 = t2;
+ this.t3 = t3;
+ this.t4 = t4;
+ }
+
+ /**
+ * Endpoint for running HTTP client tests.
+ * This method allows testing different HTTP client proxy implementations and methods.
+ *
+ * @param type The type of test interface to use (t1, t2, t3, or t4).
+ * @param method The method to invoke on the selected test interface.
+ * @return The result of the invoked method.
+ */
+ @GetMapping(path = "/test")
+ public Object test(@RequestQuery("type") String type, @RequestQuery("method") String method) {
+ TestInterface testClass = switch (type) {
+ case "t1" -> t1;
+ case "t2" -> t2;
+ case "t3" -> t3;
+ case "t4" -> t4;
+ default -> throw new IllegalArgumentException("Invalid type: " + type);
+ };
+ switch (method) {
+ case "requestBean":
+ Education education = new Education();
+ education.setBachelor("PKU");
+ education.setMaster("THU");
+ return testClass.requestBean(education);
+ case "pathVariable":
+ return testClass.pathVariable("variable");
+ case "header":
+ return testClass.header("header", Arrays.asList(1, 2, 3));
+ case "cookie":
+ return testClass.cookie("cookie");
+ case "query":
+ return testClass.query("query");
+ case "requestBody":
+ return testClass.requestBody("requestBody");
+ case "form":
+ return testClass.form("form");
+ default:
+ throw new IllegalArgumentException("Invalid method: " + method);
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/entity/Education.java b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/entity/Education.java
new file mode 100644
index 00000000..7eb39ffb
--- /dev/null
+++ b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/java/modelengine/fit/example/entity/Education.java
@@ -0,0 +1,72 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.example.entity;
+
+import modelengine.fit.http.annotation.RequestHeader;
+import modelengine.fitframework.annotation.Property;
+
+/**
+ * Represents educational information, including bachelor's and master's degrees.
+ * This class is used to encapsulate educational details and is annotated with {@link RequestHeader}
+ * to map specific fields to HTTP request headers.
+ *
+ * @author 季聿阶
+ * @since 2025-06-01
+ */
+public class Education {
+ /**
+ * Represents the bachelor's degree information.
+ * This field is mapped to the HTTP request header named "bachelor".
+ */
+ @Property(description = "Indicates the bachelor's degree", example = "PKU")
+ @RequestHeader(name = "bachelor")
+ private String bachelor;
+
+ /**
+ * Represents the master's degree information.
+ * This field is mapped to the HTTP request header named "master".
+ */
+ @Property(description = "Indicates the master's degree", example = "THU")
+ @RequestHeader(name = "master")
+ private String master;
+
+ /**
+ * Gets the bachelor's degree information.
+ *
+ * @return The bachelor's degree.
+ */
+ public String getBachelor() {
+ return this.bachelor;
+ }
+
+ /**
+ * Sets the bachelor's degree information.
+ *
+ * @param bachelor The bachelor's degree to set.
+ */
+ public void setBachelor(String bachelor) {
+ this.bachelor = bachelor;
+ }
+
+ /**
+ * Gets the master's degree information.
+ *
+ * @return The master's degree.
+ */
+ public String getMaster() {
+ return this.master;
+ }
+
+ /**
+ * Sets the master's degree information.
+ *
+ * @param master The master's degree to set.
+ */
+ public void setMaster(String master) {
+ this.master = master;
+ }
+}
diff --git a/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/resources/application.yml b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/resources/application.yml
new file mode 100644
index 00000000..c6f07dad
--- /dev/null
+++ b/examples/fit-example/07-http-client-proxy/plugin-http-client/src/main/resources/application.yml
@@ -0,0 +1,10 @@
+fit:
+ beans:
+ packages:
+ - 'modelengine.fit.example'
+
+http:
+ client:
+ interface:
+ package:
+ - 'modelengine.fit.example.client'
\ No newline at end of file
diff --git a/examples/fit-example/07-http-client-proxy/plugin-http-server/pom.xml b/examples/fit-example/07-http-client-proxy/plugin-http-server/pom.xml
new file mode 100644
index 00000000..4d89a11a
--- /dev/null
+++ b/examples/fit-example/07-http-client-proxy/plugin-http-server/pom.xml
@@ -0,0 +1,75 @@
+
+
+ 4.0.0
+
+ org.fitframework.example
+ http-server
+ 1.0-SNAPSHOT
+
+
+ UTF-8
+ 17
+
+
+ 3.5.0-SNAPSHOT
+
+
+ 3.14.0
+
+
+
+
+ org.fitframework
+ fit-api
+ ${fit.version}
+
+
+ org.fitframework
+ fit-util
+ ${fit.version}
+
+
+ org.fitframework.service
+ fit-http-classic
+ ${fit.version}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven.compiler.version}
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+ -parameters
+
+
+
+
+ org.fitframework
+ fit-build-maven-plugin
+ ${fit.version}
+
+
+ build-plugin
+
+ build-plugin
+
+
+
+ package-plugin
+
+ package-plugin
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/fit-example/07-http-client-proxy/plugin-http-server/src/main/java/modelengine/fit/example/controller/TestServerController.java b/examples/fit-example/07-http-client-proxy/plugin-http-server/src/main/java/modelengine/fit/example/controller/TestServerController.java
new file mode 100644
index 00000000..74fd7154
--- /dev/null
+++ b/examples/fit-example/07-http-client-proxy/plugin-http-server/src/main/java/modelengine/fit/example/controller/TestServerController.java
@@ -0,0 +1,122 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.example.controller;
+
+import modelengine.fit.example.entity.Education;
+import modelengine.fit.http.annotation.GetMapping;
+import modelengine.fit.http.annotation.PatchMapping;
+import modelengine.fit.http.annotation.PathVariable;
+import modelengine.fit.http.annotation.PostMapping;
+import modelengine.fit.http.annotation.PutMapping;
+import modelengine.fit.http.annotation.RequestBean;
+import modelengine.fit.http.annotation.RequestBody;
+import modelengine.fit.http.annotation.RequestCookie;
+import modelengine.fit.http.annotation.RequestForm;
+import modelengine.fit.http.annotation.RequestHeader;
+import modelengine.fit.http.annotation.RequestMapping;
+import modelengine.fit.http.annotation.RequestQuery;
+import modelengine.fitframework.annotation.Component;
+
+import java.util.List;
+
+/**
+ * Controller for handling HTTP requests related to test server operations.
+ * This class provides endpoints for testing various HTTP request types and parameter bindings.
+ *
+ * @author 季聿阶
+ * @since 2025-06-01
+ */
+@Component
+@RequestMapping(path = "/http-server")
+public class TestServerController {
+ /**
+ * Endpoint for testing request bean binding.
+ * This method receives an Education object as a request bean and modifies its master degree field.
+ *
+ * @param education The Education object received in the request.
+ * @return The modified Education object.
+ */
+ @PostMapping(path = "/request-bean")
+ public Education requestBean(@RequestBean Education education) {
+ education.setMaster("SJTU");
+ return education;
+ }
+
+ /**
+ * Endpoint for testing path variable binding.
+ * This method retrieves a path variable from the URL and returns it in a response.
+ *
+ * @param variable The path variable extracted from the URL.
+ * @return A string containing the path variable value.
+ */
+ @GetMapping(path = "/path-variable/{variable}")
+ public String pathVariable(@PathVariable(name = "variable") String variable) {
+ return "PathVariable: " + variable;
+ }
+
+ /**
+ * Endpoint for testing header binding.
+ * This method retrieves header values from the request and returns them in a response.
+ *
+ * @param header The value of the "header" header.
+ * @param headers The list of values for the "headers" header.
+ * @return A string containing the header values.
+ */
+ @GetMapping(path = "/header")
+ public String header(@RequestHeader(name = "header") String header,
+ @RequestHeader(name = "headers") List headers) {
+ return "Header: " + header + ", Headers: " + headers;
+ }
+
+ /**
+ * Endpoint for testing cookie binding.
+ * This method retrieves a cookie value from the request and returns it in a response.
+ *
+ * @param cookieValue The value of the "cookie" cookie.
+ * @return A string containing the cookie value.
+ */
+ @GetMapping(path = "/cookie")
+ public String cookie(@RequestCookie(name = "cookie") String cookieValue) {
+ return "Cookie: " + cookieValue;
+ }
+
+ /**
+ * Endpoint for testing query parameter binding.
+ * This method retrieves a query parameter from the request and returns it in a response.
+ *
+ * @param query The value of the "query" query parameter.
+ * @return A string containing the query parameter value.
+ */
+ @GetMapping(path = "/query")
+ public String query(@RequestQuery(name = "query") String query) {
+ return "Query: " + query;
+ }
+
+ /**
+ * Endpoint for testing request body binding.
+ * This method retrieves the request body as a string and returns it in a response.
+ *
+ * @param requestBody The content of the request body.
+ * @return A string containing the request body content.
+ */
+ @PatchMapping(path = "/request-body")
+ public String requestBody(@RequestBody String requestBody) {
+ return "RequestBody: " + requestBody;
+ }
+
+ /**
+ * Endpoint for testing form data binding.
+ * This method retrieves a form field value from the request and returns it in a response.
+ *
+ * @param form The value of the "form" form field.
+ * @return A string containing the form field value.
+ */
+ @PutMapping(path = "/form")
+ public String form(@RequestForm(name = "form") String form) {
+ return "Form: " + form;
+ }
+}
\ No newline at end of file
diff --git a/examples/fit-example/07-http-client-proxy/plugin-http-server/src/main/java/modelengine/fit/example/entity/Education.java b/examples/fit-example/07-http-client-proxy/plugin-http-server/src/main/java/modelengine/fit/example/entity/Education.java
new file mode 100644
index 00000000..7eb39ffb
--- /dev/null
+++ b/examples/fit-example/07-http-client-proxy/plugin-http-server/src/main/java/modelengine/fit/example/entity/Education.java
@@ -0,0 +1,72 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.example.entity;
+
+import modelengine.fit.http.annotation.RequestHeader;
+import modelengine.fitframework.annotation.Property;
+
+/**
+ * Represents educational information, including bachelor's and master's degrees.
+ * This class is used to encapsulate educational details and is annotated with {@link RequestHeader}
+ * to map specific fields to HTTP request headers.
+ *
+ * @author 季聿阶
+ * @since 2025-06-01
+ */
+public class Education {
+ /**
+ * Represents the bachelor's degree information.
+ * This field is mapped to the HTTP request header named "bachelor".
+ */
+ @Property(description = "Indicates the bachelor's degree", example = "PKU")
+ @RequestHeader(name = "bachelor")
+ private String bachelor;
+
+ /**
+ * Represents the master's degree information.
+ * This field is mapped to the HTTP request header named "master".
+ */
+ @Property(description = "Indicates the master's degree", example = "THU")
+ @RequestHeader(name = "master")
+ private String master;
+
+ /**
+ * Gets the bachelor's degree information.
+ *
+ * @return The bachelor's degree.
+ */
+ public String getBachelor() {
+ return this.bachelor;
+ }
+
+ /**
+ * Sets the bachelor's degree information.
+ *
+ * @param bachelor The bachelor's degree to set.
+ */
+ public void setBachelor(String bachelor) {
+ this.bachelor = bachelor;
+ }
+
+ /**
+ * Gets the master's degree information.
+ *
+ * @return The master's degree.
+ */
+ public String getMaster() {
+ return this.master;
+ }
+
+ /**
+ * Sets the master's degree information.
+ *
+ * @param master The master's degree to set.
+ */
+ public void setMaster(String master) {
+ this.master = master;
+ }
+}
diff --git a/examples/fit-example/07-http-client-proxy/plugin-http-server/src/main/resources/application.yml b/examples/fit-example/07-http-client-proxy/plugin-http-server/src/main/resources/application.yml
new file mode 100644
index 00000000..13c4081e
--- /dev/null
+++ b/examples/fit-example/07-http-client-proxy/plugin-http-server/src/main/resources/application.yml
@@ -0,0 +1,4 @@
+fit:
+ beans:
+ packages:
+ - 'modelengine.fit.example'
\ No newline at end of file
diff --git a/examples/fit-example/07-http-client-proxy/pom.xml b/examples/fit-example/07-http-client-proxy/pom.xml
new file mode 100644
index 00000000..a8cc9135
--- /dev/null
+++ b/examples/fit-example/07-http-client-proxy/pom.xml
@@ -0,0 +1,15 @@
+
+
+ 4.0.0
+
+ org.fitframework.example
+ http-client-proxy
+ 1.0-SNAPSHOT
+ pom
+
+
+ plugin-http-client
+ plugin-http-server
+
+
\ No newline at end of file
diff --git a/examples/fit-example/pom.xml b/examples/fit-example/pom.xml
index 33ffafe9..769be155 100644
--- a/examples/fit-example/pom.xml
+++ b/examples/fit-example/pom.xml
@@ -15,5 +15,6 @@
04-complicated-apps
05-aop-log-plugin
06-spring-boot-starter
+ 07-http-client-proxy
diff --git a/framework/fit/java/fit-builtin/plugins/fit-client-http/src/main/java/modelengine/fit/client/http/support/HttpProxyCreator.java b/framework/fit/java/fit-builtin/plugins/fit-client-http/src/main/java/modelengine/fit/client/http/support/HttpProxyCreator.java
new file mode 100644
index 00000000..8dda7d05
--- /dev/null
+++ b/framework/fit/java/fit-builtin/plugins/fit-client-http/src/main/java/modelengine/fit/client/http/support/HttpProxyCreator.java
@@ -0,0 +1,100 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.client.http.support;
+
+import static modelengine.fitframework.inspection.Validation.notNull;
+
+import modelengine.fit.http.annotation.HttpProxy;
+import modelengine.fit.http.client.HttpClassicClientFactory;
+import modelengine.fit.http.client.proxy.scanner.AnnotationParser;
+import modelengine.fit.http.client.proxy.scanner.HttpInvocationHandler;
+import modelengine.fit.http.client.proxy.scanner.entity.HttpInfo;
+import modelengine.fitframework.annotation.Component;
+import modelengine.fitframework.annotation.Order;
+import modelengine.fitframework.conf.Config;
+import modelengine.fitframework.ioc.BeanContainer;
+import modelengine.fitframework.ioc.lifecycle.container.BeanContainerInitializedObserver;
+import modelengine.fitframework.jvm.scan.PackageScanner;
+import modelengine.fitframework.plugin.Plugin;
+import modelengine.fitframework.util.StringUtils;
+import modelengine.fitframework.value.ValueFetcher;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Creates HTTP proxy objects for interfaces annotated with {@link HttpProxy}.
+ * This class implements the {@link BeanContainerInitializedObserver} interface and is responsible for
+ * scanning packages for interfaces annotated with {@link HttpProxy}, parsing their annotations,
+ * and creating proxy objects that can be used to make HTTP requests.
+ *
+ * @author 王攀博
+ * @author 季聿阶
+ * @since 2025-05-31
+ */
+@Component
+@Order(Order.NEARLY_HIGH)
+public class HttpProxyCreator implements BeanContainerInitializedObserver {
+ private static final String CONFIG_PREFIX = "http.client.interface.package";
+
+ private final HttpClassicClientFactory factory;
+ private final ValueFetcher valueFetcher;
+
+ /**
+ * Constructs an HttpProxyCreator with the specified HTTP client factory and value fetcher.
+ *
+ * @param factory The HTTP client factory used to create HTTP clients.
+ * @param valueFetcher The value fetcher used to fetch values for property setters.
+ */
+ public HttpProxyCreator(HttpClassicClientFactory factory, ValueFetcher valueFetcher) {
+ this.factory = notNull(factory, "The http classic client factory cannot be null.");
+ this.valueFetcher = notNull(valueFetcher, "The value fetcher cannot be null.");
+ }
+
+ @Override
+ public void onBeanContainerInitialized(BeanContainer container) {
+ Config config = container.beans().get(Config.class);
+ List packages = this.packages(config);
+ if (packages.isEmpty()) {
+ return;
+ }
+ List> classes = this.scan(container, packages);
+ for (Class> clazz : classes) {
+ AnnotationParser annotationParser = new AnnotationParser(this.valueFetcher);
+ Map httpInfoMap = annotationParser.parseInterface(clazz);
+ // Scan all interfaces, create proxy objects for each, and register them in the container.
+ container.registry()
+ .register(Proxy.newProxyInstance(clazz.getClassLoader(),
+ new Class[] {clazz},
+ new HttpInvocationHandler(httpInfoMap, container, this.factory)));
+ }
+ }
+
+ private List> scan(BeanContainer container, List packages) {
+ List> interfaceClasses = new ArrayList<>();
+ if (packages != null) {
+ Plugin plugin = container.beans().get(Plugin.class);
+ PackageScanner.forClassLoader(plugin.pluginClassLoader(), (scanner, clazz) -> {
+ if (clazz.isInterface() && clazz.isAnnotationPresent(HttpProxy.class)) {
+ interfaceClasses.add(clazz);
+ }
+ }).scan(packages);
+ }
+ return interfaceClasses;
+ }
+
+ private List packages(Config config) {
+ String value = config.get(CONFIG_PREFIX, String.class);
+ if (StringUtils.isNotBlank(value)) {
+ return StringUtils.splitToList(value, ",");
+ }
+ return new ArrayList<>();
+ }
+}
\ No newline at end of file
diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/annotation/HttpProxy.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/annotation/HttpProxy.java
new file mode 100644
index 00000000..05141e83
--- /dev/null
+++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/annotation/HttpProxy.java
@@ -0,0 +1,27 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.http.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks an interface as a client proxy for HTTP requests.
+ * This annotation is used to indicate that an interface should be treated as a proxy for making HTTP requests.
+ * Interfaces annotated with {@code @HttpProxy} will be processed by the framework to generate dynamic proxy objects
+ * that can be used to invoke HTTP endpoints.
+ *
+ * @author 王攀博
+ * @since 2025-01-13
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface HttpProxy {}
\ No newline at end of file
diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/annotation/RequestAddress.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/annotation/RequestAddress.java
new file mode 100644
index 00000000..eed8f9b0
--- /dev/null
+++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/annotation/RequestAddress.java
@@ -0,0 +1,72 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.http.annotation;
+
+import modelengine.fit.http.client.proxy.scanner.AddressLocator;
+import modelengine.fitframework.annotation.Forward;
+import modelengine.fitframework.util.StringUtils;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Defines the address information for HTTP requests.
+ * This annotation is used to specify the protocol, host, port, and address locator for an HTTP request.
+ * It can be applied to interfaces annotated with {@link HttpProxy} to configure the base URL and other connection
+ * details.
+ *
+ * @author 王攀博
+ * @since 2025-01-24
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface RequestAddress {
+ /**
+ * Specifies the class used to locate the address dynamically.
+ * This property is optional and defaults to {@link AddressLocator}.
+ *
+ * @return The class used to locate the address.
+ */
+ @Forward(annotation = RequestAddress.class,
+ property = "source") Class extends AddressLocator> value() default AddressLocator.class;
+
+ /**
+ * Specifies the protocol for the HTTP request.
+ * This property is optional and defaults to an empty string.
+ *
+ * @return The protocol for the HTTP request.
+ */
+ String protocol() default StringUtils.EMPTY;
+
+ /**
+ * Specifies the host for the HTTP request.
+ * This property is optional and defaults to an empty string.
+ *
+ * @return The host for the HTTP request.
+ */
+ String host() default StringUtils.EMPTY;
+
+ /**
+ * Specifies the port for the HTTP request.
+ * This property is optional and defaults to an empty string.
+ *
+ * @return The port for the HTTP request.
+ */
+ String port() default StringUtils.EMPTY;
+
+ /**
+ * Specifies the class used to locate the address dynamically.
+ * This property is optional and defaults to {@link AddressLocator}.
+ *
+ * @return The class used to locate the address.
+ */
+ Class extends AddressLocator> address() default AddressLocator.class;
+}
\ No newline at end of file
diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/annotation/RequestAuthorization.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/annotation/RequestAuthorization.java
new file mode 100644
index 00000000..3b9a5e81
--- /dev/null
+++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/annotation/RequestAuthorization.java
@@ -0,0 +1,27 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.http.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Defines the authorization information for HTTP requests.
+ * This annotation is used to specify the authentication details for an HTTP request.
+ * It can be applied to methods annotated with HTTP mapping annotations (e.g., @GetMapping, @PostMapping)
+ * to configure the authorization headers or tokens required for the request.
+ *
+ * @author 王攀博
+ * @since 2025-01-24
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface RequestAuthorization {}
\ No newline at end of file
diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/RequestBuilder.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/RequestBuilder.java
index 3ee603d4..acf26b00 100644
--- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/RequestBuilder.java
+++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/RequestBuilder.java
@@ -13,144 +13,160 @@
import modelengine.fit.http.protocol.HttpRequestMethod;
/**
- * 表示 Http 请求提供建造者。
+ * Represents a builder for HTTP requests.
*
* @author 王攀博
* @since 2024-06-08
*/
public interface RequestBuilder {
/**
- * 设置 Http 客户端。
+ * Sets the HTTP client.
*
- * @param httpClassicClient 表示测试需要的客户端。
- * @return 表示客户端请求参数的建造者 {@link RequestBuilder}。
+ * @param httpClassicClient The HTTP client to be used.
+ * @return The builder for HTTP request parameters {@link RequestBuilder}.
*/
RequestBuilder client(HttpClassicClient httpClassicClient);
/**
- * 设置客户端请协议。
+ * Sets the HTTP request method.
*
- * @param method 表示客户端请求的协议 {@link HttpRequestMethod}。
- * @return 表示客户端请求参数的建造者 {@link RequestBuilder}。
+ * @param method The HTTP request method {@link HttpRequestMethod}.
+ * @return The builder for HTTP request parameters {@link RequestBuilder}.
*/
RequestBuilder method(HttpRequestMethod method);
/**
- * 设置客户端请协议。
+ * Sets the protocol for the HTTP request.
*
- * @param protocol 表示客户端请求的协议 {@link String}。
- * @return 表示客户端请求参数的建造者 {@link RequestBuilder}。
+ * @param protocol The protocol for the HTTP request {@link String}.
+ * @return The builder for HTTP request parameters {@link RequestBuilder}.
*/
RequestBuilder protocol(String protocol);
/**
- * 设置客户端请求域名。
+ * Sets the domain for the HTTP request.
*
- * @param domain 表示客户端请求的域名 {@link String}。
- * @return 表示客户端请求参数的建造者 {@link RequestBuilder}。
+ * @param domain The domain for the HTTP request {@link String}.
+ * @return The builder for HTTP request parameters {@link RequestBuilder}.
*/
RequestBuilder domain(String domain);
/**
- * 设置客户端请求模板。
+ * Sets the host for the HTTP request.
*
- * @param pathPattern 表示客户端请求的路径模板的 {@link String}。
- * @return 表示客户端请求参数的建造者 {@link RequestBuilder}。
+ * @param host The host for the HTTP request {@link String}.
+ * @return The builder for HTTP request parameters {@link RequestBuilder}.
+ */
+ RequestBuilder host(String host);
+
+ /**
+ * Sets the port for the HTTP request.
+ *
+ * @param port The port for the HTTP request {@link int}.
+ * @return The builder for HTTP request parameters {@link RequestBuilder}.
+ */
+ RequestBuilder port(int port);
+
+ /**
+ * Sets the path pattern for the HTTP request.
+ *
+ * @param pathPattern The path pattern for the HTTP request {@link String}.
+ * @return The builder for HTTP request parameters {@link RequestBuilder}.
*/
RequestBuilder pathPattern(String pathPattern);
/**
- * 设置客户端请求路径段。
+ * Sets the path variable for the HTTP request.
*
- * @param key 表示客户端请求的路径变量的 {@link String}。
- * @param pathVariable 表示客户端请求的路径变量的值的 {@link String}。
- * @return 表示客户端请求参数的建造者 {@link RequestBuilder}。
+ * @param key The key for the path variable {@link String}.
+ * @param pathVariable The value for the path variable {@link String}.
+ * @return The builder for HTTP request parameters {@link RequestBuilder}.
*/
RequestBuilder pathVariable(String key, String pathVariable);
/**
- * 为请求插件结构体添加键值对参数。
+ * Adds a key-value pair to the query parameters of the HTTP request.
*
- * @param key 表示请求体内请求参数的键的 {@link String}。
- * @param value 表示请求体内请求参数的值的 {@link String}。
- * @return 表示客户端请求参数的建造者 {@link RequestBuilder}。
+ * @param key The key for the query parameter {@link String}.
+ * @param value The value for the query parameter {@link String}.
+ * @return The builder for HTTP request parameters {@link RequestBuilder}.
*/
RequestBuilder query(String key, String value);
/**
- * 设置请求结构体的消息头。
+ * Sets the header for the HTTP request.
*
- * @param name 表示待设置的消息头的名字的 {@link String}。
- * @param header 表示待设置的消息头内容的 {@link String}。
- * @return 表示客户端请求参数的建造者 {@link RequestBuilder}。
+ * @param name The name of the header {@link String}.
+ * @param header The content of the header {@link String}.
+ * @return The builder for HTTP request parameters {@link RequestBuilder}.
*/
RequestBuilder header(String name, String header);
/**
- * 设置请求结构体的 Cookie。
+ * Sets the cookie for the HTTP request.
*
- * @param key 表示待设置的 Cookie 的键的 {@link String}。
- * @param value 表示待设置的 Cookie 的值的 {@link String}。
- * @return 表示客户端请求参数的建造者 {@link RequestBuilder}。
+ * @param key The key for the cookie {@link String}.
+ * @param value The value for the cookie {@link String}.
+ * @return The builder for HTTP request parameters {@link RequestBuilder}.
*/
RequestBuilder cookie(String key, String value);
/**
- * 设置请求结构体的消息体内容。
+ * Sets the entity (body content) for the HTTP request.
*
- * @param entity 表示 Http 请求的消息体内容的 {@link Entity}。
- * @return 表示客户端请求参数的建造者 {@link RequestBuilder}。
+ * @param entity The entity (body content) for the HTTP request {@link Entity}.
+ * @return The builder for HTTP request parameters {@link RequestBuilder}.
*/
RequestBuilder entity(Entity entity);
/**
- * 设置 Http 请求的 Form 格式的消息体内容。
+ * Sets the form entity (body content) for the HTTP request.
*
- * @param key 表示 Http 请求的 Form 格式的消息体内容键值对键的 {@link String}。
- * @param value 表示 Http 请求的 Form 格式的消息体内容键值对值的 {@link String}。
- * @return 表示客户端请求参数的建造者 {@link RequestBuilder}。
+ * @param key The key for the form entity {@link String}.
+ * @param value The value for the form entity {@link String}.
+ * @return The builder for HTTP request parameters {@link RequestBuilder}.
*/
RequestBuilder formEntity(String key, String value);
/**
- * 设置 Http 请求的 Json 格式的消息体内容。
+ * Sets the JSON entity (body content) for the HTTP request.
*
- * @param propertyValuePath 表示 Http 请求的 json 格式的消息体内容属性路径的 {@link String}。
- * @param value 表示 Http 请求的消息体内容属性值的 {@link Object}。
- * @return 表示客户端请求参数的建造者 {@link RequestBuilder}。
+ * @param propertyValuePath The property path for the JSON entity {@link String}.
+ * @param value The value for the JSON entity {@link Object}.
+ * @return The builder for HTTP request parameters {@link RequestBuilder}.
*/
RequestBuilder jsonEntity(String propertyValuePath, Object value);
/**
- * 设置 Http 请求的鉴权类型。
+ * Sets the authorization type for the HTTP request.
*
- * @param authorization 表示 Http 请求的鉴权信息结构的 {@link Authorization}。
- * @return 表示客户端请求参数的建造者 {@link RequestBuilder}。
+ * @param authorization The authorization information for the HTTP request {@link Authorization}.
+ * @return The builder for HTTP request parameters {@link RequestBuilder}.
*/
RequestBuilder authorization(Authorization authorization);
/**
- * 设置 Http 请求的鉴权信息。
+ * Sets the authorization information for the HTTP request.
*
- * @param key 表示 Http 鉴权信息的参数键值的 {@link String}。
- * @param value 表示鉴权信息的值的 {@link Object}。
- * @return 表示客户端请求参数的建造者 {@link RequestBuilder}。
+ * @param key The key for the authorization information {@link String}.
+ * @param value The value for the authorization information {@link Object}.
+ * @return The builder for HTTP request parameters {@link RequestBuilder}.
*/
RequestBuilder authorizationInfo(String key, Object value);
/**
- * 构建客户端的请求参数。
+ * Builds the HTTP request parameters.
*
- * @return 表示返回构建完成的客户端的请求参数 {@link HttpClassicClientRequest}。
+ * @return The built HTTP request parameters {@link HttpClassicClientRequest}.
*/
HttpClassicClientRequest build();
/**
- * 创建请求构建器。
+ * Creates a new instance of the request builder.
*
- * @return 表示创建出的请求构建器的 {@link RequestBuilder}。
+ * @return A new instance of the request builder {@link RequestBuilder}.
*/
static RequestBuilder create() {
return new DefaultRequestBuilder();
}
-}
+}
\ No newline at end of file
diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/AddressLocator.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/AddressLocator.java
new file mode 100644
index 00000000..f9d72149
--- /dev/null
+++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/AddressLocator.java
@@ -0,0 +1,26 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.http.client.proxy.scanner;
+
+import modelengine.fit.http.client.proxy.scanner.entity.Address;
+
+/**
+ * Defines a contract for locating and providing address information for HTTP requests.
+ * Implementations of this interface are responsible for returning an {@link Address} object
+ * that contains details such as protocol, host, port, and locator class.
+ *
+ * @author 王攀博
+ * @since 2025-01-24
+ */
+public interface AddressLocator {
+ /**
+ * Retrieves the address information for an HTTP request.
+ *
+ * @return The address information as an {@link Address} object.
+ */
+ Address address();
+}
\ No newline at end of file
diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/AnnotationParser.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/AnnotationParser.java
new file mode 100644
index 00000000..8704672e
--- /dev/null
+++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/AnnotationParser.java
@@ -0,0 +1,194 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.http.client.proxy.scanner;
+
+import static modelengine.fitframework.inspection.Validation.notNull;
+
+import modelengine.fit.http.annotation.DeleteMapping;
+import modelengine.fit.http.annotation.GetMapping;
+import modelengine.fit.http.annotation.PatchMapping;
+import modelengine.fit.http.annotation.PathVariable;
+import modelengine.fit.http.annotation.PostMapping;
+import modelengine.fit.http.annotation.PutMapping;
+import modelengine.fit.http.annotation.RequestAddress;
+import modelengine.fit.http.annotation.RequestBean;
+import modelengine.fit.http.annotation.RequestBody;
+import modelengine.fit.http.annotation.RequestCookie;
+import modelengine.fit.http.annotation.RequestForm;
+import modelengine.fit.http.annotation.RequestHeader;
+import modelengine.fit.http.annotation.RequestMapping;
+import modelengine.fit.http.annotation.RequestQuery;
+import modelengine.fit.http.client.proxy.PropertyValueApplier;
+import modelengine.fit.http.client.proxy.scanner.entity.Address;
+import modelengine.fit.http.client.proxy.scanner.entity.HttpInfo;
+import modelengine.fit.http.client.proxy.scanner.resolver.PathVariableResolver;
+import modelengine.fit.http.client.proxy.scanner.resolver.RequestBodyResolver;
+import modelengine.fit.http.client.proxy.scanner.resolver.RequestCookieResolver;
+import modelengine.fit.http.client.proxy.scanner.resolver.RequestFormResolver;
+import modelengine.fit.http.client.proxy.scanner.resolver.RequestHeaderResolver;
+import modelengine.fit.http.client.proxy.scanner.resolver.RequestQueryResolver;
+import modelengine.fit.http.client.proxy.support.applier.MultiDestinationsPropertyValueApplier;
+import modelengine.fit.http.client.proxy.support.setter.DestinationSetterInfo;
+import modelengine.fitframework.util.ArrayUtils;
+import modelengine.fitframework.util.ReflectionUtils;
+import modelengine.fitframework.util.StringUtils;
+import modelengine.fitframework.value.ValueFetcher;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Parses annotations on interfaces and methods to extract HTTP-related information.
+ * This class is responsible for interpreting annotations such as @RequestMapping, @GetMapping, @PostMapping, etc.,
+ * and converting them into structured data that can be used to build HTTP requests.
+ *
+ * @author 王攀博
+ * @since 2025-01-07
+ */
+public class AnnotationParser {
+ private static final int MAX_PATH_SIZE = 1;
+ private static final String KEY_OF_METHOD_PATH = "path";
+ private static final Set> mappingMethodAnnotations =
+ Stream.of(PostMapping.class, PutMapping.class, GetMapping.class, DeleteMapping.class, PatchMapping.class)
+ .collect(Collectors.toSet());
+ private static final Map, ParamResolver> annotationParsers = new HashMap<>();
+
+ static {
+ annotationParsers.put(RequestQuery.class, new RequestQueryResolver());
+ annotationParsers.put(RequestHeader.class, new RequestHeaderResolver());
+ annotationParsers.put(RequestCookie.class, new RequestCookieResolver());
+ annotationParsers.put(RequestBody.class, new RequestBodyResolver());
+ annotationParsers.put(RequestForm.class, new RequestFormResolver());
+ annotationParsers.put(PathVariable.class, new PathVariableResolver());
+ }
+
+ private final ValueFetcher valueFetcher;
+
+ /**
+ * Constructs an AnnotationParser with the specified ValueFetcher.
+ *
+ * @param valueFetcher The ValueFetcher used to fetch values for property setters.
+ */
+ public AnnotationParser(ValueFetcher valueFetcher) {
+ this.valueFetcher = notNull(valueFetcher, "The value fetcher cannot be null.");
+ }
+
+ /**
+ * Parses the given interface class to extract HTTP information for each method.
+ *
+ * @param clazz The interface class to parse.
+ * @return A map of methods to their corresponding HTTP information.
+ */
+ public Map parseInterface(Class> clazz) {
+ Map httpInfoMap = new HashMap<>();
+ if (clazz.isInterface()) {
+ String pathPatternPrefix = this.getPathPatternPrefix(clazz);
+ Address address = this.getAddress(clazz);
+ Arrays.stream(clazz.getMethods()).forEach(method -> {
+ HttpInfo httpInfo = this.parseMethod(method, pathPatternPrefix);
+ httpInfo.setAddress(address);
+ httpInfoMap.put(method, httpInfo);
+ });
+ }
+ return httpInfoMap;
+ }
+
+ private HttpInfo parseMethod(Method method, String pathPatternPrefix) {
+ HttpInfo httpInfo = new HttpInfo();
+ this.parseHttpMethod(method, httpInfo, pathPatternPrefix);
+ List appliers = new ArrayList<>();
+ Arrays.stream(method.getParameters()).forEach(parameter -> appliers.add(this.parseParam(parameter)));
+ httpInfo.setAppliers(appliers);
+ return httpInfo;
+ }
+
+ private void parseHttpMethod(Method method, HttpInfo httpInfo, String pathPatternPrefix) {
+ Arrays.stream(method.getAnnotations())
+ .filter(annotation -> mappingMethodAnnotations.contains(annotation.annotationType()))
+ .forEach(annotation -> {
+ Method pathMethod =
+ ReflectionUtils.getDeclaredMethod(annotation.annotationType(), KEY_OF_METHOD_PATH);
+ String[] paths =
+ (String[]) ReflectionUtils.invoke(method.getAnnotation(annotation.annotationType()),
+ pathMethod);
+ if (ArrayUtils.isEmpty(paths)) {
+ return;
+ }
+ if (paths.length > MAX_PATH_SIZE) {
+ throw new IllegalArgumentException("The path size cannot be more than one.");
+ }
+ httpInfo.setPathPattern(pathPatternPrefix + paths[0]);
+ httpInfo.setMethod(annotation.annotationType()
+ .getDeclaredAnnotation(RequestMapping.class)
+ .method()[0]);
+ });
+ }
+
+ private String getPathPatternPrefix(Class> clazz) {
+ String pathPatternPrefix = StringUtils.EMPTY;
+ if (clazz.isAnnotationPresent(RequestMapping.class)) {
+ RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
+ String[] paths = requestMapping.path();
+ if (ArrayUtils.isNotEmpty(paths)) {
+ pathPatternPrefix = paths[0];
+ }
+ }
+ return pathPatternPrefix;
+ }
+
+ private Address getAddress(Class> requestAddressClazz) {
+ Address address = null;
+ if (requestAddressClazz.isAnnotationPresent(RequestAddress.class)) {
+ address = new Address();
+ RequestAddress requestAddress = requestAddressClazz.getAnnotation(RequestAddress.class);
+ address.setProtocol(requestAddress.protocol());
+ address.setHost(requestAddress.host());
+ if (StringUtils.isNotEmpty(requestAddress.port())) {
+ address.setPort(Integer.parseInt(requestAddress.port()));
+ }
+ address.setLocator(requestAddress.address());
+ }
+ return address;
+ }
+
+ private PropertyValueApplier parseParam(Parameter parameter) {
+ Annotation[] annotations = parameter.getAnnotations();
+ Class> type = parameter.getType();
+ List setterInfos = getSetterInfos(annotations, type.getDeclaredFields(), "$");
+ return new MultiDestinationsPropertyValueApplier(setterInfos, this.valueFetcher);
+ }
+
+ private List getSetterInfos(Annotation[] annotations, Field[] fields, String prefix) {
+ List setterInfos = new ArrayList<>();
+ for (Annotation annotation : annotations) {
+ if (annotation.annotationType() == RequestBean.class) {
+ Arrays.stream(fields)
+ .forEach(field -> setterInfos.addAll(this.getSetterInfos(field.getAnnotations(),
+ field.getType().getDeclaredFields(),
+ prefix + "." + field.getName())));
+ return setterInfos;
+ } else {
+ ParamResolver resolver = annotationParsers.get(annotation.annotationType());
+ if (resolver != null) {
+ setterInfos.add(resolver.resolve(annotation, prefix));
+ return setterInfos;
+ }
+ }
+ }
+ return setterInfos;
+ }
+}
\ No newline at end of file
diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/HttpInvocationHandler.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/HttpInvocationHandler.java
new file mode 100644
index 00000000..0a4526a4
--- /dev/null
+++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/HttpInvocationHandler.java
@@ -0,0 +1,116 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.http.client.proxy.scanner;
+
+import static modelengine.fitframework.inspection.Validation.notNull;
+import static modelengine.fitframework.util.ObjectUtils.cast;
+
+import modelengine.fit.http.client.HttpClassicClient;
+import modelengine.fit.http.client.HttpClassicClientFactory;
+import modelengine.fit.http.client.HttpClassicClientRequest;
+import modelengine.fit.http.client.HttpClassicClientResponse;
+import modelengine.fit.http.client.HttpClientErrorException;
+import modelengine.fit.http.client.HttpClientException;
+import modelengine.fit.http.client.HttpClientResponseException;
+import modelengine.fit.http.client.HttpServerErrorException;
+import modelengine.fit.http.client.proxy.PropertyValueApplier;
+import modelengine.fit.http.client.proxy.RequestBuilder;
+import modelengine.fit.http.client.proxy.scanner.entity.Address;
+import modelengine.fit.http.client.proxy.scanner.entity.HttpInfo;
+import modelengine.fit.http.entity.ObjectEntity;
+import modelengine.fit.http.entity.TextEntity;
+import modelengine.fitframework.ioc.BeanContainer;
+import modelengine.fitframework.util.StringUtils;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Handles HTTP invocations for proxy interfaces by mapping method calls to HTTP requests.
+ * This class implements the {@link InvocationHandler} interface and is responsible for
+ * constructing and executing HTTP requests based on the annotations and parameters of the
+ * invoked methods.
+ *
+ * @author 王攀博
+ * @since 2025-01-07
+ */
+public class HttpInvocationHandler implements InvocationHandler {
+ private final HttpClassicClientFactory factory;
+ private final Map httpInfoMap;
+ private final BeanContainer container;
+
+ /**
+ * Constructs an HttpInvocationHandler with the specified HTTP client factory, HTTP info map, and bean container.
+ *
+ * @param httpInfoMap The map of methods to their corresponding HTTP information.
+ * @param container The bean container used to retrieve beans for address resolution.
+ * @param factory The HTTP client factory used to create HTTP clients.
+ */
+ public HttpInvocationHandler(Map httpInfoMap, BeanContainer container,
+ HttpClassicClientFactory factory) {
+ this.httpInfoMap = notNull(httpInfoMap, "The http info cannot be null.");
+ this.container = notNull(container, "The bean container cannot be null.");
+ this.factory = notNull(factory, "The HTTP client factory cannot be null.");
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ HttpInfo httpInfo = this.httpInfoMap.get(method);
+ if (httpInfo == null) {
+ throw new HttpClientException("No method http info.");
+ }
+ List appliers = httpInfo.getAppliers();
+ if (args.length != appliers.size()) {
+ throw new HttpClientException("Args length not equals to appliers size.");
+ }
+ HttpClassicClient client = this.factory.create();
+ RequestBuilder requestBuilder = RequestBuilder.create()
+ .client(client)
+ .method(httpInfo.getMethod())
+ .pathPattern(httpInfo.getPathPattern());
+ Address address = this.updateAddress(httpInfo.getAddress());
+ if (address != null) {
+ requestBuilder.protocol(address.getProtocol()).host(address.getHost()).port(address.getPort());
+ }
+ for (int i = 0; i < appliers.size(); i++) {
+ appliers.get(i).apply(requestBuilder, args[i]);
+ }
+ HttpClassicClientRequest request = requestBuilder.build();
+ try (HttpClassicClientResponse> response = client.exchange(request, method.getReturnType())) {
+ if (response.statusCode() >= 200 && response.statusCode() < 300) {
+ if (method.getReturnType() == String.class) {
+ return cast(response.textEntity().map(TextEntity::content).orElse(StringUtils.EMPTY));
+ }
+ return cast(response.objectEntity().map(ObjectEntity::object).orElse(null));
+ } else if (response.statusCode() >= 400 && response.statusCode() < 500) {
+ throw new HttpClientErrorException(request, response);
+ } else if (response.statusCode() >= 500 && response.statusCode() < 600) {
+ throw new HttpServerErrorException(request, response);
+ } else {
+ throw new HttpClientResponseException(request, response);
+ }
+ }
+ }
+
+ private Address updateAddress(Address addressIn) {
+ if (addressIn == null || StringUtils.isNotEmpty(addressIn.getHost())) {
+ return addressIn;
+ }
+ if (addressIn.getLocator() != null) {
+ AddressLocator addressSource = this.container.beans().get(addressIn.getLocator());
+ if (addressSource != null) {
+ Address address = addressSource.address();
+ addressIn.setProtocol(address.getProtocol());
+ addressIn.setHost(address.getHost());
+ addressIn.setPort(address.getPort());
+ }
+ }
+ return addressIn;
+ }
+}
\ No newline at end of file
diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/ParamResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/ParamResolver.java
new file mode 100644
index 00000000..a0681647
--- /dev/null
+++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/ParamResolver.java
@@ -0,0 +1,30 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.http.client.proxy.scanner;
+
+import modelengine.fit.http.client.proxy.support.setter.DestinationSetterInfo;
+
+/**
+ * Defines a contract for resolving annotations into destination setter information.
+ * Implementations of this interface are responsible for parsing specific annotations
+ * and converting them into {@link DestinationSetterInfo} objects that can be used to
+ * set properties on HTTP request objects.
+ *
+ * @param The type of annotation that this resolver handles.
+ * @author 王攀博
+ * @since 2025-02-10
+ */
+public interface ParamResolver {
+ /**
+ * Resolves the given annotation into a destination setter information object.
+ *
+ * @param annotation The annotation to resolve.
+ * @param jsonPath The JSON path associated with the annotation.
+ * @return A {@link DestinationSetterInfo} object containing the resolved information.
+ */
+ DestinationSetterInfo resolve(T annotation, String jsonPath);
+}
\ No newline at end of file
diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/entity/Address.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/entity/Address.java
new file mode 100644
index 00000000..d924c4d8
--- /dev/null
+++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/entity/Address.java
@@ -0,0 +1,94 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.http.client.proxy.scanner.entity;
+
+import modelengine.fit.http.client.proxy.scanner.AddressLocator;
+
+/**
+ * Represents the address information for an HTTP request.
+ *
+ * @author 王攀博
+ * @since 2025-01-10
+ */
+public class Address {
+ private String protocol;
+ private String host;
+ private int port;
+ private Class extends AddressLocator> locator;
+
+ /**
+ * Gets the protocol for the HTTP request.
+ *
+ * @return The protocol for the HTTP request.
+ */
+ public String getProtocol() {
+ return this.protocol;
+ }
+
+ /**
+ * Sets the protocol for the HTTP request.
+ *
+ * @param protocol The protocol for the HTTP request.
+ */
+ public void setProtocol(String protocol) {
+ this.protocol = protocol;
+ }
+
+ /**
+ * Gets the host for the HTTP request.
+ *
+ * @return The host for the HTTP request.
+ */
+ public String getHost() {
+ return this.host;
+ }
+
+ /**
+ * Sets the host for the HTTP request.
+ *
+ * @param host The host for the HTTP request.
+ */
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ /**
+ * Gets the port for the HTTP request.
+ *
+ * @return The port for the HTTP request.
+ */
+ public int getPort() {
+ return this.port;
+ }
+
+ /**
+ * Sets the port for the HTTP request.
+ *
+ * @param port The port for the HTTP request.
+ */
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ /**
+ * Gets the class used to locate the address.
+ *
+ * @return The class used to locate the address.
+ */
+ public Class extends AddressLocator> getLocator() {
+ return this.locator;
+ }
+
+ /**
+ * Sets the class used to locate the address.
+ *
+ * @param locator The class used to locate the address.
+ */
+ public void setLocator(Class extends AddressLocator> locator) {
+ this.locator = locator;
+ }
+}
\ No newline at end of file
diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/entity/HttpInfo.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/entity/HttpInfo.java
new file mode 100644
index 00000000..dd673728
--- /dev/null
+++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/entity/HttpInfo.java
@@ -0,0 +1,98 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.http.client.proxy.scanner.entity;
+
+import modelengine.fit.http.client.proxy.PropertyValueApplier;
+import modelengine.fit.http.protocol.HttpRequestMethod;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents the HTTP request information, including address, method, path pattern, and property value appliers.
+ *
+ * @author 王攀博
+ * @since 2025-01-10
+ */
+public class HttpInfo {
+ private Address address;
+ private HttpRequestMethod method;
+ private String pathPattern;
+ private List appliers = new ArrayList<>();
+
+ /**
+ * Gets the address information for the HTTP request.
+ *
+ * @return The address information.
+ */
+ public Address getAddress() {
+ return this.address;
+ }
+
+ /**
+ * Sets the address information for the HTTP request.
+ *
+ * @param address The address information to set.
+ */
+ public void setAddress(Address address) {
+ this.address = address;
+ }
+
+ /**
+ * Gets the HTTP request method.
+ *
+ * @return The HTTP request method.
+ */
+ public HttpRequestMethod getMethod() {
+ return this.method;
+ }
+
+ /**
+ * Sets the HTTP request method.
+ *
+ * @param method The HTTP request method to set.
+ */
+ public void setMethod(HttpRequestMethod method) {
+ this.method = method;
+ }
+
+ /**
+ * Gets the path pattern for the HTTP request.
+ *
+ * @return The path pattern.
+ */
+ public String getPathPattern() {
+ return this.pathPattern;
+ }
+
+ /**
+ * Sets the path pattern for the HTTP request.
+ *
+ * @param pathPattern The path pattern to set.
+ */
+ public void setPathPattern(String pathPattern) {
+ this.pathPattern = pathPattern;
+ }
+
+ /**
+ * Gets the list of property value appliers for the HTTP request.
+ *
+ * @return The list of property value appliers.
+ */
+ public List getAppliers() {
+ return this.appliers;
+ }
+
+ /**
+ * Sets the list of property value appliers for the HTTP request.
+ *
+ * @param appliers The list of property value appliers to set.
+ */
+ public void setAppliers(List appliers) {
+ this.appliers = appliers;
+ }
+}
\ No newline at end of file
diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/PathVariableResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/PathVariableResolver.java
new file mode 100644
index 00000000..2f999752
--- /dev/null
+++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/PathVariableResolver.java
@@ -0,0 +1,28 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.http.client.proxy.scanner.resolver;
+
+import modelengine.fit.http.annotation.PathVariable;
+import modelengine.fit.http.client.proxy.scanner.ParamResolver;
+import modelengine.fit.http.client.proxy.support.setter.DestinationSetterInfo;
+import modelengine.fit.http.client.proxy.support.setter.PathVariableDestinationSetter;
+
+/**
+ * Resolves the {@link PathVariable} annotation into a destination setter information object.
+ * This class implements the {@link ParamResolver} interface and is responsible for parsing
+ * the {@link PathVariable} annotation and converting it into a {@link DestinationSetterInfo}
+ * object that can be used to set path variables on HTTP request objects.
+ *
+ * @author 王攀博
+ * @since 2025-02-10
+ */
+public class PathVariableResolver implements ParamResolver {
+ @Override
+ public DestinationSetterInfo resolve(PathVariable annotation, String jsonPath) {
+ return new DestinationSetterInfo(new PathVariableDestinationSetter(annotation.name()), jsonPath);
+ }
+}
\ No newline at end of file
diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/RequestBodyResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/RequestBodyResolver.java
new file mode 100644
index 00000000..73f3244d
--- /dev/null
+++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/RequestBodyResolver.java
@@ -0,0 +1,28 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.http.client.proxy.scanner.resolver;
+
+import modelengine.fit.http.annotation.RequestBody;
+import modelengine.fit.http.client.proxy.scanner.ParamResolver;
+import modelengine.fit.http.client.proxy.support.setter.DestinationSetterInfo;
+import modelengine.fit.http.client.proxy.support.setter.ObjectEntitySetter;
+
+/**
+ * Resolves the {@link RequestBody} annotation into a destination setter information object.
+ * This class implements the {@link ParamResolver} interface and is responsible for parsing
+ * the {@link RequestBody} annotation and converting it into a {@link DestinationSetterInfo}
+ * object that can be used to set the request body on HTTP request objects.
+ *
+ * @author 王攀博
+ * @since 2025-02-10
+ */
+public class RequestBodyResolver implements ParamResolver {
+ @Override
+ public DestinationSetterInfo resolve(RequestBody annotation, String jsonPath) {
+ return new DestinationSetterInfo(new ObjectEntitySetter(annotation.key()), jsonPath);
+ }
+}
\ No newline at end of file
diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/RequestCookieResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/RequestCookieResolver.java
new file mode 100644
index 00000000..599c7943
--- /dev/null
+++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/RequestCookieResolver.java
@@ -0,0 +1,28 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.http.client.proxy.scanner.resolver;
+
+import modelengine.fit.http.annotation.RequestCookie;
+import modelengine.fit.http.client.proxy.scanner.ParamResolver;
+import modelengine.fit.http.client.proxy.support.setter.CookieDestinationSetter;
+import modelengine.fit.http.client.proxy.support.setter.DestinationSetterInfo;
+
+/**
+ * Resolves the {@link RequestCookie} annotation into a destination setter information object.
+ * This class implements the {@link ParamResolver} interface and is responsible for parsing
+ * the {@link RequestCookie} annotation and converting it into a {@link DestinationSetterInfo}
+ * object that can be used to set cookies on HTTP request objects.
+ *
+ * @author 王攀博
+ * @since 2025-02-10
+ */
+public class RequestCookieResolver implements ParamResolver {
+ @Override
+ public DestinationSetterInfo resolve(RequestCookie annotation, String jsonPath) {
+ return new DestinationSetterInfo(new CookieDestinationSetter(annotation.name()), jsonPath);
+ }
+}
\ No newline at end of file
diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/RequestFormResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/RequestFormResolver.java
new file mode 100644
index 00000000..54804431
--- /dev/null
+++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/RequestFormResolver.java
@@ -0,0 +1,28 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.http.client.proxy.scanner.resolver;
+
+import modelengine.fit.http.annotation.RequestForm;
+import modelengine.fit.http.client.proxy.scanner.ParamResolver;
+import modelengine.fit.http.client.proxy.support.setter.DestinationSetterInfo;
+import modelengine.fit.http.client.proxy.support.setter.FormUrlEncodedEntitySetter;
+
+/**
+ * Resolves the {@link RequestForm} annotation into a destination setter information object.
+ * This class implements the {@link ParamResolver} interface and is responsible for parsing
+ * the {@link RequestForm} annotation and converting it into a {@link DestinationSetterInfo}
+ * object that can be used to set form data on HTTP request objects.
+ *
+ * @author 王攀博
+ * @since 2025-02-10
+ */
+public class RequestFormResolver implements ParamResolver {
+ @Override
+ public DestinationSetterInfo resolve(RequestForm annotation, String jsonPath) {
+ return new DestinationSetterInfo(new FormUrlEncodedEntitySetter(annotation.name()), jsonPath);
+ }
+}
\ No newline at end of file
diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/RequestHeaderResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/RequestHeaderResolver.java
new file mode 100644
index 00000000..c56d5d92
--- /dev/null
+++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/RequestHeaderResolver.java
@@ -0,0 +1,28 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.http.client.proxy.scanner.resolver;
+
+import modelengine.fit.http.annotation.RequestHeader;
+import modelengine.fit.http.client.proxy.scanner.ParamResolver;
+import modelengine.fit.http.client.proxy.support.setter.DestinationSetterInfo;
+import modelengine.fit.http.client.proxy.support.setter.HeaderDestinationSetter;
+
+/**
+ * Resolves the {@link RequestHeader} annotation into a destination setter information object.
+ * This class implements the {@link ParamResolver} interface and is responsible for parsing
+ * the {@link RequestHeader} annotation and converting it into a {@link DestinationSetterInfo}
+ * object that can be used to set headers on HTTP request objects.
+ *
+ * @author 王攀博
+ * @since 2025-02-10
+ */
+public class RequestHeaderResolver implements ParamResolver {
+ @Override
+ public DestinationSetterInfo resolve(RequestHeader annotation, String jsonPath) {
+ return new DestinationSetterInfo(new HeaderDestinationSetter(annotation.name()), jsonPath);
+ }
+}
\ No newline at end of file
diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/RequestQueryResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/RequestQueryResolver.java
new file mode 100644
index 00000000..45513ac4
--- /dev/null
+++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/scanner/resolver/RequestQueryResolver.java
@@ -0,0 +1,28 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+package modelengine.fit.http.client.proxy.scanner.resolver;
+
+import modelengine.fit.http.annotation.RequestQuery;
+import modelengine.fit.http.client.proxy.scanner.ParamResolver;
+import modelengine.fit.http.client.proxy.support.setter.DestinationSetterInfo;
+import modelengine.fit.http.client.proxy.support.setter.QueryDestinationSetter;
+
+/**
+ * Resolves the {@link RequestQuery} annotation into a destination setter information object.
+ * This class implements the {@link ParamResolver} interface and is responsible for parsing
+ * the {@link RequestQuery} annotation and converting it into a {@link DestinationSetterInfo}
+ * object that can be used to set query parameters on HTTP request objects.
+ *
+ * @author 王攀博
+ * @since 2025-02-10
+ */
+public class RequestQueryResolver implements ParamResolver {
+ @Override
+ public DestinationSetterInfo resolve(RequestQuery annotation, String jsonPath) {
+ return new DestinationSetterInfo(new QueryDestinationSetter(annotation.name()), jsonPath);
+ }
+}
\ No newline at end of file
diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/support/DefaultRequestBuilder.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/support/DefaultRequestBuilder.java
index 758277bb..c3d942ad 100644
--- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/support/DefaultRequestBuilder.java
+++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/client/proxy/support/DefaultRequestBuilder.java
@@ -42,6 +42,8 @@ public class DefaultRequestBuilder implements RequestBuilder {
private HttpRequestMethod method;
private String protocol;
private String domain;
+ private String host;
+ private int port;
private String pathPattern;
private Entity entity;
private Authorization authorization;
@@ -70,6 +72,18 @@ public RequestBuilder domain(String domain) {
return this;
}
+ @Override
+ public RequestBuilder host(String host) {
+ this.host = host;
+ return this;
+ }
+
+ @Override
+ public RequestBuilder port(int port) {
+ this.port = port;
+ return this;
+ }
+
@Override
public RequestBuilder pathPattern(String pathPattern) {
this.pathPattern = pathPattern;
@@ -163,16 +177,23 @@ public RequestBuilder authorizationInfo(String key, Object value) {
@Override
public HttpClassicClientRequest build() {
- StringBuilder url = new StringBuilder(this.protocol);
- url.append("://").append(this.domain);
+ if (this.authorization != null) {
+ this.authorization.assemble(this);
+ }
+ StringBuilder url = new StringBuilder();
+ if (StringUtils.isNotEmpty(this.protocol)) {
+ url.append(this.protocol).append("://");
+ }
+ if (StringUtils.isNotEmpty(this.domain)) {
+ url.append(this.domain);
+ } else if (StringUtils.isNotEmpty(this.host)) {
+ url.append(this.host).append(":").append(this.port);
+ }
if (!this.pathVariables.isEmpty()) {
this.pathVariables.forEach((key, value) -> this.pathPattern =
this.pathPattern.replace("{" + key + "}", value));
}
url.append(this.pathPattern);
- if (this.authorization != null) {
- this.authorization.assemble(this);
- }
if (!this.queries.isEmpty()) {
url.append("?");
this.queries.forEach((key, values) -> values.forEach(value -> url.append(key)
diff --git a/framework/fit/java/fit-plugin/src/main/java/modelengine/fitframework/globalization/ResourceBundleStringResource.java b/framework/fit/java/fit-plugin/src/main/java/modelengine/fitframework/globalization/ResourceBundleStringResource.java
index ab46da3c..bca8afc3 100644
--- a/framework/fit/java/fit-plugin/src/main/java/modelengine/fitframework/globalization/ResourceBundleStringResource.java
+++ b/framework/fit/java/fit-plugin/src/main/java/modelengine/fitframework/globalization/ResourceBundleStringResource.java
@@ -12,12 +12,12 @@
import modelengine.fitframework.util.StringUtils;
import java.util.Enumeration;
-import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.NoSuchElementException;
import java.util.ResourceBundle;
+import java.util.concurrent.ConcurrentHashMap;
/**
* 为 {@link StringResource} 提供基于 {@link ResourceBundle} 的实现。
@@ -35,7 +35,7 @@ final class ResourceBundleStringResource implements StringResource {
ResourceBundleStringResource(ClassLoader loader, String baseName, String encoding) {
this.loader = loader;
this.baseName = baseName;
- this.bundles = new HashMap<>();
+ this.bundles = new ConcurrentHashMap<>();
this.control = new MessageBundleControl(encoding);
}