|
@@ -0,0 +1,97 @@
|
|
|
|
|
+package space.anyi.httpClient;
|
|
|
|
|
+
|
|
|
|
|
+import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
|
|
+import com.fasterxml.jackson.core.type.TypeReference;
|
|
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
|
+import space.anyi.httpClient.model.Result;
|
|
|
|
|
+import space.anyi.httpClient.model.UserRequest;
|
|
|
|
|
+import space.anyi.httpClient.model.UserVO;
|
|
|
|
|
+
|
|
|
|
|
+import java.io.IOException;
|
|
|
|
|
+import java.net.URI;
|
|
|
|
|
+import java.net.http.HttpClient;
|
|
|
|
|
+import java.net.http.HttpRequest;
|
|
|
|
|
+import java.net.http.HttpRequest.BodyPublishers;
|
|
|
|
|
+import java.net.http.HttpResponse;
|
|
|
|
|
+import java.net.http.HttpResponse.BodyHandlers;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * POST 请求示例:向服务器提交 JSON 数据创建用户。
|
|
|
|
|
+ *
|
|
|
|
|
+ * <p>POST 与 GET 最大的区别在于<b>携带请求体</b>。使用 JDK HTTP Client
|
|
|
|
|
+ * 发送 POST JSON 的标准套路:</p>
|
|
|
|
|
+ * <ol>
|
|
|
|
|
+ * <li>用 Jackson 把对象序列化为 JSON 字符串</li>
|
|
|
|
|
+ * <li>设置 Content-Type: application/json 请求头</li>
|
|
|
|
|
+ * <li>用 BodyPublishers.ofString(json) 指定请求体</li>
|
|
|
|
|
+ * <li>调用 .POST(bodyPublisher) 声明请求方法</li>
|
|
|
|
|
+ * </ol>
|
|
|
|
|
+ */
|
|
|
|
|
+public class PostExample {
|
|
|
|
|
+
|
|
|
|
|
+ /** 服务基地址常量 */
|
|
|
|
|
+ private static final String BASE_URL = "http://localhost:8080";
|
|
|
|
|
+
|
|
|
|
|
+ /** Jackson 对象映射器,负责对象 <-> JSON 的互相转换(线程安全,可复用) */
|
|
|
|
|
+ private final ObjectMapper objectMapper = new ObjectMapper();
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 创建用户:POST /api/users,请求体为 JSON。
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param user 待创建的用户信息(name、account、sex 均必填)
|
|
|
|
|
+ * @return 原始响应对象
|
|
|
|
|
+ */
|
|
|
|
|
+ public HttpResponse<String> createUser(UserRequest user) throws IOException, InterruptedException {
|
|
|
|
|
+ // 1. 使用 Jackson 把对象序列化为 JSON 字符串
|
|
|
|
|
+ String json = objectMapper.writeValueAsString(user);
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 构造请求:设置 URI、Content-Type 请求头、JSON 请求体
|
|
|
|
|
+ HttpRequest request = HttpRequest.newBuilder()
|
|
|
|
|
+ .uri(URI.create(BASE_URL + "/api/users"))
|
|
|
|
|
+ // 告诉服务器请求体是 JSON 格式,服务器才能正确解析
|
|
|
|
|
+ .header("Content-Type", "application/json")
|
|
|
|
|
+ // POST 方法的第一个参数是 BodyPublisher,这里把 JSON 字符串包装为请求体
|
|
|
|
|
+ .POST(BodyPublishers.ofString(json))
|
|
|
|
|
+ .build();
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 发送请求
|
|
|
|
|
+ return HttpClient.newHttpClient().send(request, BodyHandlers.ofString());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 创建用户并解析响应中的用户数据。
|
|
|
|
|
+ *
|
|
|
|
|
+ * <p>演示如何用 Jackson 的 TypeReference 将统一包装结构反序列化为
|
|
|
|
|
+ * Result<UserVO>,从而拿到具体的用户对象。</p>
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param user 待创建的用户信息
|
|
|
|
|
+ * @return 创建成功后服务端返回的用户对象(含服务器生成的 id)
|
|
|
|
|
+ */
|
|
|
|
|
+ public UserVO createUserAndGetUser(UserRequest user) throws IOException, InterruptedException {
|
|
|
|
|
+ HttpResponse<String> response = createUser(user);
|
|
|
|
|
+
|
|
|
|
|
+ // 将包装结构 {code, message, data} 反序列化为 Result<UserVO>
|
|
|
|
|
+ Result<UserVO> result =
|
|
|
|
|
+ objectMapper.readValue(response.body(), new TypeReference<Result<UserVO>>() {
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 业务成功(code == 200)时返回 data,否则抛出异常
|
|
|
|
|
+ if (result.getCode() == 200) {
|
|
|
|
|
+ return result.getData();
|
|
|
|
|
+ }
|
|
|
|
|
+ throw new IllegalStateException("创建用户失败: " + result.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 演示:声明一个 POST 请求,但不发送。
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param json 已经序列化好的 JSON 字符串
|
|
|
|
|
+ */
|
|
|
|
|
+ public HttpRequest buildPostRequest(String json) throws JsonProcessingException {
|
|
|
|
|
+ return HttpRequest.newBuilder()
|
|
|
|
|
+ .uri(URI.create(BASE_URL + "/api/users"))
|
|
|
|
|
+ .header("Content-Type", "application/json")
|
|
|
|
|
+ .POST(BodyPublishers.ofString(json))
|
|
|
|
|
+ .build();
|
|
|
|
|
+ }
|
|
|
|
|
+}
|